summaryrefslogtreecommitdiffstats
path: root/src/display
diff options
context:
space:
mode:
authorsu_v <suv-sf@users.sourceforge.net>2013-01-01 18:24:47 +0000
committer~suv <suv-sf@users.sourceforge.net>2013-01-01 18:24:47 +0000
commit0b3b386881da011ac7ee60dd20bd610fd9670677 (patch)
tree59d08dfb788ebbe333fa21140fcd8203faadc356 /src/display
parentmerge from trunk (r11952) (diff)
parentclip path visual bbox refresh, second try (Bug 1005085) (diff)
downloadinkscape-0b3b386881da011ac7ee60dd20bd610fd9670677.tar.gz
inkscape-0b3b386881da011ac7ee60dd20bd610fd9670677.zip
merge from trunk (r12005)
(bzr r11668.1.47)
Diffstat (limited to 'src/display')
-rw-r--r--src/display/cairo-utils.cpp125
-rw-r--r--src/display/cairo-utils.h15
-rw-r--r--src/display/drawing.cpp34
-rw-r--r--src/display/nr-filter-blend.cpp14
-rw-r--r--src/display/nr-filter-colormatrix.cpp89
-rw-r--r--src/display/nr-filter-colormatrix.h9
-rw-r--r--src/display/nr-filter-component-transfer.cpp11
-rw-r--r--src/display/nr-filter-composite.cpp11
-rw-r--r--src/display/nr-filter-convolve-matrix.cpp13
-rw-r--r--src/display/nr-filter-diffuselighting.cpp7
-rw-r--r--src/display/nr-filter-displacement-map.cpp11
-rw-r--r--src/display/nr-filter-flood.cpp6
-rw-r--r--src/display/nr-filter-gaussian.cpp13
-rw-r--r--src/display/nr-filter-image.cpp6
-rw-r--r--src/display/nr-filter-merge.cpp8
-rw-r--r--src/display/nr-filter-morphology.cpp4
-rw-r--r--src/display/nr-filter-offset.cpp3
-rw-r--r--src/display/nr-filter-primitive.cpp14
-rw-r--r--src/display/nr-filter-primitive.h9
-rw-r--r--src/display/nr-filter-slot.cpp8
-rw-r--r--src/display/nr-filter-specularlighting.cpp7
-rw-r--r--src/display/nr-filter-turbulence.cpp5
-rw-r--r--src/display/nr-filter.cpp5
-rw-r--r--src/display/nr-svgfonts.cpp2
-rw-r--r--src/display/sp-canvas.cpp59
25 files changed, 402 insertions, 86 deletions
diff --git a/src/display/cairo-utils.cpp b/src/display/cairo-utils.cpp
index 2e2eb42dd..692e31837 100644
--- a/src/display/cairo-utils.cpp
+++ b/src/display/cairo-utils.cpp
@@ -24,6 +24,7 @@
#include <2geom/transforms.h>
#include <2geom/sbasis-to-bezier.h>
#include "color.h"
+#include "style.h"
#include "helper/geom-curves.h"
namespace Inkscape {
@@ -276,6 +277,43 @@ feed_pathvector_to_cairo (cairo_t *ct, Geom::PathVector const &pathv)
}
}
+SPColorInterpolation
+get_cairo_surface_ci(cairo_surface_t *surface) {
+ void* data = cairo_surface_get_user_data( surface, &ci_key );
+ if( data != NULL ) {
+ return (SPColorInterpolation)GPOINTER_TO_INT( data );
+ } else {
+ return SP_CSS_COLOR_INTERPOLATION_AUTO;
+ }
+}
+
+/** Set the color_interpolation_value for a Cairo surface.
+ * Transform the surface between sRGB and linearRGB if necessary. */
+void
+set_cairo_surface_ci(cairo_surface_t *surface, SPColorInterpolation ci) {
+
+ if( cairo_surface_get_content( surface ) != CAIRO_CONTENT_ALPHA ) {
+
+ SPColorInterpolation ci_in = get_cairo_surface_ci( surface );
+
+ if( ci_in == SP_CSS_COLOR_INTERPOLATION_SRGB &&
+ ci == SP_CSS_COLOR_INTERPOLATION_LINEARRGB ) {
+ ink_cairo_surface_srgb_to_linear( surface );
+ }
+ if( ci_in == SP_CSS_COLOR_INTERPOLATION_LINEARRGB &&
+ ci == SP_CSS_COLOR_INTERPOLATION_SRGB ) {
+ ink_cairo_surface_linear_to_srgb( surface );
+ }
+
+ cairo_surface_set_user_data(surface, &ci_key, GINT_TO_POINTER (ci), NULL);
+ }
+}
+
+void
+copy_cairo_surface_ci(cairo_surface_t *in, cairo_surface_t *out) {
+ cairo_surface_set_user_data(out, &ci_key, cairo_surface_get_user_data(in, &ci_key), NULL);
+}
+
void
ink_cairo_set_source_rgba32(cairo_t *ct, guint32 rgba)
{
@@ -395,6 +433,7 @@ cairo_surface_t *
ink_cairo_surface_create_identical(cairo_surface_t *s)
{
cairo_surface_t *ns = ink_cairo_surface_create_same_size(s, cairo_surface_get_content(s));
+ cairo_surface_set_user_data(ns, &ci_key, cairo_surface_get_user_data(s, &ci_key), NULL);
return ns;
}
@@ -547,6 +586,92 @@ void ink_cairo_surface_average_color_premul(cairo_surface_t *surface, double &r,
a = CLAMP(a, 0.0, 1.0);
}
+void srgb_to_linear( guint32* c, guint32 a ) {
+
+ *c = unpremul_alpha( *c, a );
+
+ double cc = *c/255.0;
+
+ if( cc < 0.04045 ) {
+ cc /= 12.92;
+ } else {
+ cc = pow( (cc+0.055)/1.055, 2.4 );
+ }
+ cc *= 255.0;
+
+ *c = (int)cc;
+
+ *c = premul_alpha( *c, a );
+}
+
+void linear_to_srgb( guint32* c, guint32 a ) {
+
+ *c = unpremul_alpha( *c, a );
+
+ double cc = *c/255.0;
+
+ if( cc < 0.0031308 ) {
+ cc *= 12.92;
+ } else {
+ cc = pow( cc, 1.0/2.4 )*1.055-0.055;
+ }
+ cc *= 255.0;
+
+ *c = (int)cc;
+
+ *c = premul_alpha( *c, a );
+}
+
+int ink_cairo_surface_srgb_to_linear(cairo_surface_t *surface)
+{
+ cairo_surface_flush(surface);
+ int width = cairo_image_surface_get_width(surface);
+ int height = cairo_image_surface_get_height(surface);
+ int stride = cairo_image_surface_get_stride(surface);
+ unsigned char *data = cairo_image_surface_get_data(surface);
+
+ /* TODO convert this to OpenMP somehow */
+ for (int y = 0; y < height; ++y, data += stride) {
+ for (int x = 0; x < width; ++x) {
+ guint32 px = *reinterpret_cast<guint32*>(data + 4*x);
+ EXTRACT_ARGB32(px, a,r,g,b) ; // Unneeded semi-colon for indenting
+ if( a != 0 ) {
+ srgb_to_linear( &r, a );
+ srgb_to_linear( &g, a );
+ srgb_to_linear( &b, a );
+ }
+ ASSEMBLE_ARGB32(px2, a,r,g,b);
+ *reinterpret_cast<guint32*>(data + 4*x) = px2;
+ }
+ }
+ return width * height;
+}
+
+int ink_cairo_surface_linear_to_srgb(cairo_surface_t *surface)
+{
+ cairo_surface_flush(surface);
+ int width = cairo_image_surface_get_width(surface);
+ int height = cairo_image_surface_get_height(surface);
+ int stride = cairo_image_surface_get_stride(surface);
+ unsigned char *data = cairo_image_surface_get_data(surface);
+
+ /* TODO convert this to OpenMP somehow */
+ for (int y = 0; y < height; ++y, data += stride) {
+ for (int x = 0; x < width; ++x) {
+ guint32 px = *reinterpret_cast<guint32*>(data + 4*x);
+ EXTRACT_ARGB32(px, a,r,g,b) ; // Unneeded semi-colon for indenting
+ if( a != 0 ) {
+ linear_to_srgb( &r, a );
+ linear_to_srgb( &g, a );
+ linear_to_srgb( &b, a );
+ }
+ ASSEMBLE_ARGB32(px2, a,r,g,b);
+ *reinterpret_cast<guint32*>(data + 4*x) = px2;
+ }
+ }
+ return width * height;
+}
+
cairo_pattern_t *
ink_cairo_pattern_create_checkerboard()
{
diff --git a/src/display/cairo-utils.h b/src/display/cairo-utils.h
index e67872891..d240545eb 100644
--- a/src/display/cairo-utils.h
+++ b/src/display/cairo-utils.h
@@ -15,6 +15,7 @@
#include <glib.h>
#include <cairomm/cairomm.h>
#include <2geom/forward.h>
+#include "style.h"
struct SPColor;
struct _GdkPixbuf;
@@ -81,6 +82,17 @@ public:
} // namespace Inkscape
+/**
+ * Key for cairo_surface_t to keep track of current color interpolation value
+ * Only the address of the structure is used, it is never initialized. See:
+ * http://www.cairographics.org/manual/cairo-Types.html#cairo-user-data-key-t
+ */
+static cairo_user_data_key_t ci_key;
+SPColorInterpolation get_cairo_surface_ci(cairo_surface_t *surface);
+void set_cairo_surface_ci(cairo_surface_t *surface, SPColorInterpolation cif);
+void copy_cairo_surface_ci(cairo_surface_t *in, cairo_surface_t *out);
+void convert_cairo_surface_ci(cairo_surface_t *surface, SPColorInterpolation cif);
+
void ink_cairo_set_source_color(cairo_t *ct, SPColor const &color, double opacity);
void ink_cairo_set_source_rgba32(cairo_t *ct, guint32 rgba);
void ink_cairo_transform(cairo_t *ct, Geom::Affine const &m);
@@ -102,6 +114,9 @@ guint32 ink_cairo_surface_average_color(cairo_surface_t *surface);
void ink_cairo_surface_average_color(cairo_surface_t *surface, double &r, double &g, double &b, double &a);
void ink_cairo_surface_average_color_premul(cairo_surface_t *surface, double &r, double &g, double &b, double &a);
+int ink_cairo_surface_srgb_to_linear(cairo_surface_t *surface);
+int ink_cairo_surface_linear_to_srgb(cairo_surface_t *surface);
+
cairo_pattern_t *ink_cairo_pattern_create_checkerboard();
void convert_pixels_pixbuf_to_argb32(guchar *data, int w, int h, int rs);
diff --git a/src/display/drawing.cpp b/src/display/drawing.cpp
index 77f24caf3..171cc014f 100644
--- a/src/display/drawing.cpp
+++ b/src/display/drawing.cpp
@@ -4,8 +4,9 @@
*//*
* Authors:
* Krzysztof KosiƄski <tweenk.pl@gmail.com>
+ * Johan Engelen <j.b.c.engelen@alumnus.utwente.nl>
*
- * Copyright (C) 2011 Authors
+ * Copyright (C) 2011-2012 Authors
* Released under GNU GPL, read the file 'COPYING' for more information
*/
@@ -14,6 +15,12 @@
#include "nr-filter-gaussian.h"
#include "nr-filter-types.h"
+//grayscale colormode:
+#include "nr-filter-colormatrix.h"
+#include "cairo-templates.h"
+#include "drawing-context.h"
+
+
namespace Inkscape {
Drawing::Drawing(SPCanvasArena *arena)
@@ -145,12 +152,37 @@ Drawing::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigned fl
_pickItemsForCaching();
}
+// hardcoded grayscale color matrix values. could be turned into preference settings in future.
+static const gdouble grayscale_value_matrix[] = {
+ 0.21, 0.72, 0.072, 0, 0,
+ 0.21, 0.72, 0.072, 0, 0,
+ 0.21, 0.72, 0.072, 0, 0,
+ 0 , 0 , 0 , 1, 0
+};
+static Filters::FilterColorMatrix::ColorMatrixMatrix grayscale_colormatrix(
+ std::vector<gdouble> (grayscale_value_matrix, grayscale_value_matrix + sizeof(grayscale_value_matrix) / sizeof(grayscale_value_matrix[0]) )
+);
+
void
Drawing::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flags)
{
if (_root) {
_root->render(ct, area, flags);
}
+
+ if (colorMode() == COLORMODE_GRAYSCALE) {
+ // apply grayscale filter on top of everything
+ cairo_surface_t *input = ct.rawTarget();
+ cairo_surface_t *out = ink_cairo_surface_create_identical(input);
+ ink_cairo_surface_filter(input, out, grayscale_colormatrix);
+ Geom::Point origin = ct.targetLogicalBounds().min();
+ ct.setSource(out, origin[Geom::X], origin[Geom::Y]);
+ ct.setOperator(CAIRO_OPERATOR_SOURCE);
+ ct.paint();
+ ct.setOperator(CAIRO_OPERATOR_OVER);
+
+ cairo_surface_destroy(out);
+ }
}
DrawingItem *
diff --git a/src/display/nr-filter-blend.cpp b/src/display/nr-filter-blend.cpp
index 267883b4b..a08191f67 100644
--- a/src/display/nr-filter-blend.cpp
+++ b/src/display/nr-filter-blend.cpp
@@ -146,13 +146,23 @@ 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.
+ SPColorInterpolation ci_fp = SP_CSS_COLOR_INTERPOLATION_AUTO;
+ if( _style ) {
+ ci_fp = (SPColorInterpolation)_style->color_interpolation_filters.computed;
+ }
+ set_cairo_surface_ci( input1, ci_fp );
+ set_cairo_surface_ci( input2, ci_fp );
// 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);
+ set_cairo_surface_ci( out, ci_fp );
+ 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 33718ed68..77873d523 100644
--- a/src/display/nr-filter-colormatrix.cpp
+++ b/src/display/nr-filter-colormatrix.cpp
@@ -32,50 +32,47 @@ FilterPrimitive * FilterColorMatrix::create() {
FilterColorMatrix::~FilterColorMatrix()
{}
-struct ColorMatrixMatrix {
- ColorMatrixMatrix(std::vector<double> const &values) {
- unsigned limit = std::min(static_cast<size_t>(20), values.size());
- for (unsigned i = 0; i < limit; ++i) {
- if (i % 5 == 4) {
- _v[i] = round(values[i]*255*255);
- } else {
- _v[i] = round(values[i]*255);
- }
- }
- for (unsigned i = limit; i < 20; ++i) {
- _v[i] = 0;
+FilterColorMatrix::ColorMatrixMatrix::ColorMatrixMatrix(std::vector<double> const &values) {
+ unsigned limit = std::min(static_cast<size_t>(20), values.size());
+ for (unsigned i = 0; i < limit; ++i) {
+ if (i % 5 == 4) {
+ _v[i] = round(values[i]*255*255);
+ } else {
+ _v[i] = round(values[i]*255);
}
}
+ for (unsigned i = limit; i < 20; ++i) {
+ _v[i] = 0;
+ }
+}
- guint32 operator()(guint32 in) {
- EXTRACT_ARGB32(in, a, r, g, b)
- // we need to un-premultiply alpha values for this type of matrix
- // TODO: unpremul can be ignored if there is an identity mapping on the alpha channel
- if (a != 0) {
- r = unpremul_alpha(r, a);
- g = unpremul_alpha(g, a);
- b = unpremul_alpha(b, a);
- }
-
- gint32 ro = r*_v[0] + g*_v[1] + b*_v[2] + a*_v[3] + _v[4];
- gint32 go = r*_v[5] + g*_v[6] + b*_v[7] + a*_v[8] + _v[9];
- gint32 bo = r*_v[10] + g*_v[11] + b*_v[12] + a*_v[13] + _v[14];
- gint32 ao = r*_v[15] + g*_v[16] + b*_v[17] + a*_v[18] + _v[19];
- ro = (pxclamp(ro, 0, 255*255) + 127) / 255;
- go = (pxclamp(go, 0, 255*255) + 127) / 255;
- bo = (pxclamp(bo, 0, 255*255) + 127) / 255;
- ao = (pxclamp(ao, 0, 255*255) + 127) / 255;
+guint32 FilterColorMatrix::ColorMatrixMatrix::operator()(guint32 in) {
+ EXTRACT_ARGB32(in, a, r, g, b)
+ // we need to un-premultiply alpha values for this type of matrix
+ // TODO: unpremul can be ignored if there is an identity mapping on the alpha channel
+ if (a != 0) {
+ r = unpremul_alpha(r, a);
+ g = unpremul_alpha(g, a);
+ b = unpremul_alpha(b, a);
+ }
- ro = premul_alpha(ro, ao);
- go = premul_alpha(go, ao);
- bo = premul_alpha(bo, ao);
+ gint32 ro = r*_v[0] + g*_v[1] + b*_v[2] + a*_v[3] + _v[4];
+ gint32 go = r*_v[5] + g*_v[6] + b*_v[7] + a*_v[8] + _v[9];
+ gint32 bo = r*_v[10] + g*_v[11] + b*_v[12] + a*_v[13] + _v[14];
+ gint32 ao = r*_v[15] + g*_v[16] + b*_v[17] + a*_v[18] + _v[19];
+ ro = (pxclamp(ro, 0, 255*255) + 127) / 255;
+ go = (pxclamp(go, 0, 255*255) + 127) / 255;
+ bo = (pxclamp(bo, 0, 255*255) + 127) / 255;
+ ao = (pxclamp(ao, 0, 255*255) + 127) / 255;
+
+ ro = premul_alpha(ro, ao);
+ go = premul_alpha(go, ao);
+ bo = premul_alpha(bo, ao);
+
+ ASSEMBLE_ARGB32(pxout, ao, ro, go, bo)
+ return pxout;
+}
- ASSEMBLE_ARGB32(pxout, ao, ro, go, bo)
- return pxout;
- }
-private:
- gint32 _v[20];
-};
struct ColorMatrixSaturate {
ColorMatrixSaturate(double v_in) {
@@ -155,15 +152,27 @@ 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.
+ SPColorInterpolation ci_fp = SP_CSS_COLOR_INTERPOLATION_AUTO;
+ if( _style ) {
+ ci_fp = (SPColorInterpolation)_style->color_interpolation_filters.computed;
+ }
+ set_cairo_surface_ci( input, ci_fp );
+
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);
}
switch (type) {
case COLORMATRIX_MATRIX:
- ink_cairo_surface_filter(input, out, ColorMatrixMatrix(values));
+ ink_cairo_surface_filter(input, out, FilterColorMatrix::ColorMatrixMatrix(values));
break;
case COLORMATRIX_SATURATE:
ink_cairo_surface_filter(input, out, ColorMatrixSaturate(value));
diff --git a/src/display/nr-filter-colormatrix.h b/src/display/nr-filter-colormatrix.h
index 5f21a4210..c7e5e91d9 100644
--- a/src/display/nr-filter-colormatrix.h
+++ b/src/display/nr-filter-colormatrix.h
@@ -42,6 +42,15 @@ public:
virtual void set_type(FilterColorMatrixType type);
virtual void set_value(gdouble value);
virtual void set_values(std::vector<gdouble> const &values);
+
+public:
+ struct ColorMatrixMatrix {
+ ColorMatrixMatrix(std::vector<double> const &values);
+ guint32 operator()(guint32 in);
+ private:
+ gint32 _v[20];
+ };
+
private:
std::vector<gdouble> values;
gdouble value;
diff --git a/src/display/nr-filter-component-transfer.cpp b/src/display/nr-filter-component-transfer.cpp
index 226a73cef..3bc00d2d7 100644
--- a/src/display/nr-filter-component-transfer.cpp
+++ b/src/display/nr-filter-component-transfer.cpp
@@ -238,6 +238,17 @@ 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.
+ 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 );
+ }
+ set_cairo_surface_ci( input, ci_fp );
+
//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..f6decad0d 100644
--- a/src/display/nr-filter-composite.cpp
+++ b/src/display/nr-filter-composite.cpp
@@ -66,7 +66,18 @@ 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.
+ SPColorInterpolation ci_fp = SP_CSS_COLOR_INTERPOLATION_AUTO;
+ if( _style ) {
+ ci_fp = (SPColorInterpolation)_style->color_interpolation_filters.computed;
+ }
+ set_cairo_surface_ci( input1, ci_fp );
+ set_cairo_surface_ci( input2, ci_fp );
+
cairo_surface_t *out = ink_cairo_surface_create_output(input1, input2);
+ set_cairo_surface_ci(out, ci_fp );
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..2aad528a6 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,19 @@ 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.
+ 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);
+ }
+ set_cairo_surface_ci( input, ci_fp );
+
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..faf56a4ca 100644
--- a/src/display/nr-filter-diffuselighting.cpp
+++ b/src/display/nr-filter-diffuselighting.cpp
@@ -126,6 +126,13 @@ 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 ) {
+ ci_fp = (SPColorInterpolation)_style->color_interpolation_filters.computed;
+ }
+ set_cairo_surface_ci(out, ci_fp );
+
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..1b979fa6c 100644
--- a/src/display/nr-filter-displacement-map.cpp
+++ b/src/display/nr-filter-displacement-map.cpp
@@ -74,6 +74,17 @@ 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.
+ SPColorInterpolation ci_fp = SP_CSS_COLOR_INTERPOLATION_AUTO;
+ if( _style ) {
+ ci_fp = (SPColorInterpolation)_style->color_interpolation_filters.computed;
+ }
+ set_cairo_surface_ci( map, ci_fp );
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..7117e0343 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,10 @@ 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 );
+ }
// 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..9d7c32585 100644
--- a/src/display/nr-filter-gaussian.cpp
+++ b/src/display/nr-filter-gaussian.cpp
@@ -553,6 +553,15 @@ 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.
+ SPColorInterpolation ci_fp = SP_CSS_COLOR_INTERPOLATION_AUTO;
+ if( _style ) {
+ ci_fp = (SPColorInterpolation)_style->color_interpolation_filters.computed;
+ }
+ set_cairo_surface_ci( in, ci_fp );
+
// zero deviation = no change in output
if (_deviation_x <= 0 && _deviation_y <= 0) {
cairo_surface_t *cp = ink_cairo_surface_copy(in);
@@ -660,10 +669,14 @@ void FilterGaussian::render_cairo(FilterSlot &slot)
cairo_paint(ct);
cairo_destroy(ct);
+ set_cairo_surface_ci( upsampled, ci_fp );
+
slot.set(_output, upsampled);
cairo_surface_destroy(upsampled);
cairo_surface_destroy(downsampled);
} else {
+ set_cairo_surface_ci( downsampled, ci_fp );
+
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..fca8fdba3 100644
--- a/src/display/nr-filter-image.cpp
+++ b/src/display/nr-filter-image.cpp
@@ -120,6 +120,9 @@ 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);
+
slot.set(_output, out);
cairo_surface_destroy(out);
return;
@@ -185,6 +188,9 @@ 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);
+
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..2b9a24f25 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,8 @@ 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);
+
+ set_cairo_surface_ci( in, ci_fp );
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..b058307cf 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,9 @@ 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);
+
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..01d6ffe56 100644
--- a/src/display/nr-filter-offset.cpp
+++ b/src/display/nr-filter-offset.cpp
@@ -35,6 +35,9 @@ 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);
+
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..fe67972d6 100644
--- a/src/display/nr-filter-slot.cpp
+++ b/src/display/nr-filter-slot.cpp
@@ -129,6 +129,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 +148,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 +177,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..50f1b48c5 100644
--- a/src/display/nr-filter-specularlighting.cpp
+++ b/src/display/nr-filter-specularlighting.cpp
@@ -139,6 +139,13 @@ 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 ) {
+ ci_fp = (SPColorInterpolation)_style->color_interpolation_filters.computed;
+ }
+ set_cairo_surface_ci(out, ci_fp );
+
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..76b877fbc 100644
--- a/src/display/nr-filter-turbulence.cpp
+++ b/src/display/nr-filter-turbulence.cpp
@@ -375,6 +375,11 @@ 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 );
+ }
+
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..eeba94d7c 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,10 @@ 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);
+
+ // Assume for the moment that we paint the filter in sRGB
+ set_cairo_surface_ci( result, SP_CSS_COLOR_INTERPOLATION_SRGB );
+
graphic.setSource(result, origin[Geom::X], origin[Geom::Y]);
graphic.setOperator(CAIRO_OPERATOR_SOURCE);
graphic.paint();
diff --git a/src/display/nr-svgfonts.cpp b/src/display/nr-svgfonts.cpp
index d0c6d2d56..0d1b56d54 100644
--- a/src/display/nr-svgfonts.cpp
+++ b/src/display/nr-svgfonts.cpp
@@ -16,7 +16,7 @@
#include <2geom/transforms.h>
#include <cairo.h>
#include <vector>
-#include "style.h"
+#include "sp-object.h"
#include "svg/svg.h"
#include "display/cairo-utils.h"
#include "display/nr-svgfonts.h"
diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp
index 536c54609..eb51860ab 100644
--- a/src/display/sp-canvas.cpp
+++ b/src/display/sp-canvas.cpp
@@ -291,7 +291,7 @@ public:
#if GTK_CHECK_VERSION(3,0,0)
static gboolean handleDraw(GtkWidget *widget, cairo_t *cr);
#else
- static gint handleExpose(GtkWidget *widget, GdkEventExpose *event);
+ static gboolean handleExpose(GtkWidget *widget, GdkEventExpose *event);
#endif
/**
@@ -2178,23 +2178,24 @@ void SPCanvas::endForcedFullRedraws()
}
#if GTK_CHECK_VERSION(3,0,0)
-
-//TODO: This could probably be done much more efficiently
gboolean SPCanvasImpl::handleDraw(GtkWidget *widget, cairo_t *cr) {
SPCanvas *canvas = SP_CANVAS(widget);
- gint width = gtk_widget_get_allocated_width(widget);
- gint height = gtk_widget_get_allocated_height(widget);
- Geom::IntRect r = Geom::IntRect::from_xywh(
- canvas->x0, canvas->y0,
- width, height);
+ cairo_rectangle_list_t *rects = cairo_copy_clip_rectangle_list(cr);
+
+ for (int i = 0; i < rects->num_rectangles; i++) {
+ cairo_rectangle_t rectangle = rects->rectangles[i];
+
+ Geom::IntRect r = Geom::IntRect::from_xywh(rectangle.x + canvas->x0, rectangle.y + canvas->y0,
+ rectangle.width, rectangle.height);
- canvas->requestRedraw(r.left(), r.top(), r.right(), r.bottom());
+ canvas->requestRedraw(r.left(), r.top(), r.right(), r.bottom());
+ }
return FALSE;
}
#else
-gint SPCanvasImpl::handleExpose(GtkWidget *widget, GdkEventExpose *event)
+gboolean SPCanvasImpl::handleExpose(GtkWidget *widget, GdkEventExpose *event)
{
SPCanvas *canvas = SP_CANVAS(widget);
@@ -2203,43 +2204,23 @@ gint SPCanvasImpl::handleExpose(GtkWidget *widget, GdkEventExpose *event)
return FALSE;
}
-#if GTK_CHECK_VERSION(3,0,0)
- int n_rects = cairo_region_num_rectangles(event->region);
-#else
int n_rects = 0;
GdkRectangle *rects = NULL;
gdk_region_get_rectangles(event->region, &rects, &n_rects);
if(rects == NULL)
- return FALSE;
-#endif
-
- if (n_rects == 0)
- {
return FALSE;
- }
- else
- {
- for (int i = 0; i < n_rects; i++) {
-#if GTK_CHECK_VERSION(3,0,0)
- cairo_rectangle_int_t rectangle;
- cairo_region_get_rectangle(event->region, i, &rectangle);
-#else
- GdkRectangle rectangle = rects[i];
-#endif
-
- Geom::IntRect r = Geom::IntRect::from_xywh(
- rectangle.x + canvas->x0, rectangle.y + canvas->y0,
- rectangle.width, rectangle.height);
+
+ for (int i = 0; i < n_rects; i++) {
+ GdkRectangle rectangle = rects[i];
+
+ Geom::IntRect r = Geom::IntRect::from_xywh(rectangle.x + canvas->x0, rectangle.y + canvas->y0,
+ rectangle.width, rectangle.height);
- canvas->requestRedraw(r.left(), r.top(), r.right(), r.bottom());
- }
-
-#if !GTK_CHECK_VERSION(3,0,0)
- g_free (rects);
-#endif
- return FALSE;
+ canvas->requestRedraw(r.left(), r.top(), r.right(), r.bottom());
}
+
+ return FALSE;
}
#endif