diff options
| author | Tavmjong Bah <tavmjong@free.fr> | 2017-11-30 10:35:36 +0000 |
|---|---|---|
| committer | Tavmjong Bah <tavmjong@free.fr> | 2017-11-30 10:35:36 +0000 |
| commit | 542441374b6d6129b69470da18e5230dd421bc21 (patch) | |
| tree | 12caf1d88b563f5c10614e1624445f2f9aaba96c /src | |
| parent | Store device-scale and propogate value where necessary. (diff) | |
| download | inkscape-542441374b6d6129b69470da18e5230dd421bc21.tar.gz inkscape-542441374b6d6129b69470da18e5230dd421bc21.zip | |
Support device scale in filters.
Diffstat (limited to 'src')
| -rw-r--r-- | src/display/nr-filter-diffuselighting.cpp | 23 | ||||
| -rw-r--r-- | src/display/nr-filter-displacement-map.cpp | 11 | ||||
| -rw-r--r-- | src/display/nr-filter-gaussian.cpp | 14 | ||||
| -rw-r--r-- | src/display/nr-filter-image.cpp | 23 | ||||
| -rw-r--r-- | src/display/nr-filter-morphology.cpp | 5 | ||||
| -rw-r--r-- | src/display/nr-filter-slot.cpp | 8 | ||||
| -rw-r--r-- | src/display/nr-filter-slot.h | 7 | ||||
| -rw-r--r-- | src/display/nr-filter-specularlighting.cpp | 20 | ||||
| -rw-r--r-- | src/display/nr-filter-turbulence.cpp | 23 | ||||
| -rw-r--r-- | src/display/nr-filter.cpp | 5 | ||||
| -rw-r--r-- | src/display/nr-light.cpp | 22 | ||||
| -rw-r--r-- | src/display/nr-light.h | 6 |
12 files changed, 127 insertions, 40 deletions
diff --git a/src/display/nr-filter-diffuselighting.cpp b/src/display/nr-filter-diffuselighting.cpp index c6724e3ba..ed5afa82a 100644 --- a/src/display/nr-filter-diffuselighting.cpp +++ b/src/display/nr-filter-diffuselighting.cpp @@ -83,9 +83,10 @@ private: struct DiffusePointLight : public DiffuseLight { DiffusePointLight(cairo_surface_t *bumpmap, SPFePointLight *light, guint32 color, - Geom::Affine const &trans, double scale, double diffuse_constant, double x0, double y0) + Geom::Affine const &trans, double scale, double diffuse_constant, + double x0, double y0, int device_scale) : DiffuseLight(bumpmap, scale, diffuse_constant) - , _light(light, color, trans) + , _light(light, color, trans, device_scale) , _x0(x0) , _y0(y0) { @@ -105,9 +106,10 @@ private: struct DiffuseSpotLight : public DiffuseLight { DiffuseSpotLight(cairo_surface_t *bumpmap, SPFeSpotLight *light, guint32 color, - Geom::Affine const &trans, double scale, double diffuse_constant, double x0, double y0) + Geom::Affine const &trans, double scale, double diffuse_constant, + double x0, double y0, int device_scale) : DiffuseLight(bumpmap, scale, diffuse_constant) - , _light(light, color, trans) + , _light(light, color, trans, device_scale) , _x0(x0) , _y0(y0) {} @@ -160,11 +162,18 @@ void FilterDiffuseLighting::render_cairo(FilterSlot &slot) set_cairo_surface_ci(out, ci_fp ); guint32 color = SP_RGBA32_F_COMPOSE( r, g, b, 1.0 ); + int device_scale = slot.get_device_scale(); + Geom::Rect slot_area = slot.get_slot_area(); Geom::Point p = slot_area.min(); + + // trans has inverse y... so we can't just scale by device_scale! We must instead explicitly + // scale the point and spot light coordinates (as well as "scale"). + Geom::Affine trans = slot.get_units().get_matrix_primitiveunits2pb(); + double x0 = p[Geom::X], y0 = p[Geom::Y]; - double scale = surfaceScale * trans.descrim(); + double scale = surfaceScale * trans.descrim() * device_scale; switch (light_type) { case DISTANT_LIGHT: @@ -173,11 +182,11 @@ void FilterDiffuseLighting::render_cairo(FilterSlot &slot) break; case POINT_LIGHT: ink_cairo_surface_synthesize(out, - DiffusePointLight(input, light.point, color, trans, scale, diffuseConstant, x0, y0)); + DiffusePointLight(input, light.point, color, trans, scale, diffuseConstant, x0, y0, device_scale)); break; case SPOT_LIGHT: ink_cairo_surface_synthesize(out, - DiffuseSpotLight(input, light.spot, color, trans, scale, diffuseConstant, x0, y0)); + DiffuseSpotLight(input, light.spot, color, trans, scale, diffuseConstant, x0, y0, device_scale)); break; default: { cairo_t *ct = cairo_create(out); diff --git a/src/display/nr-filter-displacement-map.cpp b/src/display/nr-filter-displacement-map.cpp index c0d1ae411..fb2f3a0f0 100644 --- a/src/display/nr-filter-displacement-map.cpp +++ b/src/display/nr-filter-displacement-map.cpp @@ -71,12 +71,17 @@ private: void FilterDisplacementMap::render_cairo(FilterSlot &slot) { + std::cout << "FilterDisplacementMap:" << std::endl; cairo_surface_t *texture = slot.getcairo(_input); cairo_surface_t *map = slot.getcairo(_input2); cairo_surface_t *out = ink_cairo_surface_create_identical(texture); // color_interpolation_filters for out same as texture. See spec. copy_cairo_surface_ci( texture, out ); + std::cout << " texture: " << cairo_image_surface_get_width(texture) << std::endl; + std::cout << " map: " << cairo_image_surface_get_width(map) << std::endl; + std::cout << " out: " << cairo_image_surface_get_width(out) << std::endl; + // We may need to transform map surface to correct color interpolation space. The map surface // might be used as input to another primitive but it is likely that all the primitives in a given // filter use the same color interpolation space so we don't copy the map before converting. @@ -87,8 +92,10 @@ void FilterDisplacementMap::render_cairo(FilterSlot &slot) set_cairo_surface_ci( map, ci_fp ); Geom::Affine trans = slot.get_units().get_matrix_primitiveunits2pb(); - double scalex = scale * trans.expansionX(); - double scaley = scale * trans.expansionY(); + + int device_scale = slot.get_device_scale(); + double scalex = scale * trans.expansionX() * device_scale; + double scaley = scale * trans.expansionY() * device_scale; ink_cairo_surface_synthesize(out, Displace(texture, map, Xchannel, Ychannel, scalex, scaley)); diff --git a/src/display/nr-filter-gaussian.cpp b/src/display/nr-filter-gaussian.cpp index cdd01e75e..2227edfef 100644 --- a/src/display/nr-filter-gaussian.cpp +++ b/src/display/nr-filter-gaussian.cpp @@ -583,6 +583,12 @@ void FilterGaussian::render_cairo(FilterSlot &slot) double deviation_x_orig = dx * trans.expansionX(); double deviation_y_orig = dy * trans.expansionY(); + + int device_scale = slot.get_device_scale(); + + deviation_x_orig *= device_scale; + deviation_y_orig *= device_scale; + cairo_format_t fmt = cairo_image_surface_get_format(in); int bytes_per_pixel = 0; switch (fmt) { @@ -604,7 +610,7 @@ void FilterGaussian::render_cairo(FilterSlot &slot) int x_step = 1 << _effect_subsample_step_log2(deviation_x_orig, quality); int y_step = 1 << _effect_subsample_step_log2(deviation_y_orig, quality); bool resampling = x_step > 1 || y_step > 1; - int w_orig = ink_cairo_surface_get_width(in); + int w_orig = ink_cairo_surface_get_width(in); // Pixels int h_orig = ink_cairo_surface_get_height(in); int w_downsampled = resampling ? static_cast<int>(ceil(static_cast<double>(w_orig)/x_step))+1 : w_orig; int h_downsampled = resampling ? static_cast<int>(ceil(static_cast<double>(h_orig)/y_step))+1 : h_orig; @@ -633,8 +639,10 @@ void FilterGaussian::render_cairo(FilterSlot &slot) cairo_surface_t *downsampled = NULL; if (resampling) { + // Divide by device scale as w_downsampled is in pixels while + // cairo_surface_create_similar() uses device units. downsampled = cairo_surface_create_similar(in, cairo_surface_get_content(in), - w_downsampled, h_downsampled); + w_downsampled/device_scale, h_downsampled/device_scale); cairo_t *ct = cairo_create(downsampled); cairo_scale(ct, static_cast<double>(w_downsampled)/w_orig, static_cast<double>(h_downsampled)/h_orig); cairo_set_source_surface(ct, in, 0, 0); @@ -671,7 +679,7 @@ void FilterGaussian::render_cairo(FilterSlot &slot) cairo_surface_mark_dirty(downsampled); if (resampling) { cairo_surface_t *upsampled = cairo_surface_create_similar(downsampled, cairo_surface_get_content(downsampled), - w_orig, h_orig); + w_orig/device_scale, h_orig/device_scale); cairo_t *ct = cairo_create(upsampled); cairo_scale(ct, static_cast<double>(w_orig)/w_downsampled, static_cast<double>(h_orig)/h_downsampled); cairo_set_source_surface(ct, downsampled, 0, 0); diff --git a/src/display/nr-filter-image.cpp b/src/display/nr-filter-image.cpp index 7e859314a..86ebb49cb 100644 --- a/src/display/nr-filter-image.cpp +++ b/src/display/nr-filter-image.cpp @@ -47,6 +47,7 @@ FilterImage::~FilterImage() void FilterImage::render_cairo(FilterSlot &slot) { + std::cout << "FilterImage::render_cairo: Entrance" << std::endl; if (!feImageHref) return; @@ -78,8 +79,11 @@ void FilterImage::render_cairo(FilterSlot &slot) if( feImageWidth == 0 ) feImageWidth = bbox_width; if( feImageHeight == 0 ) feImageHeight = bbox_height; + int device_scale = slot.get_device_scale(); + // Internal image, like <use> if (from_element) { + std::cout << " Internal image" << std::endl; if (!SVGElem) return; // TODO: do not recreate the rendering tree every time @@ -108,8 +112,12 @@ void FilterImage::render_cairo(FilterSlot &slot) */ Geom::Rect sa = slot.get_slot_area(); - cairo_surface_t *out = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, - sa.width(), sa.height()); + cairo_surface_t *out = + cairo_image_surface_create(CAIRO_FORMAT_ARGB32, + sa.width() * device_scale, + sa.height() * device_scale); + cairo_surface_set_device_scale(out, device_scale, device_scale); + Inkscape::DrawingContext dc(out, sa.min()); dc.transform(user2pb); // we are now in primitive units dc.translate(feImageX, feImageY); @@ -128,11 +136,14 @@ void FilterImage::render_cairo(FilterSlot &slot) slot.set(_output, out); cairo_surface_destroy(out); + std::cout << " feImage: out: " << cairo_image_surface_get_width( out) << std::endl; + std::cout << "FilterImage::render_cairo: Exit 2" << std::endl; return; } // External image, like <image> if (!image && !broken_ref) { + std::cout << " External image" << std::endl; broken_ref = true; /* TODO: If feImageHref is absolute, then use that (preferably handling the @@ -170,10 +181,12 @@ void FilterImage::render_cairo(FilterSlot &slot) } cairo_surface_t *image_surface = image->getSurfaceRaw(); - + std::cout << " image: " << cairo_image_surface_get_width(image_surface) << std::endl; Geom::Rect sa = slot.get_slot_area(); cairo_surface_t *out = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, - sa.width(), sa.height()); + sa.width() * device_scale, sa.height() * device_scale); + cairo_surface_set_device_scale( out, device_scale, device_scale ); + std::cout << " out: " << cairo_image_surface_get_width(out) << std::endl; // For the moment, we'll assume that any image is in sRGB color space // set_cairo_surface_ci(out, SP_CSS_COLOR_INTERPOLATION_SRGB); @@ -278,8 +291,8 @@ void FilterImage::render_cairo(FilterSlot &slot) cairo_set_source_surface(ct, image_surface, 0, 0); cairo_paint(ct); cairo_destroy(ct); - slot.set(_output, out); + std::cout << "FilterImage::render_cairo: Exit 2" << std::endl; } bool FilterImage::can_handle_affine(Geom::Affine const &) diff --git a/src/display/nr-filter-morphology.cpp b/src/display/nr-filter-morphology.cpp index b6e5052e1..a06033e80 100644 --- a/src/display/nr-filter-morphology.cpp +++ b/src/display/nr-filter-morphology.cpp @@ -171,9 +171,10 @@ void FilterMorphology::render_cairo(FilterSlot &slot) return; } + int device_scale = slot.get_device_scale(); Geom::Affine p2pb = slot.get_units().get_matrix_primitiveunits2pb(); - double xr = fabs(xradius * p2pb.expansionX()); - double yr = fabs(yradius * p2pb.expansionY()); + double xr = fabs(xradius * p2pb.expansionX()) * device_scale; + double yr = fabs(yradius * p2pb.expansionY()) * device_scale; int bpp = cairo_image_surface_get_format(input) == CAIRO_FORMAT_A8 ? 1 : 4; cairo_surface_t *interm = ink_cairo_surface_create_identical(input); diff --git a/src/display/nr-filter-slot.cpp b/src/display/nr-filter-slot.cpp index a6e0c5c4e..9d76462c0 100644 --- a/src/display/nr-filter-slot.cpp +++ b/src/display/nr-filter-slot.cpp @@ -270,6 +270,14 @@ int FilterSlot::get_blurquality(void) { return blurquality; } +void FilterSlot::set_device_scale(int const s) { + device_scale = s; +} + +int FilterSlot::get_device_scale() { + return device_scale; +} + Geom::Rect FilterSlot::get_slot_area() const { Geom::Point p(_slot_x, _slot_y); Geom::Point dim(_slot_w, _slot_h); diff --git a/src/display/nr-filter-slot.h b/src/display/nr-filter-slot.h index 166b2e718..d73e9d91c 100644 --- a/src/display/nr-filter-slot.h +++ b/src/display/nr-filter-slot.h @@ -72,6 +72,12 @@ public: /** Gets the gaussian filtering quality. Affects used interpolation methods */ int get_blurquality(void); + /** Sets the device scale; for high DPI monitors. */ + void set_device_scale(int const s); + + /** Gets the device scale; for high DPI monitors. */ + int get_device_scale(); + FilterUnits const &get_units() const { return _units; } Geom::Rect get_slot_area() const; @@ -98,6 +104,7 @@ private: int _last_out; FilterQuality filterquality; int blurquality; + int device_scale; cairo_surface_t *_get_transformed_source_graphic(); cairo_surface_t *_get_transformed_background(); diff --git a/src/display/nr-filter-specularlighting.cpp b/src/display/nr-filter-specularlighting.cpp index 2ce02adee..e8d03d42e 100644 --- a/src/display/nr-filter-specularlighting.cpp +++ b/src/display/nr-filter-specularlighting.cpp @@ -93,9 +93,9 @@ private: struct SpecularPointLight : public SpecularLight { SpecularPointLight(cairo_surface_t *bumpmap, SPFePointLight *light, guint32 color, Geom::Affine const &trans, double scale, double specular_constant, - double specular_exponent, double x0, double y0) + double specular_exponent, double x0, double y0, int device_scale) : SpecularLight(bumpmap, scale, specular_constant, specular_exponent) - , _light(light, color, trans) + , _light(light, color, trans, device_scale) , _x0(x0) , _y0(y0) { @@ -117,9 +117,9 @@ private: struct SpecularSpotLight : public SpecularLight { SpecularSpotLight(cairo_surface_t *bumpmap, SPFeSpotLight *light, guint32 color, Geom::Affine const &trans, double scale, double specular_constant, - double specular_exponent, double x0, double y0) + double specular_exponent, double x0, double y0, int device_scale) : SpecularLight(bumpmap, scale, specular_constant, specular_exponent) - , _light(light, color, trans) + , _light(light, color, trans, device_scale) , _x0(x0) , _y0(y0) {} @@ -173,11 +173,17 @@ void FilterSpecularLighting::render_cairo(FilterSlot &slot) set_cairo_surface_ci(out, ci_fp ); guint32 color = SP_RGBA32_F_COMPOSE( r, g, b, 1.0 ); + int device_scale = slot.get_device_scale(); + + // trans has inverse y... so we can't just scale by device_scale! We must instead explicitly + // scale the point and spot light coordinates (as well as "scale"). + Geom::Affine trans = slot.get_units().get_matrix_primitiveunits2pb(); + Geom::Point p = slot.get_slot_area().min(); double x0 = p[Geom::X]; double y0 = p[Geom::Y]; - double scale = surfaceScale * trans.descrim(); + double scale = surfaceScale * trans.descrim() * device_scale; double ks = specularConstant; double se = specularExponent; @@ -188,11 +194,11 @@ void FilterSpecularLighting::render_cairo(FilterSlot &slot) break; case POINT_LIGHT: ink_cairo_surface_synthesize(out, - SpecularPointLight(input, light.point, color, trans, scale, ks, se, x0, y0)); + SpecularPointLight(input, light.point, color, trans, scale, ks, se, x0, y0, device_scale)); break; case SPOT_LIGHT: ink_cairo_surface_synthesize(out, - SpecularSpotLight(input, light.spot, color, trans, scale, ks, se, x0, y0)); + SpecularSpotLight(input, light.spot, color, trans, scale, ks, se, x0, y0, device_scale)); break; default: { cairo_t *ct = cairo_create(out); diff --git a/src/display/nr-filter-turbulence.cpp b/src/display/nr-filter-turbulence.cpp index 1397c0f34..349bcc242 100644 --- a/src/display/nr-filter-turbulence.cpp +++ b/src/display/nr-filter-turbulence.cpp @@ -378,6 +378,19 @@ void FilterTurbulence::render_cairo(FilterSlot &slot) cairo_surface_t *input = slot.getcairo(_input); cairo_surface_t *out = ink_cairo_surface_create_same_size(input, CAIRO_CONTENT_COLOR_ALPHA); + // It is probably possible to render at a device scale greater than one + // but for the moment rendering at a device scale of one is the easiest. + // cairo_image_surface_get_width() returns width in pixels but + // cairo_surface_create_similar() requires width in device units so divide by device scale. + // We are rendering at a device scale of 1... so divide by device scale again! + double x_scale = 0; + double y_scale = 0; + cairo_surface_get_device_scale(input, &x_scale, &y_scale); + int width = ceil(cairo_image_surface_get_width( input)/x_scale/x_scale); + int height = ceil(cairo_image_surface_get_height(input)/y_scale/y_scale); + cairo_surface_t *temp = cairo_surface_create_similar (input, CAIRO_CONTENT_COLOR_ALPHA, width, height); + cairo_surface_set_device_scale( temp, 1, 1 ); + // color_interpolation_filter is determined by CSS value (see spec. Turbulence). if( _style ) { set_cairo_surface_ci(out, (SPColorInterpolation)_style->color_interpolation_filters.computed ); @@ -395,8 +408,16 @@ void FilterTurbulence::render_cairo(FilterSlot &slot) Geom::Rect slot_area = slot.get_slot_area(); double x0 = slot_area.min()[Geom::X]; double y0 = slot_area.min()[Geom::Y]; + ink_cairo_surface_synthesize(temp, Turbulence(*gen, unit_trans, x0, y0)); + + // cairo_surface_write_to_png( temp, "turbulence0.png" ); + + cairo_t *ct = cairo_create(out); + cairo_set_source_surface(ct, temp, 0, 0); + cairo_paint(ct); + cairo_destroy(ct); - ink_cairo_surface_synthesize(out, Turbulence(*gen, unit_trans, x0, y0)); + cairo_surface_destroy(temp); cairo_surface_mark_dirty(out); diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp index d430553d4..a1bea4fce 100644 --- a/src/display/nr-filter.cpp +++ b/src/display/nr-filter.cpp @@ -42,6 +42,7 @@ #include "display/drawing.h" #include "display/drawing-item.h" #include "display/drawing-context.h" +#include "display/drawing-surface.h" #include <2geom/affine.h> #include <2geom/rect.h> #include "svg/svg-length.h" @@ -95,6 +96,9 @@ Filter::~Filter() int Filter::render(Inkscape::DrawingItem const *item, DrawingContext &graphic, DrawingContext *bgdc) { + // std::cout << "Filter::render() for: " << const_cast<Inkscape::DrawingItem *>(item)->name() << std::endl; + // std::cout << " graphic drawing_scale: " << graphic.surface()->device_scale() << std::endl; + if (_primitive.empty()) { // when no primitives are defined, clear source graphic graphic.setSource(0,0,0,0); @@ -150,6 +154,7 @@ int Filter::render(Inkscape::DrawingItem const *item, DrawingContext &graphic, D FilterSlot slot(const_cast<Inkscape::DrawingItem*>(item), bgdc, graphic, units); slot.set_quality(filterquality); slot.set_blurquality(blurquality); + slot.set_device_scale(graphic.surface()->device_scale()); for (unsigned i = 0 ; i < _primitive.size() ; i++) { _primitive[i]->render_cairo(slot); diff --git a/src/display/nr-light.cpp b/src/display/nr-light.cpp index 0e9a55a9f..791ae53da 100644 --- a/src/display/nr-light.cpp +++ b/src/display/nr-light.cpp @@ -41,11 +41,11 @@ void DistantLight::light_components(NR::Fvector &lc) { lc[LIGHT_BLUE] = SP_RGBA32_B_U(color); } -PointLight::PointLight(SPFePointLight *light, guint32 lighting_color, const Geom::Affine &trans) { +PointLight::PointLight(SPFePointLight *light, guint32 lighting_color, const Geom::Affine &trans, int device_scale) { color = lighting_color; - l_x = light->x; - l_y = light->y; - l_z = light->z; + l_x = light->x * device_scale; + l_y = light->y * device_scale; + l_z = light->z * device_scale; NR::convert_coord(l_x, l_y, l_z, trans); } @@ -64,15 +64,15 @@ void PointLight::light_components(NR::Fvector &lc) { lc[LIGHT_BLUE] = SP_RGBA32_B_U(color); } -SpotLight::SpotLight(SPFeSpotLight *light, guint32 lighting_color, const Geom::Affine &trans) { +SpotLight::SpotLight(SPFeSpotLight *light, guint32 lighting_color, const Geom::Affine &trans, int device_scale) { double p_x, p_y, p_z; color = lighting_color; - l_x = light->x; - l_y = light->y; - l_z = light->z; - p_x = light->pointsAtX; - p_y = light->pointsAtY; - p_z = light->pointsAtZ; + l_x = light->x * device_scale; + l_y = light->y * device_scale; + l_z = light->z * device_scale; + p_x = light->pointsAtX * device_scale; + p_y = light->pointsAtY * device_scale; + p_z = light->pointsAtZ * device_scale; cos_lca = std::cos(M_PI / 180 * light->limitingConeAngle); speExp = light->specularExponent; NR::convert_coord(l_x, l_y, l_z, trans); diff --git a/src/display/nr-light.h b/src/display/nr-light.h index 57c421f4a..2eacdc92b 100644 --- a/src/display/nr-light.h +++ b/src/display/nr-light.h @@ -69,8 +69,9 @@ class PointLight { * \param trans the transformation between absolute coordinate (those * employed in the sp light object) and current coordinate (those * employed in the rendering) + * \param device_scale for high DPI monitors. */ - PointLight(SPFePointLight *light, guint32 lighting_color, const Geom::Affine &trans); + PointLight(SPFePointLight *light, guint32 lighting_color, const Geom::Affine &trans, int device_scale = 1); virtual ~PointLight(); /** * Computes the light vector of the distant light at point (x,y,z). @@ -109,8 +110,9 @@ class SpotLight { * \param trans the transformation between absolute coordinate (those * employed in the sp light object) and current coordinate (those * employed in the rendering) + * \param device_scale for high DPI monitors. */ - SpotLight(SPFeSpotLight *light, guint32 lighting_color, const Geom::Affine &trans); + SpotLight(SPFeSpotLight *light, guint32 lighting_color, const Geom::Affine &trans, int device_scale = 1); virtual ~SpotLight(); /** |
