diff options
Diffstat (limited to 'src')
22 files changed, 372 insertions, 33 deletions
diff --git a/src/display/nr-filter-blend.cpp b/src/display/nr-filter-blend.cpp index 267883b4b..2ada36949 100644 --- a/src/display/nr-filter-blend.cpp +++ b/src/display/nr-filter-blend.cpp @@ -146,13 +146,53 @@ void FilterBlend::render_cairo(FilterSlot &slot) cairo_surface_t *input1 = slot.getcairo(_input); cairo_surface_t *input2 = slot.getcairo(_input2); - cairo_content_t ct1 = cairo_surface_get_content(input1); - cairo_content_t ct2 = cairo_surface_get_content(input2); + // We may need to transform input surface to correct color interpolation space. The input 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 input before converting. + // The converting function tags surface with the proper ci value. + // Note: an alpha only surface should not have ci set. + SPColorInterpolation ci_in1 = get_cairo_surface_ci(input1); + SPColorInterpolation ci_in2 = get_cairo_surface_ci(input2); + SPColorInterpolation ci_fp = SP_CSS_COLOR_INTERPOLATION_AUTO; + if( _style ) { + ci_fp = (SPColorInterpolation)_style->color_interpolation_filters.computed; + } + if( ci_in1 == SP_CSS_COLOR_INTERPOLATION_SRGB && + ci_fp == SP_CSS_COLOR_INTERPOLATION_LINEARRGB ) { + //std::cout << "FilterColorBlend: srgb -> linear" << std::endl; + ink_cairo_surface_srgb_to_linear( input1 ); + } + if( ci_in1 == SP_CSS_COLOR_INTERPOLATION_LINEARRGB && + ci_fp == SP_CSS_COLOR_INTERPOLATION_SRGB ) { + //std::cout << "FilterColorBlend: linear -> srgb" << std::endl; + ink_cairo_surface_linear_to_srgb( input1 ); + } + if( ci_in2 == SP_CSS_COLOR_INTERPOLATION_SRGB && + ci_fp == SP_CSS_COLOR_INTERPOLATION_LINEARRGB ) { + //std::cout << "FilterColorBlend: srgb -> linear" << std::endl; + ink_cairo_surface_srgb_to_linear( input2 ); + } + if( ci_in2 == SP_CSS_COLOR_INTERPOLATION_LINEARRGB && + ci_fp == SP_CSS_COLOR_INTERPOLATION_SRGB ) { + //std::cout << "FilterColorBlend: linear -> srgb" << std::endl; + ink_cairo_surface_linear_to_srgb( input2 ); + } // input2 is the "background" image // out should be ARGB32 if any of the inputs is ARGB32 cairo_surface_t *out = ink_cairo_surface_create_output(input1, input2); + if( cairo_surface_get_content( out ) == CAIRO_CONTENT_COLOR_ALPHA ) { + set_cairo_surface_ci(out, ci_fp ); + } + + // std::cout << "FilterBlend: ci data: " + // << " in1: " << get_cairo_surface_ci(input1) + // << " in2: " << get_cairo_surface_ci(input2) + // << " out: " << get_cairo_surface_ci(out) + // << std::endl; + cairo_content_t ct1 = cairo_surface_get_content(input1); + cairo_content_t ct2 = cairo_surface_get_content(input2); if ((ct1 == CAIRO_CONTENT_ALPHA && ct2 == CAIRO_CONTENT_ALPHA) || _blend_mode == BLEND_NORMAL) { diff --git a/src/display/nr-filter-colormatrix.cpp b/src/display/nr-filter-colormatrix.cpp index fad6215ff..5d3cf6a9e 100644 --- a/src/display/nr-filter-colormatrix.cpp +++ b/src/display/nr-filter-colormatrix.cpp @@ -152,12 +152,41 @@ void FilterColorMatrix::render_cairo(FilterSlot &slot) { cairo_surface_t *input = slot.getcairo(_input); cairo_surface_t *out = NULL; + + // We may need to transform input surface to correct color interpolation space. The input 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 input before converting. + // The converting function tags surface with the proper ci value. + // Note: an alpha only surface should not have ci set. + SPColorInterpolation ci_in = get_cairo_surface_ci(input); + SPColorInterpolation ci_fp = SP_CSS_COLOR_INTERPOLATION_AUTO; + if( _style ) { + ci_fp = (SPColorInterpolation)_style->color_interpolation_filters.computed; + } + if( ci_in == SP_CSS_COLOR_INTERPOLATION_SRGB && + ci_fp == SP_CSS_COLOR_INTERPOLATION_LINEARRGB ) { + //std::cout << "FilterColorMatrix: srgb -> linear" << std::endl; + ink_cairo_surface_srgb_to_linear( input ); + } + if( ci_in == SP_CSS_COLOR_INTERPOLATION_LINEARRGB && + ci_fp == SP_CSS_COLOR_INTERPOLATION_SRGB ) { + //std::cout << "FilterColorMatrix: linear -> srgb" << std::endl; + ink_cairo_surface_linear_to_srgb( input ); + } + if (type == COLORMATRIX_LUMINANCETOALPHA) { out = ink_cairo_surface_create_same_size(input, CAIRO_CONTENT_ALPHA); } else { out = ink_cairo_surface_create_identical(input); + // Set ci to that used for computation + set_cairo_surface_ci(out, ci_fp); } + // std::cout << "FilterColorMatrix: ci data: " + // << " in1: " << get_cairo_surface_ci(input) + // << " out: " << get_cairo_surface_ci(out) + // << std::endl; + switch (type) { case COLORMATRIX_MATRIX: ink_cairo_surface_filter(input, out, FilterColorMatrix::ColorMatrixMatrix(values)); diff --git a/src/display/nr-filter-component-transfer.cpp b/src/display/nr-filter-component-transfer.cpp index 226a73cef..8efcc9c4d 100644 --- a/src/display/nr-filter-component-transfer.cpp +++ b/src/display/nr-filter-component-transfer.cpp @@ -238,6 +238,33 @@ void FilterComponentTransfer::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); + + // We may need to transform input surface to correct color interpolation space. The input 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 input before converting. + // The converting function tags surface with the proper ci value. + SPColorInterpolation ci_in = get_cairo_surface_ci(input); + SPColorInterpolation ci_fp = SP_CSS_COLOR_INTERPOLATION_AUTO; + if( _style ) { + ci_fp = (SPColorInterpolation)_style->color_interpolation_filters.computed; + set_cairo_surface_ci(out, ci_fp ); + } + if( ci_in == SP_CSS_COLOR_INTERPOLATION_SRGB && + ci_fp == SP_CSS_COLOR_INTERPOLATION_LINEARRGB ) { + //std::cout << "FilterComponentTransfer: srgb -> linear" << std::endl; + ink_cairo_surface_srgb_to_linear( input ); + } + if( ci_in == SP_CSS_COLOR_INTERPOLATION_LINEARRGB && + ci_fp == SP_CSS_COLOR_INTERPOLATION_SRGB ) { + //std::cout << "FilterComponentTransfer: linear -> srgb" << std::endl; + ink_cairo_surface_linear_to_srgb( input ); + } + + // std::cout << "FilterComponentTransfer: ci data: " + // << " in1: " << get_cairo_surface_ci(input) + // << " out: " << get_cairo_surface_ci(out) + // << std::endl; + //cairo_surface_t *outtemp = ink_cairo_surface_create_identical(out); ink_cairo_surface_blit(input, out); diff --git a/src/display/nr-filter-composite.cpp b/src/display/nr-filter-composite.cpp index 040424cb3..f5ec94a46 100644 --- a/src/display/nr-filter-composite.cpp +++ b/src/display/nr-filter-composite.cpp @@ -66,7 +66,48 @@ void FilterComposite::render_cairo(FilterSlot &slot) cairo_surface_t *input1 = slot.getcairo(_input); cairo_surface_t *input2 = slot.getcairo(_input2); + // We may need to transform input surface to correct color interpolation space. The input 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 input before converting. + // The converting function tags surface with the proper ci value. + // Note: an alpha only surface should not have ci set. + SPColorInterpolation ci_in1 = get_cairo_surface_ci(input1); + SPColorInterpolation ci_in2 = get_cairo_surface_ci(input2); + SPColorInterpolation ci_fp = SP_CSS_COLOR_INTERPOLATION_AUTO; + if( _style ) { + ci_fp = (SPColorInterpolation)_style->color_interpolation_filters.computed; + } + if( ci_in1 == SP_CSS_COLOR_INTERPOLATION_SRGB && + ci_fp == SP_CSS_COLOR_INTERPOLATION_LINEARRGB ) { + //std::cout << "FilterColorComposite: srgb -> linear" << std::endl; + ink_cairo_surface_srgb_to_linear( input1 ); + } + if( ci_in1 == SP_CSS_COLOR_INTERPOLATION_LINEARRGB && + ci_fp == SP_CSS_COLOR_INTERPOLATION_SRGB ) { + //std::cout << "FilterColorComposite: linear -> srgb" << std::endl; + ink_cairo_surface_linear_to_srgb( input1 ); + } + if( ci_in2 == SP_CSS_COLOR_INTERPOLATION_SRGB && + ci_fp == SP_CSS_COLOR_INTERPOLATION_LINEARRGB ) { + std::cout << "FilterColorComposite: srgb -> linear" << std::endl; + //ink_cairo_surface_srgb_to_linear( input2 ); + } + if( ci_in2 == SP_CSS_COLOR_INTERPOLATION_LINEARRGB && + ci_fp == SP_CSS_COLOR_INTERPOLATION_SRGB ) { + //std::cout << "FilterColorComposite: linear -> srgb" << std::endl; + ink_cairo_surface_linear_to_srgb( input2 ); + } + cairo_surface_t *out = ink_cairo_surface_create_output(input1, input2); + if( cairo_surface_get_content( out ) == CAIRO_CONTENT_COLOR_ALPHA ) { + set_cairo_surface_ci(out, ci_fp ); + } + + // std::cout << "FilterComposite: ci data: " + // << " in1: " << get_cairo_surface_ci(input1) + // << " in2: " << get_cairo_surface_ci(input2) + // << " out: " << get_cairo_surface_ci(out) + // << std::endl; if (op == COMPOSITE_ARITHMETIC) { ink_cairo_surface_blend(input1, input2, out, ComposeArithmetic(k1, k2, k3, k4)); diff --git a/src/display/nr-filter-convolve-matrix.cpp b/src/display/nr-filter-convolve-matrix.cpp index 5469aff88..6ee67d126 100644 --- a/src/display/nr-filter-convolve-matrix.cpp +++ b/src/display/nr-filter-convolve-matrix.cpp @@ -104,8 +104,6 @@ void FilterConvolveMatrix::render_cairo(FilterSlot &slot) static bool bias_warning = false; static bool edge_warning = false; - cairo_surface_t *input = slot.getcairo(_input); - if (orderX<=0 || orderY<=0) { g_warning("Empty kernel!"); return; @@ -119,8 +117,35 @@ void FilterConvolveMatrix::render_cairo(FilterSlot &slot) return; } + cairo_surface_t *input = slot.getcairo(_input); cairo_surface_t *out = ink_cairo_surface_create_identical(input); + // We may need to transform input surface to correct color interpolation space. The input 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 input before converting. + // The converting function tags surface with the proper ci value. + SPColorInterpolation ci_in = get_cairo_surface_ci(input); + SPColorInterpolation ci_fp = SP_CSS_COLOR_INTERPOLATION_AUTO; + if( _style ) { + ci_fp = (SPColorInterpolation)_style->color_interpolation_filters.computed; + set_cairo_surface_ci(out, ci_fp); + } + if( ci_in == SP_CSS_COLOR_INTERPOLATION_SRGB && + ci_fp == SP_CSS_COLOR_INTERPOLATION_LINEARRGB ) { + //std::cout << "FilterConvolveMatrix: srgb -> linear" << std::endl; + ink_cairo_surface_srgb_to_linear( input ); + } + if( ci_in == SP_CSS_COLOR_INTERPOLATION_LINEARRGB && + ci_fp == SP_CSS_COLOR_INTERPOLATION_SRGB ) { + //std::cout << "FilterConvolveMatrix: linear -> srgb" << std::endl; + ink_cairo_surface_linear_to_srgb( input ); + } + + // std::cout << "FilterConvolveMatrix: ci data: " + // << " in1: " << get_cairo_surface_ci(input) + // << " out: " << get_cairo_surface_ci(out) + // << std::endl; + if (bias!=0 && !bias_warning) { g_warning("It is unknown whether Inkscape's implementation of bias in feConvolveMatrix " "is correct!"); diff --git a/src/display/nr-filter-diffuselighting.cpp b/src/display/nr-filter-diffuselighting.cpp index fcc986189..bd473eb76 100644 --- a/src/display/nr-filter-diffuselighting.cpp +++ b/src/display/nr-filter-diffuselighting.cpp @@ -126,6 +126,18 @@ void FilterDiffuseLighting::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); + // Only alpha channel of input is used, no need to check input color_interpolation_filter value. + SPColorInterpolation ci_fp = SP_CSS_COLOR_INTERPOLATION_AUTO; + if( _style ) { + set_cairo_surface_ci(out, (SPColorInterpolation)_style->color_interpolation_filters.computed ); + set_cairo_surface_ci(out, ci_fp ); + } + + // std::cout << "FilterDiffuseLighting: ci data: " + // << " in1: " << get_cairo_surface_ci(input) + // << " out: " << get_cairo_surface_ci(out) + // << std::endl; + Geom::Rect slot_area = slot.get_slot_area(); Geom::Point p = slot_area.min(); Geom::Affine trans = slot.get_units().get_matrix_primitiveunits2pb(); diff --git a/src/display/nr-filter-displacement-map.cpp b/src/display/nr-filter-displacement-map.cpp index 9b44c2302..909e11f50 100644 --- a/src/display/nr-filter-displacement-map.cpp +++ b/src/display/nr-filter-displacement-map.cpp @@ -74,6 +74,34 @@ void FilterDisplacementMap::render_cairo(FilterSlot &slot) 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 ); + + // 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. + // The converting function tags surface with the proper ci value. + SPColorInterpolation ci_map = get_cairo_surface_ci(map); + SPColorInterpolation ci_fp = SP_CSS_COLOR_INTERPOLATION_AUTO; + if( _style ) { + ci_fp = (SPColorInterpolation)_style->color_interpolation_filters.computed; + } + if( ci_map == SP_CSS_COLOR_INTERPOLATION_SRGB && + ci_fp == SP_CSS_COLOR_INTERPOLATION_LINEARRGB ) { + //std::cout << "FilterDisplacementMap: srgb -> linear" << std::endl; + ink_cairo_surface_srgb_to_linear( map ); + } + if( ci_map == SP_CSS_COLOR_INTERPOLATION_LINEARRGB && + ci_fp == SP_CSS_COLOR_INTERPOLATION_SRGB ) { + //std::cout << "FilterDisplacementMap: linear -> srgb" << std::endl; + ink_cairo_surface_linear_to_srgb( map ); + } + + // std::cout << "FilterDisplacementMap: ci data: " + // << " texture: " << get_cairo_surface_ci(texture) + // << " map: " << get_cairo_surface_ci(map) + // << " out: " << get_cairo_surface_ci(out) + // << std::endl; Geom::Affine trans = slot.get_units().get_matrix_primitiveunits2pb(); double scalex = scale * trans.expansionX(); diff --git a/src/display/nr-filter-flood.cpp b/src/display/nr-filter-flood.cpp index 56a27ecd7..649d4609f 100644 --- a/src/display/nr-filter-flood.cpp +++ b/src/display/nr-filter-flood.cpp @@ -45,6 +45,8 @@ void FilterFlood::render_cairo(FilterSlot &slot) #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + // DOES THIS REALLY BELONG HERE? SHOULDN'T ICC BE APPLIED AFTER ALL COMPOSITING? + // What if color_interpolation_filter is set to linear RGB? if (icc) { guchar ru, gu, bu; icc_color_to_sRGB(icc, &ru, &gu, &bu); @@ -55,6 +57,13 @@ void FilterFlood::render_cairo(FilterSlot &slot) #endif cairo_surface_t *out = ink_cairo_surface_create_same_size(input, CAIRO_CONTENT_COLOR_ALPHA); + // color_interpolation_filter is determined by CSS value (see spec. Turbulence). + if( _style ) { + set_cairo_surface_ci(out, (SPColorInterpolation)_style->color_interpolation_filters.computed ); + } + + // std::cout << "FilterFlood: ci data: out: " + // << get_cairo_surface_ci(out) << std::endl; // Get filter primitive area in user units Geom::Rect fp = filter_primitive_area( slot.get_units() ); diff --git a/src/display/nr-filter-gaussian.cpp b/src/display/nr-filter-gaussian.cpp index 6ef321992..3b29e825d 100644 --- a/src/display/nr-filter-gaussian.cpp +++ b/src/display/nr-filter-gaussian.cpp @@ -553,6 +553,30 @@ void FilterGaussian::render_cairo(FilterSlot &slot) cairo_surface_t *in = slot.getcairo(_input); if (!in) return; + // We may need to transform input surface to correct color interpolation space. The input 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 input before converting. + // The converting function tags surface with the proper ci value. + // Note: an alpha only surface should not have ci set. + SPColorInterpolation ci_in = get_cairo_surface_ci(in); + SPColorInterpolation ci_fp = SP_CSS_COLOR_INTERPOLATION_AUTO; + if( _style ) { + ci_fp = (SPColorInterpolation)_style->color_interpolation_filters.computed; + } + if( ci_in == SP_CSS_COLOR_INTERPOLATION_SRGB && + ci_fp == SP_CSS_COLOR_INTERPOLATION_LINEARRGB ) { + //std::cout << "FilterGaussian: srgb -> linear" << std::endl; + ink_cairo_surface_srgb_to_linear( in ); + } + if( ci_in == SP_CSS_COLOR_INTERPOLATION_LINEARRGB && + ci_fp == SP_CSS_COLOR_INTERPOLATION_SRGB ) { + //std::cout << "FilterGaussian: linear -> srgb" << std::endl; + ink_cairo_surface_linear_to_srgb( in ); + } + + // std::cout << "FilterGaussian: ci data: in: " + // << get_cairo_surface_ci( in ) << std::endl; + // zero deviation = no change in output if (_deviation_x <= 0 && _deviation_y <= 0) { cairo_surface_t *cp = ink_cairo_surface_copy(in); @@ -660,10 +684,20 @@ void FilterGaussian::render_cairo(FilterSlot &slot) cairo_paint(ct); cairo_destroy(ct); + if( cairo_surface_get_content( upsampled ) == CAIRO_CONTENT_COLOR_ALPHA ) { + set_cairo_surface_ci( upsampled, ci_fp ); + } + // std::cout << "FilterGaussian: ci data: resampled: " + // << get_cairo_surface_ci(upsampled) << std::endl; slot.set(_output, upsampled); cairo_surface_destroy(upsampled); cairo_surface_destroy(downsampled); } else { + if( cairo_surface_get_content( downsampled ) == CAIRO_CONTENT_COLOR_ALPHA ) { + set_cairo_surface_ci( downsampled, ci_fp ); + } + // std::cout << "FilterGaussian: ci data: downsampled: " + // << get_cairo_surface_ci(downsampled) << std::endl; slot.set(_output, downsampled); cairo_surface_destroy(downsampled); } diff --git a/src/display/nr-filter-image.cpp b/src/display/nr-filter-image.cpp index bc18cbcc6..8aae29cbe 100644 --- a/src/display/nr-filter-image.cpp +++ b/src/display/nr-filter-image.cpp @@ -120,6 +120,11 @@ void FilterImage::render_cairo(FilterSlot &slot) drawing.render(ct, render_rect); SVGElem->invoke_hide(key); + // For the moment, we'll assume that any image is in sRGB color space + set_cairo_surface_ci(out, SP_CSS_COLOR_INTERPOLATION_SRGB); + // std::cout << "FilterImage: ci set to: " + // << get_cairo_surface_ci(out) << std::endl; + slot.set(_output, out); cairo_surface_destroy(out); return; @@ -185,6 +190,11 @@ void FilterImage::render_cairo(FilterSlot &slot) cairo_surface_t *out = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, sa.width(), sa.height()); + // For the moment, we'll assume that any image is in sRGB color space + set_cairo_surface_ci(out, SP_CSS_COLOR_INTERPOLATION_SRGB); + // std::cout << "FilterImage: ci set to: " + // << get_cairo_surface_ci(out) << std::endl; + cairo_t *ct = cairo_create(out); cairo_translate(ct, -sa.min()[Geom::X], -sa.min()[Geom::Y]); diff --git a/src/display/nr-filter-merge.cpp b/src/display/nr-filter-merge.cpp index 759d7d6d1..4d3862a33 100644 --- a/src/display/nr-filter-merge.cpp +++ b/src/display/nr-filter-merge.cpp @@ -33,6 +33,11 @@ void FilterMerge::render_cairo(FilterSlot &slot) { if (_input_image.empty()) return; + SPColorInterpolation ci_fp = SP_CSS_COLOR_INTERPOLATION_AUTO; + if( _style ) { + ci_fp = (SPColorInterpolation)_style->color_interpolation_filters.computed; + } + // output is RGBA if at least one input is RGBA bool rgba32 = false; cairo_surface_t *out = NULL; @@ -40,6 +45,7 @@ void FilterMerge::render_cairo(FilterSlot &slot) cairo_surface_t *in = slot.getcairo(*i); if (cairo_surface_get_content(in) == CAIRO_CONTENT_COLOR_ALPHA) { out = ink_cairo_surface_create_identical(in); + set_cairo_surface_ci( out, ci_fp ); rgba32 = true; break; } @@ -52,6 +58,19 @@ void FilterMerge::render_cairo(FilterSlot &slot) for (std::vector<int>::iterator i = _input_image.begin(); i != _input_image.end(); ++i) { cairo_surface_t *in = slot.getcairo(*i); + + SPColorInterpolation ci_in = get_cairo_surface_ci(in); + //std::cout << "FilterMerge: slot: ci: " << ci_in << std::endl; + if( ci_in == SP_CSS_COLOR_INTERPOLATION_SRGB && + ci_fp == SP_CSS_COLOR_INTERPOLATION_LINEARRGB ) { + //std::cout << "FilterMerge: srgb -> linear" << std::endl; + ink_cairo_surface_srgb_to_linear( in ); + } + if( ci_in == SP_CSS_COLOR_INTERPOLATION_LINEARRGB && + ci_fp == SP_CSS_COLOR_INTERPOLATION_SRGB ) { + //std::cout << "FilterMerge: linear -> srgb" << std::endl; + ink_cairo_surface_linear_to_srgb( in ); + } cairo_set_source_surface(out_ct, in, 0, 0); cairo_paint(out_ct); } diff --git a/src/display/nr-filter-morphology.cpp b/src/display/nr-filter-morphology.cpp index 18f99cdcd..7447b76fe 100644 --- a/src/display/nr-filter-morphology.cpp +++ b/src/display/nr-filter-morphology.cpp @@ -164,6 +164,7 @@ void FilterMorphology::render_cairo(FilterSlot &slot) if (xradius == 0.0 || yradius == 0.0) { // output is transparent black cairo_surface_t *out = ink_cairo_surface_create_identical(input); + copy_cairo_surface_ci(input, out); slot.set(_output, out); cairo_surface_destroy(out); return; @@ -192,6 +193,11 @@ void FilterMorphology::render_cairo(FilterSlot &slot) cairo_surface_t *out = ink_cairo_surface_create_identical(interm); + // color_interpolation_filters for out same as input. See spec (DisplacementMap). + copy_cairo_surface_ci(input, out); + // std::cout << "FilterMorphology: ci set to: " + // << get_cairo_surface_ci(out) << std::endl; + if (Operator == MORPHOLOGY_OPERATOR_DILATE) { if (bpp == 1) { morphologicalFilter1D< std::greater<unsigned char>, Geom::Y, 1 >(interm, out, yr); diff --git a/src/display/nr-filter-offset.cpp b/src/display/nr-filter-offset.cpp index 833f6ecc9..3543de6df 100644 --- a/src/display/nr-filter-offset.cpp +++ b/src/display/nr-filter-offset.cpp @@ -35,6 +35,12 @@ void FilterOffset::render_cairo(FilterSlot &slot) { cairo_surface_t *in = slot.getcairo(_input); cairo_surface_t *out = ink_cairo_surface_create_identical(in); + // color_interpolation_filters for out same as in. See spec (DisplacementMap). + copy_cairo_surface_ci(in, out); + + // std::cout << "FilterOffset: ci data: out: " + // << get_cairo_surface_ci(out) << std::endl; + cairo_t *ct = cairo_create(out); Geom::Affine trans = slot.get_units().get_matrix_primitiveunits2pb(); diff --git a/src/display/nr-filter-primitive.cpp b/src/display/nr-filter-primitive.cpp index ce562668a..fca82c810 100644 --- a/src/display/nr-filter-primitive.cpp +++ b/src/display/nr-filter-primitive.cpp @@ -20,6 +20,7 @@ #include "desktop-handles.h" #include "document.h" #include "sp-root.h" +#include "style.h" namespace Inkscape { namespace Filters { @@ -45,11 +46,14 @@ FilterPrimitive::FilterPrimitive() _subregion_y.unset(SVGLength::PERCENT, 0, 0); _subregion_width.unset(SVGLength::PERCENT, 1, 0); _subregion_height.unset(SVGLength::PERCENT, 1, 0); + + _style = NULL; } FilterPrimitive::~FilterPrimitive() { - // Nothing to do here + if(_style) + sp_style_unref(_style); } void FilterPrimitive::render_cairo(FilterSlot &slot) @@ -179,6 +183,14 @@ Geom::Rect FilterPrimitive::filter_primitive_area(FilterUnits const &units) return area; } +void FilterPrimitive::setStyle(SPStyle *style) +{ + if (style) sp_style_ref(style); + if (_style) sp_style_unref(_style); + _style = style; +} + + } /* namespace Filters */ } /* namespace Inkscape */ diff --git a/src/display/nr-filter-primitive.h b/src/display/nr-filter-primitive.h index da2097156..214b2cfc5 100644 --- a/src/display/nr-filter-primitive.h +++ b/src/display/nr-filter-primitive.h @@ -16,6 +16,8 @@ #include "display/nr-filter-types.h" #include "svg/svg-length.h" +class SPStyle; + namespace Inkscape { namespace Filters { @@ -113,6 +115,11 @@ public: */ virtual bool can_handle_affine(Geom::Affine const &) { return false; } + /** + * Sets style for access to properties used by filter primitives. + */ + void setStyle(SPStyle *style); + protected: int _input; int _output; @@ -122,6 +129,8 @@ protected: SVGLength _subregion_y; SVGLength _subregion_width; SVGLength _subregion_height; + + SPStyle *_style; }; diff --git a/src/display/nr-filter-slot.cpp b/src/display/nr-filter-slot.cpp index 4f7a8849e..64c5143ff 100644 --- a/src/display/nr-filter-slot.cpp +++ b/src/display/nr-filter-slot.cpp @@ -84,11 +84,13 @@ cairo_surface_t *FilterSlot::getcairo(int slot_nr) case NR_FILTER_SOURCEGRAPHIC: { cairo_surface_t *tr = _get_transformed_source_graphic(); _set_internal(NR_FILTER_SOURCEGRAPHIC, tr); + //std::cout << "Source Graphic: ci data: " << get_cairo_surface_ci( tr ) << std::endl; cairo_surface_destroy(tr); } break; case NR_FILTER_BACKGROUNDIMAGE: { cairo_surface_t *bg = _get_transformed_background(); _set_internal(NR_FILTER_BACKGROUNDIMAGE, bg); + //std::cout << "Background Image: ci data: " << get_cairo_surface_ci( bg ) << std::endl; cairo_surface_destroy(bg); } break; case NR_FILTER_SOURCEALPHA: { @@ -129,6 +131,9 @@ cairo_surface_t *FilterSlot::_get_transformed_source_graphic() if (trans.isTranslation()) { cairo_surface_reference(_source_graphic); + + // Assume all source graphics are sRGB + set_cairo_surface_ci( _source_graphic, SP_CSS_COLOR_INTERPOLATION_SRGB ); return _source_graphic; } @@ -145,6 +150,8 @@ cairo_surface_t *FilterSlot::_get_transformed_source_graphic() cairo_paint(tsg_ct); cairo_destroy(tsg_ct); + // Assume all source graphics are sRGB + set_cairo_surface_ci( tsg, SP_CSS_COLOR_INTERPOLATION_SRGB ); return tsg; } @@ -172,6 +179,9 @@ cairo_surface_t *FilterSlot::_get_transformed_background() tbg = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, _slot_w, _slot_h); } + // Assume all source graphics are sRGB + set_cairo_surface_ci( tbg, SP_CSS_COLOR_INTERPOLATION_SRGB ); + return tbg; } diff --git a/src/display/nr-filter-specularlighting.cpp b/src/display/nr-filter-specularlighting.cpp index 0242754eb..4cf8f319d 100644 --- a/src/display/nr-filter-specularlighting.cpp +++ b/src/display/nr-filter-specularlighting.cpp @@ -139,6 +139,18 @@ void FilterSpecularLighting::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); + // Only alpha channel of input is used, no need to check input color_interpolation_filter value. + SPColorInterpolation ci_fp = SP_CSS_COLOR_INTERPOLATION_AUTO; + if( _style ) { + set_cairo_surface_ci(out, (SPColorInterpolation)_style->color_interpolation_filters.computed ); + set_cairo_surface_ci(out, ci_fp ); + } + + // std::cout << "FilterSpecularLighting: ci data: " + // << " in1: " << get_cairo_surface_ci(input) + // << " out: " << get_cairo_surface_ci(out) + // << std::endl; + Geom::Affine trans = slot.get_units().get_matrix_primitiveunits2pb(); Geom::Point p = slot.get_slot_area().min(); double x0 = p[Geom::X]; diff --git a/src/display/nr-filter-turbulence.cpp b/src/display/nr-filter-turbulence.cpp index bce532f21..e2b52a1d4 100644 --- a/src/display/nr-filter-turbulence.cpp +++ b/src/display/nr-filter-turbulence.cpp @@ -375,6 +375,13 @@ 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); + // color_interpolation_filter is determined by CSS value (see spec. Turbulence). + if( _style ) { + set_cairo_surface_ci(out, (SPColorInterpolation)_style->color_interpolation_filters.computed ); + } + // std::cout << "FilterTurbulance: ci data: out: " + // << get_cairo_surface_ci(out) << std::endl; + if (!gen->ready()) { Geom::Point ta(fTileX, fTileY); Geom::Point tb(fTileX + fTileWidth, fTileY + fTileHeight); diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp index f580a5044..a29ac551a 100644 --- a/src/display/nr-filter.cpp +++ b/src/display/nr-filter.cpp @@ -38,6 +38,7 @@ #include "display/nr-filter-tile.h" #include "display/nr-filter-turbulence.h" +#include "display/cairo-utils.h" #include "display/drawing.h" #include "display/drawing-item.h" #include "display/drawing-context.h" @@ -159,6 +160,16 @@ int Filter::render(Inkscape::DrawingItem const *item, DrawingContext &graphic, D Geom::Point origin = graphic.targetLogicalBounds().min(); cairo_surface_t *result = slot.get_result(_output_slot); + + // std::cout << "Filter: result: ci data: " + // << get_cairo_surface_ci(result) << std::endl; + + // Assume for the moment that we paint the filter in sRGB + if( get_cairo_surface_ci(result) == SP_CSS_COLOR_INTERPOLATION_LINEARRGB ) { + //std::cout << "Filter: result: linear -> sRGB" << std::endl; + ink_cairo_surface_linear_to_srgb( result ); + } + graphic.setSource(result, origin[Geom::X], origin[Geom::Y]); graphic.setOperator(CAIRO_OPERATOR_SOURCE); graphic.paint(); diff --git a/src/filter-chemistry.cpp b/src/filter-chemistry.cpp index fc74ee8a2..14bd00057 100644 --- a/src/filter-chemistry.cpp +++ b/src/filter-chemistry.cpp @@ -98,7 +98,10 @@ SPFilter *new_filter(SPDocument *document) Inkscape::XML::Node *repr; repr = xml_doc->createElement("svg:filter"); - // Inkscape only supports sRGB. See note in sp-filter.cpp. + // Inkscape now supports both sRGB and linear color-interpolation-filters. + // But, for the moment, keep sRGB as default value for new filters + // (historically set to sRGB and doesn't require conversion between + // filter cairo surfaces and other types of cairo surfaces). SPCSSAttr *css = sp_repr_css_attr_new(); sp_repr_css_set_property(css, "color-interpolation-filters", "sRGB"); sp_repr_css_change(repr, css, "style"); diff --git a/src/sp-filter-primitive.cpp b/src/sp-filter-primitive.cpp index b63a05b4b..7ddf3b065 100644 --- a/src/sp-filter-primitive.cpp +++ b/src/sp-filter-primitive.cpp @@ -20,6 +20,7 @@ #include <string.h> #include "attributes.h" +#include "style.h" #include "sp-filter-primitive.h" #include "xml/repr.h" #include "sp-filter.h" @@ -100,16 +101,17 @@ static void sp_filter_primitive_init(SPFilterPrimitive *filter_primitive) static void sp_filter_primitive_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) { - if ((static_cast<SPObjectClass *>(filter_primitive_parent_class))->build) { - (static_cast<SPObjectClass *>(filter_primitive_parent_class))->build(object, document, repr); - } - + object->readAttr( "style" ); // struct not derived from SPItem, we need to do this ourselves. object->readAttr( "in" ); object->readAttr( "result" ); object->readAttr( "x" ); object->readAttr( "y" ); object->readAttr( "width" ); object->readAttr( "height" ); + + if ((static_cast<SPObjectClass *>(filter_primitive_parent_class))->build) { + (static_cast<SPObjectClass *>(filter_primitive_parent_class))->build(object, document, repr); + } } /** @@ -188,7 +190,9 @@ sp_filter_primitive_update(SPObject *object, SPCtx *ctx, guint flags) { //SPFilterPrimitive *filter_primitive = SP_FILTER_PRIMITIVE(object); + // Is this required? if (flags & SP_OBJECT_MODIFIED_FLAG) { + object->readAttr( "style" ); object->readAttr( "in" ); object->readAttr( "result" ); object->readAttr( "x" ); @@ -311,6 +315,9 @@ void sp_filter_primitive_renderer_common(SPFilterPrimitive *sp_prim, Inkscape::F /* TODO: place here code to handle input images, filter area etc. */ nr_prim->set_subregion( sp_prim->x, sp_prim->y, sp_prim->width, sp_prim->height ); + + // Give renderer access to filter properties + nr_prim->setStyle( sp_prim->style ); } diff --git a/src/sp-filter.cpp b/src/sp-filter.cpp index a20856f53..c7dce3850 100644 --- a/src/sp-filter.cpp +++ b/src/sp-filter.cpp @@ -130,11 +130,8 @@ sp_filter_init(SPFilter *filter) static void sp_filter_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) { - if (((SPObjectClass *) filter_parent_class)->build) { - ((SPObjectClass *) filter_parent_class)->build(object, document, repr); - } - //Read values of key attributes from XML nodes into object. + object->readAttr( "style" ); // struct not derived from SPItem, we need to do this ourselves. object->readAttr( "filterUnits" ); object->readAttr( "primitiveUnits" ); object->readAttr( "x" ); @@ -144,6 +141,10 @@ sp_filter_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *rep object->readAttr( "filterRes" ); object->readAttr( "xlink:href" ); + if (((SPObjectClass *) filter_parent_class)->build) { + ((SPObjectClass *) filter_parent_class)->build(object, document, repr); + } + //is this necessary? document->addResource("filter", object); } @@ -366,25 +367,6 @@ sp_filter_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::N g_free(uri_string); } - // TODO: This is evil, correctly implement support for color-interpolation-filters!!! - // The color-interpolation-filters attribute is initially set to linearRGB according to the SVG standard. - // However, Inkscape completely ignores it and implicitly assumes that it is sRGB (like color-interpolation). - // This results in a discrepancy between Inkscape and other renderers in how they render filters. - // To mitigate this problem I've (Jasper van de Gronde,th.v.d.gronde@hccnet.nl) added this to ensure that at least - // any filters written by Inkscape will henceforth be rendered the same in other renderers. - // In the future Inkscape should have proper support for the color-interpolation properties and this should be changed. - - // repr->setAttribute("color-interpolation-filters", "sRGB"); - - // Actually, the above line is not correct as the attribute is only allowed on filter - // primitives and not <filter> objects. However, it is allowed as a property in a style - // attribute. Note, this property must also be set in sp-filter-chemistry, filter_new() as the - // code here is not necessarily called when a new filter is created. 29 Aug 2011 Tav. - SPCSSAttr *css = sp_repr_css_attr_new(); - sp_repr_css_set_property(css, "color-interpolation-filters", "sRGB"); - sp_repr_css_change(repr, css, "style"); - sp_repr_css_attr_unref(css); - if (((SPObjectClass *) filter_parent_class)->write) { ((SPObjectClass *) filter_parent_class)->write(object, doc, repr, flags); } |
