summaryrefslogtreecommitdiffstats
path: root/src/display
diff options
context:
space:
mode:
authorMarkus Engel <markus.engel@tum.de>2013-03-29 23:52:42 +0000
committerMarkus Engel <markus.engel@tum.de>2013-03-29 23:52:42 +0000
commita168040d5a452544328a1e6ad35aaac351f94d44 (patch)
treefae1ba829f543a473da281bd5fa6e4deabbf6912 /src/display
parentRemoved function pointers from SPObject and subclasses. (diff)
parentDutch translation update (diff)
downloadinkscape-a168040d5a452544328a1e6ad35aaac351f94d44.tar.gz
inkscape-a168040d5a452544328a1e6ad35aaac351f94d44.zip
merged from trunk
(bzr r11608.1.56)
Diffstat (limited to 'src/display')
-rw-r--r--src/display/Makefile_insert3
-rw-r--r--src/display/cairo-templates.h12
-rw-r--r--src/display/cairo-utils.cpp175
-rw-r--r--src/display/cairo-utils.h25
-rw-r--r--src/display/canvas-arena.cpp12
-rw-r--r--src/display/canvas-axonomgrid.cpp164
-rw-r--r--src/display/canvas-axonomgrid.h17
-rw-r--r--src/display/canvas-bpath.h2
-rw-r--r--src/display/canvas-grid.cpp85
-rw-r--r--src/display/canvas-grid.h10
-rw-r--r--src/display/canvas-text.cpp4
-rw-r--r--src/display/curve.cpp2
-rw-r--r--src/display/drawing-context.h2
-rw-r--r--src/display/drawing-group.h2
-rw-r--r--src/display/drawing-image.cpp126
-rw-r--r--src/display/drawing-image.h3
-rw-r--r--src/display/drawing-item.cpp33
-rw-r--r--src/display/drawing-item.h2
-rw-r--r--src/display/drawing-shape.cpp2
-rw-r--r--src/display/drawing-shape.h2
-rw-r--r--src/display/drawing-text.cpp2
-rw-r--r--src/display/drawing-text.h2
-rw-r--r--src/display/drawing.cpp37
-rw-r--r--src/display/drawing.h5
-rw-r--r--src/display/guideline.cpp8
-rw-r--r--src/display/guideline.h2
-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.cpp20
-rw-r--r--src/display/nr-filter-convolve-matrix.cpp13
-rw-r--r--src/display/nr-filter-diffuselighting.cpp44
-rw-r--r--src/display/nr-filter-diffuselighting.h9
-rw-r--r--src/display/nr-filter-displacement-map.cpp11
-rw-r--r--src/display/nr-filter-flood.cpp48
-rw-r--r--src/display/nr-filter-flood.h2
-rw-r--r--src/display/nr-filter-gaussian.cpp23
-rw-r--r--src/display/nr-filter-image.cpp142
-rw-r--r--src/display/nr-filter-image.h1
-rw-r--r--src/display/nr-filter-merge.cpp10
-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.cpp42
-rw-r--r--src/display/nr-filter-primitive.h9
-rw-r--r--src/display/nr-filter-skeleton.cpp3
-rw-r--r--src/display/nr-filter-slot.cpp8
-rw-r--r--src/display/nr-filter-specularlighting.cpp44
-rw-r--r--src/display/nr-filter-specularlighting.h9
-rw-r--r--src/display/nr-filter-turbulence.cpp10
-rw-r--r--src/display/nr-filter.cpp5
-rw-r--r--src/display/nr-style.cpp8
-rw-r--r--src/display/nr-style.h6
-rw-r--r--src/display/nr-svgfonts.cpp72
-rw-r--r--src/display/nr-svgfonts.h4
-rw-r--r--src/display/sodipodi-ctrl.cpp8
-rw-r--r--src/display/sodipodi-ctrlrect.cpp11
-rw-r--r--src/display/sp-canvas.cpp204
-rw-r--r--src/display/sp-canvas.h6
-rw-r--r--src/display/sp-ctrlcurve.h2
-rw-r--r--src/display/sp-ctrlpoint.cpp4
-rw-r--r--src/display/sp-ctrlquadr.cpp4
62 files changed, 1203 insertions, 448 deletions
diff --git a/src/display/Makefile_insert b/src/display/Makefile_insert
index cf211108f..abbd89a68 100644
--- a/src/display/Makefile_insert
+++ b/src/display/Makefile_insert
@@ -47,7 +47,6 @@ ink_common_sources += \
display/guideline.h \
display/nr-3dutils.cpp \
display/nr-3dutils.h \
- display/nr-arena-forward.h \
display/nr-filter-blend.cpp \
display/nr-filter-blend.h \
display/nr-filter-colormatrix.cpp \
@@ -107,6 +106,8 @@ ink_common_sources += \
display/sodipodi-ctrlrect.h \
display/sp-canvas.cpp \
display/sp-canvas.h \
+ display/sp-canvas-item.h \
+ display/sp-canvas-group.h \
display/sp-canvas-util.cpp \
display/sp-canvas-util.h \
display/sp-ctrlcurve.cpp \
diff --git a/src/display/cairo-templates.h b/src/display/cairo-templates.h
index 45b6790e6..57ec98f81 100644
--- a/src/display/cairo-templates.h
+++ b/src/display/cairo-templates.h
@@ -66,9 +66,9 @@ void ink_cairo_surface_blend(cairo_surface_t *in1, cairo_surface_t *in2, cairo_s
int limit = w * h;
- guint32 *const in1_data = (guint32*) cairo_image_surface_get_data(in1);
- guint32 *const in2_data = (guint32*) cairo_image_surface_get_data(in2);
- guint32 *const out_data = (guint32*) cairo_image_surface_get_data(out);
+ guint32 *const in1_data = reinterpret_cast<guint32*>(cairo_image_surface_get_data(in1));
+ guint32 *const in2_data = reinterpret_cast<guint32*>(cairo_image_surface_get_data(in2));
+ guint32 *const out_data = reinterpret_cast<guint32*>(cairo_image_surface_get_data(out));
// NOTE
// OpenMP probably doesn't help much here.
@@ -199,8 +199,8 @@ void ink_cairo_surface_filter(cairo_surface_t *in, cairo_surface_t *out, Filter
fast_path &= (stridein == w * bppin);
fast_path &= (strideout == w * bppout);
- guint32 *const in_data = (guint32*) cairo_image_surface_get_data(in);
- guint32 *const out_data = (guint32*) cairo_image_surface_get_data(out);
+ guint32 *const in_data = reinterpret_cast<guint32*>(cairo_image_surface_get_data(in));
+ guint32 *const out_data = reinterpret_cast<guint32*>(cairo_image_surface_get_data(out));
#if HAVE_OPENMP
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
@@ -695,4 +695,4 @@ pxclamp(gint32 v, gint32 low, gint32 high) {
fill-column:99
End:
*/
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/display/cairo-utils.cpp b/src/display/cairo-utils.cpp
index 2e2eb42dd..fc56c7b26 100644
--- a/src/display/cairo-utils.cpp
+++ b/src/display/cairo-utils.cpp
@@ -24,7 +24,20 @@
#include <2geom/transforms.h>
#include <2geom/sbasis-to-bezier.h>
#include "color.h"
+#include "style.h"
#include "helper/geom-curves.h"
+#include "display/cairo-templates.h"
+
+namespace {
+
+/**
+ * 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
+ */
+cairo_user_data_key_t ci_key;
+
+} // namespace
namespace Inkscape {
@@ -276,6 +289,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 +445,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 +598,128 @@ void ink_cairo_surface_average_color_premul(cairo_surface_t *surface, double &r,
a = CLAMP(a, 0.0, 1.0);
}
+static guint32 srgb_to_linear( const guint32 c, const guint32 a ) {
+
+ const guint32 c1 = unpremul_alpha( c, a );
+
+ double cc = c1/255.0;
+
+ if( cc < 0.04045 ) {
+ cc /= 12.92;
+ } else {
+ cc = pow( (cc+0.055)/1.055, 2.4 );
+ }
+ cc *= 255.0;
+
+ const guint32 c2 = (int)cc;
+
+ return premul_alpha( c2, a );
+}
+
+static guint32 linear_to_srgb( const guint32 c, const guint32 a ) {
+
+ const guint32 c1 = unpremul_alpha( c, a );
+
+ double cc = c1/255.0;
+
+ if( cc < 0.0031308 ) {
+ cc *= 12.92;
+ } else {
+ cc = pow( cc, 1.0/2.4 )*1.055-0.055;
+ }
+ cc *= 255.0;
+
+ const guint32 c2 = (int)cc;
+
+ return premul_alpha( c2, a );
+}
+
+struct SurfaceSrgbToLinear {
+
+ guint32 operator()(guint32 in) {
+ EXTRACT_ARGB32(in, a,r,g,b) ; // Unneeded semi-colon for indenting
+ if( a != 0 ) {
+ r = srgb_to_linear( r, a );
+ g = srgb_to_linear( g, a );
+ b = srgb_to_linear( b, a );
+ }
+ ASSEMBLE_ARGB32(out, a,r,g,b);
+ return out;
+ }
+private:
+ /* None */
+};
+
+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);
+
+ ink_cairo_surface_filter( surface, surface, SurfaceSrgbToLinear() );
+
+ /* 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 ) {
+ // r = srgb_to_linear( r, a );
+ // g = srgb_to_linear( g, a );
+ // b = srgb_to_linear( b, a );
+ // }
+ // ASSEMBLE_ARGB32(px2, a,r,g,b);
+ // *reinterpret_cast<guint32*>(data + 4*x) = px2;
+ // }
+ // }
+ return width * height;
+}
+
+struct SurfaceLinearToSrgb {
+
+ guint32 operator()(guint32 in) {
+ EXTRACT_ARGB32(in, a,r,g,b) ; // Unneeded semi-colon for indenting
+ if( a != 0 ) {
+ r = linear_to_srgb( r, a );
+ g = linear_to_srgb( g, a );
+ b = linear_to_srgb( b, a );
+ }
+ ASSEMBLE_ARGB32(out, a,r,g,b);
+ return out;
+ }
+private:
+ /* None */
+};
+
+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);
+
+ ink_cairo_surface_filter( surface, surface, SurfaceLinearToSrgb() );
+
+ // /* 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 ) {
+ // r = linear_to_srgb( r, a );
+ // g = linear_to_srgb( g, a );
+ // b = 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()
{
@@ -715,4 +888,4 @@ guint32 argb32_from_rgba(guint32 in)
fill-column:99
End:
*/
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/display/cairo-utils.h b/src/display/cairo-utils.h
index e67872891..2596cd969 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,11 @@ public:
} // namespace Inkscape
+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 +108,10 @@ 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);
+double srgb_to_linear( const double c );
+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);
@@ -118,13 +128,13 @@ G_GNUC_CONST guint32 argb32_from_rgba(guint32 in);
G_GNUC_CONST inline guint32
-premul_alpha(guint32 color, guint32 alpha)
+premul_alpha(const guint32 color, const guint32 alpha)
{
- guint32 temp = alpha * color + 128;
+ const guint32 temp = alpha * color + 128;
return (temp + (temp >> 8)) >> 8;
}
G_GNUC_CONST inline guint32
-unpremul_alpha(guint32 color, guint32 alpha)
+unpremul_alpha(const guint32 color, const guint32 alpha)
{
// NOTE: you must check for alpha != 0 yourself.
return (255 * color + alpha/2) / alpha;
@@ -144,6 +154,15 @@ void feed_pathvector_to_cairo (cairo_t *ct, Geom::PathVector const &pathv);
#define ASSEMBLE_ARGB32(px,a,r,g,b) \
guint32 px = (a << 24) | (r << 16) | (g << 8) | b;
+inline double srgb_to_linear( const double c ) {
+ if( c < 0.04045 ) {
+ return c / 12.92;
+ } else {
+ return pow( (c+0.055)/1.055, 2.4 );
+ }
+}
+
+
namespace Inkscape {
namespace Display
diff --git a/src/display/canvas-arena.cpp b/src/display/canvas-arena.cpp
index f0fd63ef4..8e25c1843 100644
--- a/src/display/canvas-arena.cpp
+++ b/src/display/canvas-arena.cpp
@@ -316,6 +316,18 @@ sp_canvas_arena_event (SPCanvasItem *item, GdkEvent *event)
ret = sp_canvas_arena_send_event (arena, event);
break;
+ case GDK_SCROLL: {
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ bool wheelzooms = prefs->getBool("/options/wheelzooms/value");
+ bool ctrl = (event->scroll.state & GDK_CONTROL_MASK);
+ if ((ctrl && !wheelzooms) || (!ctrl && wheelzooms)) {
+ /* Zoom is emitted by the canvas as well, ignore here */
+ return FALSE;
+ }
+ ret = sp_canvas_arena_send_event (arena, event);
+ break;
+ }
+
default:
/* Just send event */
ret = sp_canvas_arena_send_event (arena, event);
diff --git a/src/display/canvas-axonomgrid.cpp b/src/display/canvas-axonomgrid.cpp
index d4e15f475..170684328 100644
--- a/src/display/canvas-axonomgrid.cpp
+++ b/src/display/canvas-axonomgrid.cpp
@@ -2,7 +2,7 @@
* Authors:
* Johan Engelen <j.b.c.engelen@alumnus.utwente.nl>
*
- * Copyright (C) 2006-2011 Authors
+ * Copyright (C) 2006-2012 Authors
* Released under GNU GPL, read the file 'COPYING' for more information
*/
@@ -13,46 +13,45 @@
* to the right). The x-axis will always have an angle between 0 and 90 degrees.
*/
- /*
- * TODO:
- * THIS FILE AND THE HEADER FILE NEED CLEANING UP. PLEASE DO NOT HESISTATE TO DO SO.
- */
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <gtkmm/box.h>
+#include <gtkmm/label.h>
+
+#if WITH_GTKMM_3_0
+# include <gtkmm/grid.h>
+#else
+# include <gtkmm/table.h>
+#endif
#include <glibmm/i18n.h>
-#include "ui/widget/registered-widget.h"
#include "display/canvas-axonomgrid.h"
-#include "2geom/line.h"
+
+#include "ui/widget/registered-widget.h"
#include "desktop.h"
-#include "canvas-grid.h"
#include "desktop-handles.h"
#include "display/cairo-utils.h"
#include "display/canvas-grid.h"
#include "display/sp-canvas-util.h"
+#include "display/sp-canvas.h"
#include "document.h"
-#include "helper/units.h"
#include "inkscape.h"
#include "preferences.h"
#include "sp-namedview.h"
#include "sp-object.h"
#include "svg/svg-color.h"
+#include "2geom/line.h"
+#include "2geom/angle.h"
#include "util/mathfns.h"
-#include "xml/node-event-vector.h"
#include "round.h"
-#include "display/sp-canvas.h"
+#include "helper/units.h"
-#include <gtkmm/box.h>
-#include <gtkmm/label.h>
-#include <gtkmm/table.h>
enum Dim3 { X=0, Y, Z };
-#ifndef M_PI
-# define M_PI 3.14159265358979323846
-#endif
-
-static double deg_to_rad(double deg) { return deg*M_PI/180.0;}
-
/**
* This function calls Cairo to render a line on a particular canvas buffer.
* Coordinates are interpreted as SCREENcoordinates
@@ -93,28 +92,60 @@ namespace Inkscape {
#define SPACE_SIZE_X 15
#define SPACE_SIZE_Y 10
static inline void
+#if WITH_GTKMM_3_0
+attach_all(Gtk::Grid &table, Gtk::Widget const *const arr[], unsigned size, int start = 0)
+#else
attach_all(Gtk::Table &table, Gtk::Widget const *const arr[], unsigned size, int start = 0)
+#endif
{
for (unsigned i=0, r=start; i<size/sizeof(Gtk::Widget*); i+=2) {
if (arr[i] && arr[i+1]) {
+#if WITH_GTKMM_3_0
+ (const_cast<Gtk::Widget&>(*arr[i])).set_hexpand();
+ (const_cast<Gtk::Widget&>(*arr[i])).set_valign(Gtk::ALIGN_CENTER);
+ table.attach(const_cast<Gtk::Widget&>(*arr[i]), 1, r, 1, 1);
+
+ (const_cast<Gtk::Widget&>(*arr[i+1])).set_hexpand();
+ (const_cast<Gtk::Widget&>(*arr[i+1])).set_valign(Gtk::ALIGN_CENTER);
+ table.attach(const_cast<Gtk::Widget&>(*arr[i+1]), 2, r, 1, 1);
+#else
table.attach (const_cast<Gtk::Widget&>(*arr[i]), 1, 2, r, r+1,
Gtk::FILL|Gtk::EXPAND, (Gtk::AttachOptions)0,0,0);
table.attach (const_cast<Gtk::Widget&>(*arr[i+1]), 2, 3, r, r+1,
Gtk::FILL|Gtk::EXPAND, (Gtk::AttachOptions)0,0,0);
+#endif
} else {
if (arr[i+1]) {
+#if WITH_GTKMM_3_0
+ (const_cast<Gtk::Widget&>(*arr[i+1])).set_hexpand();
+ (const_cast<Gtk::Widget&>(*arr[i+1])).set_valign(Gtk::ALIGN_CENTER);
+ table.attach(const_cast<Gtk::Widget&>(*arr[i+1]), 1, r, 2, 1);
+#else
table.attach (const_cast<Gtk::Widget&>(*arr[i+1]), 1, 3, r, r+1,
Gtk::FILL|Gtk::EXPAND, (Gtk::AttachOptions)0,0,0);
+#endif
} else if (arr[i]) {
Gtk::Label& label = reinterpret_cast<Gtk::Label&> (const_cast<Gtk::Widget&>(*arr[i]));
label.set_alignment (0.0);
+#if WITH_GTKMM_3_0
+ label.set_hexpand();
+ label.set_valign(Gtk::ALIGN_CENTER);
+ table.attach(label, 0, r, 3, 1);
+#else
table.attach (label, 0, 3, r, r+1,
Gtk::FILL|Gtk::EXPAND, (Gtk::AttachOptions)0,0,0);
+#endif
} else {
Gtk::HBox *space = manage (new Gtk::HBox);
space->set_size_request (SPACE_SIZE_X, SPACE_SIZE_Y);
+#if WITH_GTKMM_3_0
+ space->set_halign(Gtk::ALIGN_CENTER);
+ space->set_valign(Gtk::ALIGN_CENTER);
+ table.attach(*space, 0, r, 1, 1);
+#else
table.attach (*space, 0, 1, r, r+1,
(Gtk::AttachOptions)0, (Gtk::AttachOptions)0,0,0);
+#endif
}
}
++r;
@@ -138,9 +169,9 @@ CanvasAxonomGrid::CanvasAxonomGrid (SPNamedView * nv, Inkscape::XML::Node * in_r
angle_deg[Z] = prefs->getDouble("/options/grids/axonom/angle_z", 30.0);
angle_deg[Y] = 0;
- angle_rad[X] = deg_to_rad(angle_deg[X]);
+ angle_rad[X] = Geom::deg_to_rad(angle_deg[X]);
tan_angle[X] = tan(angle_rad[X]);
- angle_rad[Z] = deg_to_rad(angle_deg[Z]);
+ angle_rad[Z] = Geom::deg_to_rad(angle_deg[Z]);
tan_angle[Z] = tan(angle_rad[Z]);
snapper = new CanvasAxonomGridSnapper(this, &namedview->snap_manager, 0);
@@ -251,17 +282,17 @@ CanvasAxonomGrid::readRepr()
if ( (value = repr->attribute("gridanglex")) ) {
angle_deg[X] = g_ascii_strtod(value, NULL);
- if (angle_deg[X] < 1.0) angle_deg[X] = 1.0;
+ if (angle_deg[X] < 0.) angle_deg[X] = 0.;
if (angle_deg[X] > 89.0) angle_deg[X] = 89.0;
- angle_rad[X] = deg_to_rad(angle_deg[X]);
+ angle_rad[X] = Geom::deg_to_rad(angle_deg[X]);
tan_angle[X] = tan(angle_rad[X]);
}
if ( (value = repr->attribute("gridanglez")) ) {
angle_deg[Z] = g_ascii_strtod(value, NULL);
- if (angle_deg[Z] < 1.0) angle_deg[Z] = 1.0;
+ if (angle_deg[Z] < 0.) angle_deg[Z] = 0.;
if (angle_deg[Z] > 89.0) angle_deg[Z] = 89.0;
- angle_rad[Z] = deg_to_rad(angle_deg[Z]);
+ angle_rad[Z] = Geom::deg_to_rad(angle_deg[Z]);
tan_angle[Z] = tan(angle_rad[Z]);
}
@@ -316,14 +347,17 @@ CanvasAxonomGrid::onReprAttrChanged(Inkscape::XML::Node */*repr*/, gchar const *
updateWidgets();
}
-
-
-
Gtk::Widget *
CanvasAxonomGrid::newSpecificWidget()
{
+#if WITH_GTKMM_3_0
+ Gtk::Grid *table = Gtk::manage(new Gtk::Grid());
+ table->set_row_spacing(2);
+ table->set_column_spacing(2);
+#else
Gtk::Table * table = Gtk::manage( new Gtk::Table(1,1) );
table->set_spacings(2);
+#endif
_wr.setUpdating (true);
@@ -477,8 +511,8 @@ CanvasAxonomGrid::Update (Geom::Affine const &affine, unsigned int /*flags*/)
spacing_ylines = sw[Geom::X] /(tan_angle[X] + tan_angle[Z]);
lyw = sw[Geom::Y];
- lxw_x = sw[Geom::X] / tan_angle[X];
- lxw_z = sw[Geom::X] / tan_angle[Z];
+ lxw_x = Geom::are_near(tan_angle[X],0.) ? Geom::infinity() : sw[Geom::X] / tan_angle[X];
+ lxw_z = Geom::are_near(tan_angle[Z],0.) ? Geom::infinity() : sw[Geom::X] / tan_angle[Z];
if (empspacing == 0) {
scaled = true;
@@ -526,8 +560,12 @@ CanvasAxonomGrid::Render (SPCanvasBuf *buf)
for (gdouble y = xstart_y_sc; y < buf->rect.bottom(); y += lyw, xlinenum++) {
gint const x0 = buf->rect.left();
gint const y0 = round(y);
- gint const x1 = x0 + round( (buf->rect.bottom() - y) / tan_angle[X] );
- gint const y1 = buf->rect.bottom();
+ gint x1 = x0 + round( (buf->rect.bottom() - y) / tan_angle[X] );
+ gint y1 = buf->rect.bottom();
+ if ( Geom::are_near(tan_angle[X],0.) ) {
+ x1 = buf->rect.right();
+ y1 = y0;
+ }
if (!scaled && (xlinenum % empspacing) != 0) {
sp_caxonomgrid_drawline (buf, x0, y0, x1, y1, color);
@@ -536,18 +574,21 @@ CanvasAxonomGrid::Render (SPCanvasBuf *buf)
}
}
// lines starting from top side
- gdouble const xstart_x_sc = buf->rect.left() + (lxw_x - (xstart_y_sc - buf->rect.top()) / tan_angle[X]) ;
- xlinenum = xlinestart-1;
- for (gdouble x = xstart_x_sc; x < buf->rect.right(); x += lxw_x, xlinenum--) {
- gint const y0 = buf->rect.top();
- gint const y1 = buf->rect.bottom();
- gint const x0 = round(x);
- gint const x1 = x0 + round( (y1 - y0) / tan_angle[X] );
-
- if (!scaled && (xlinenum % empspacing) != 0) {
- sp_caxonomgrid_drawline (buf, x0, y0, x1, y1, color);
- } else {
- sp_caxonomgrid_drawline (buf, x0, y0, x1, y1, _empcolor);
+ if (!Geom::are_near(tan_angle[X],0.))
+ {
+ gdouble const xstart_x_sc = buf->rect.left() + (lxw_x - (xstart_y_sc - buf->rect.top()) / tan_angle[X]) ;
+ xlinenum = xlinestart-1;
+ for (gdouble x = xstart_x_sc; x < buf->rect.right(); x += lxw_x, xlinenum--) {
+ gint const y0 = buf->rect.top();
+ gint const y1 = buf->rect.bottom();
+ gint const x0 = round(x);
+ gint const x1 = x0 + round( (y1 - y0) / tan_angle[X] );
+
+ if (!scaled && (xlinenum % empspacing) != 0) {
+ sp_caxonomgrid_drawline (buf, x0, y0, x1, y1, color);
+ } else {
+ sp_caxonomgrid_drawline (buf, x0, y0, x1, y1, _empcolor);
+ }
}
}
@@ -575,8 +616,12 @@ CanvasAxonomGrid::Render (SPCanvasBuf *buf)
for (gdouble y = zstart_y_sc; y < buf->rect.bottom(); y += lyw, zlinenum++, next_y = y) {
gint const x0 = buf->rect.left();
gint const y0 = round(y);
- gint const x1 = x0 + round( (y - buf->rect.top() ) / tan_angle[Z] );
- gint const y1 = buf->rect.top();
+ gint x1 = x0 + round( (y - buf->rect.top() ) / tan_angle[Z] );
+ gint y1 = buf->rect.top();
+ if ( Geom::are_near(tan_angle[Z],0.) ) {
+ x1 = buf->rect.right();
+ y1 = y0;
+ }
if (!scaled && (zlinenum % empspacing) != 0) {
sp_caxonomgrid_drawline (buf, x0, y0, x1, y1, color);
@@ -585,17 +630,20 @@ CanvasAxonomGrid::Render (SPCanvasBuf *buf)
}
}
// draw lines from bottom-up
- gdouble const zstart_x_sc = buf->rect.left() + (next_y - buf->rect.bottom()) / tan_angle[Z] ;
- for (gdouble x = zstart_x_sc; x < buf->rect.right(); x += lxw_z, zlinenum++) {
- gint const y0 = buf->rect.bottom();
- gint const y1 = buf->rect.top();
- gint const x0 = round(x);
- gint const x1 = x0 + round(buf->rect.height() / tan_angle[Z] );
-
- if (!scaled && (zlinenum % empspacing) != 0) {
- sp_caxonomgrid_drawline (buf, x0, y0, x1, y1, color);
- } else {
- sp_caxonomgrid_drawline (buf, x0, y0, x1, y1, _empcolor);
+ if (!Geom::are_near(tan_angle[Z],0.))
+ {
+ gdouble const zstart_x_sc = buf->rect.left() + (next_y - buf->rect.bottom()) / tan_angle[Z] ;
+ for (gdouble x = zstart_x_sc; x < buf->rect.right(); x += lxw_z, zlinenum++) {
+ gint const y0 = buf->rect.bottom();
+ gint const y1 = buf->rect.top();
+ gint const x0 = round(x);
+ gint const x1 = x0 + round(buf->rect.height() / tan_angle[Z] );
+
+ if (!scaled && (zlinenum % empspacing) != 0) {
+ sp_caxonomgrid_drawline (buf, x0, y0, x1, y1, color);
+ } else {
+ sp_caxonomgrid_drawline (buf, x0, y0, x1, y1, _empcolor);
+ }
}
}
diff --git a/src/display/canvas-axonomgrid.h b/src/display/canvas-axonomgrid.h
index 04919f947..f58ea3aca 100644
--- a/src/display/canvas-axonomgrid.h
+++ b/src/display/canvas-axonomgrid.h
@@ -2,20 +2,23 @@
#define CANVAS_AXONOMGRID_H
/*
- * Copyright (C) 2006-2007 Johan Engelen <johan@shouraizou.nl>
+ * Authors:
+ * Johan Engelen <j.b.c.engelen@alumnus.utwente.nl>
*
- */
+ * Copyright (C) 2006-2012 Authors
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
#include "line-snapper.h"
#include "canvas-grid.h"
-class SPCanvasBuf;
+struct SPCanvasBuf;
class SPDesktop;
struct SPNamedView;
namespace Inkscape {
namespace XML {
- class Node;
+ class Node;
};
class CanvasAxonomGrid : public CanvasGrid {
@@ -36,6 +39,9 @@ public:
bool scaled; /**< Whether the grid is in scaled mode */
+protected:
+ friend class CanvasAxonomGridSnapper;
+
Geom::Point ow; /**< Transformed origin by the affine for the zoom */
double lyw; /**< Transformed length y by the affine for the zoom */
double lxw_x;
@@ -44,7 +50,6 @@ public:
Geom::Point sw; /**< the scaling factors of the affine transform */
-protected:
virtual Gtk::Widget * newSpecificWidget();
private:
@@ -63,7 +68,7 @@ public:
bool ThisSnapperMightSnap() const;
Geom::Coord getSnapperTolerance() const; //returns the tolerance of the snapper in screen pixels (i.e. independent of zoom)
- bool getSnapperAlwaysSnap() const; //if true, then the snapper will always snap, regardless of its tolerance
+ bool getSnapperAlwaysSnap() const; //if true, then the snapper will always snap, regardless of its tolerance
private:
LineList _getSnapLines(Geom::Point const &p) const;
diff --git a/src/display/canvas-bpath.h b/src/display/canvas-bpath.h
index f0520f012..72eca6eeb 100644
--- a/src/display/canvas-bpath.h
+++ b/src/display/canvas-bpath.h
@@ -22,7 +22,7 @@
struct SPCanvasBPath;
struct SPCanvasBPathClass;
struct SPCanvasGroup;
-struct SPCurve;
+class SPCurve;
#define SP_TYPE_CANVAS_BPATH (sp_canvas_bpath_get_type ())
#define SP_CANVAS_BPATH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_CANVAS_BPATH, SPCanvasBPath))
diff --git a/src/display/canvas-grid.cpp b/src/display/canvas-grid.cpp
index 498958f08..88da22835 100644
--- a/src/display/canvas-grid.cpp
+++ b/src/display/canvas-grid.cpp
@@ -13,6 +13,19 @@
* Don't be shy to correct things.
*/
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <gtkmm/box.h>
+#include <gtkmm/label.h>
+
+#if WITH_GTKMM_3_0
+# include <gtkmm/grid.h>
+#else
+# include <gtkmm/table.h>
+#endif
+
#include <glibmm/i18n.h>
#include "ui/widget/registered-widget.h"
@@ -37,10 +50,6 @@
#include "verbs.h"
#include "display/sp-canvas.h"
-#include <gtkmm/box.h>
-#include <gtkmm/label.h>
-#include <gtkmm/table.h>
-
using Inkscape::DocumentUndo;
namespace Inkscape {
@@ -184,19 +193,19 @@ CanvasGrid::~CanvasGrid()
}
const char *
-CanvasGrid::getName()
+CanvasGrid::getName() const
{
return _(grid_name[gridtype]);
}
const char *
-CanvasGrid::getSVGName()
+CanvasGrid::getSVGName() const
{
return grid_svgname[gridtype];
}
GridType
-CanvasGrid::getGridType()
+CanvasGrid::getGridType() const
{
return gridtype;
}
@@ -275,9 +284,9 @@ CanvasGrid::NewGrid(SPNamedView * nv, Inkscape::XML::Node * repr, SPDocument * d
switch (gridtype) {
case GRID_RECTANGULAR:
- return (CanvasGrid*) new CanvasXYGrid(nv, repr, doc);
+ return dynamic_cast<CanvasGrid*>(new CanvasXYGrid(nv, repr, doc));
case GRID_AXONOMETRIC:
- return (CanvasGrid*) new CanvasAxonomGrid(nv, repr, doc);
+ return dynamic_cast<CanvasGrid*>(new CanvasAxonomGrid(nv, repr, doc));
}
return NULL;
@@ -351,12 +360,13 @@ CanvasGrid::newWidget()
_rcb_enabled->setSlaveWidgets(slaves);
// set widget values
+ _wr.setUpdating (true);
_rcb_visible->setActive(visible);
if (snapper != NULL) {
_rcb_enabled->setActive(snapper->getEnabled());
_rcb_snap_visible_only->setActive(snapper->getSnapVisibleOnly());
}
-
+ _wr.setUpdating (false);
return dynamic_cast<Gtk::Widget *> (vbox);
}
@@ -366,10 +376,10 @@ CanvasGrid::on_repr_attr_changed(Inkscape::XML::Node *repr, gchar const *key, gc
if (!data)
return;
- ((CanvasGrid*) data)->onReprAttrChanged(repr, key, oldval, newval, is_interactive);
+ (static_cast<CanvasGrid*>(data))->onReprAttrChanged(repr, key, oldval, newval, is_interactive);
}
-bool CanvasGrid::isEnabled()
+bool CanvasGrid::isEnabled() const
{
if (snapper == NULL) {
return false;
@@ -410,29 +420,60 @@ void CanvasGrid::setOrigin(Geom::Point const &origin_px)
**/
#define SPACE_SIZE_X 15
#define SPACE_SIZE_Y 10
-static inline void
-attach_all(Gtk::Table &table, Gtk::Widget const *const arr[], unsigned size, int start = 0)
+#if WITH_GTKMM_3_0
+static inline void attach_all(Gtk::Grid &table, Gtk::Widget const *const arr[], unsigned size, int start = 0)
+#else
+static inline void attach_all(Gtk::Table &table, Gtk::Widget const *const arr[], unsigned size, int start = 0)
+#endif
{
for (unsigned i=0, r=start; i<size/sizeof(Gtk::Widget*); i+=2) {
if (arr[i] && arr[i+1]) {
+#if WITH_GTKMM_3_0
+ (const_cast<Gtk::Widget&>(*arr[i])).set_hexpand();
+ (const_cast<Gtk::Widget&>(*arr[i])).set_valign(Gtk::ALIGN_CENTER);
+ table.attach(const_cast<Gtk::Widget&>(*arr[i]), 1, r, 1, 1);
+
+ (const_cast<Gtk::Widget&>(*arr[i+1])).set_hexpand();
+ (const_cast<Gtk::Widget&>(*arr[i+1])).set_valign(Gtk::ALIGN_CENTER);
+ table.attach(const_cast<Gtk::Widget&>(*arr[i+1]), 2, r, 1, 1);
+#else
table.attach (const_cast<Gtk::Widget&>(*arr[i]), 1, 2, r, r+1,
Gtk::FILL|Gtk::EXPAND, (Gtk::AttachOptions)0,0,0);
table.attach (const_cast<Gtk::Widget&>(*arr[i+1]), 2, 3, r, r+1,
Gtk::FILL|Gtk::EXPAND, (Gtk::AttachOptions)0,0,0);
+#endif
} else {
if (arr[i+1]) {
+#if WITH_GTKMM_3_0
+ (const_cast<Gtk::Widget&>(*arr[i+1])).set_hexpand();
+ (const_cast<Gtk::Widget&>(*arr[i+1])).set_valign(Gtk::ALIGN_CENTER);
+ table.attach(const_cast<Gtk::Widget&>(*arr[i+1]), 1, r, 2, 1);
+#else
table.attach (const_cast<Gtk::Widget&>(*arr[i+1]), 1, 3, r, r+1,
Gtk::FILL|Gtk::EXPAND, (Gtk::AttachOptions)0,0,0);
+#endif
} else if (arr[i]) {
Gtk::Label& label = reinterpret_cast<Gtk::Label&> (const_cast<Gtk::Widget&>(*arr[i]));
label.set_alignment (0.0);
+#if WITH_GTKMM_3_0
+ label.set_hexpand();
+ label.set_valign(Gtk::ALIGN_CENTER);
+ table.attach(label, 0, r, 3, 1);
+#else
table.attach (label, 0, 3, r, r+1,
Gtk::FILL|Gtk::EXPAND, (Gtk::AttachOptions)0,0,0);
+#endif
} else {
Gtk::HBox *space = manage (new Gtk::HBox);
space->set_size_request (SPACE_SIZE_X, SPACE_SIZE_Y);
+#if WITH_GTKMM_3_0
+ space->set_halign(Gtk::ALIGN_CENTER);
+ space->set_valign(Gtk::ALIGN_CENTER);
+ table.attach(*space, 0, r, 1, 1);
+#else
table.attach (*space, 0, 1, r, r+1,
(Gtk::AttachOptions)0, (Gtk::AttachOptions)0,0,0);
+#endif
}
}
++r;
@@ -688,7 +729,14 @@ CanvasXYGrid::onReprAttrChanged(Inkscape::XML::Node */*repr*/, gchar const */*ke
Gtk::Widget *
CanvasXYGrid::newSpecificWidget()
{
+#if WITH_GTKMM_3_0
+ Gtk::Grid * table = Gtk::manage( new Gtk::Grid() );
+ table->set_row_spacing(2);
+ table->set_column_spacing(2);
+#else
Gtk::Table * table = Gtk::manage( new Gtk::Table(1,1) );
+ table->set_spacings(2);
+#endif
Inkscape::UI::Widget::RegisteredUnitMenu *_rumg = Gtk::manage( new Inkscape::UI::Widget::RegisteredUnitMenu(
_("Grid _units:"), "units", _wr, repr, doc) );
@@ -715,9 +763,7 @@ CanvasXYGrid::newSpecificWidget()
Inkscape::UI::Widget::RegisteredSuffixedInteger *_rsi = Gtk::manage( new Inkscape::UI::Widget::RegisteredSuffixedInteger(
_("_Major grid line every:"), "", _("lines"), "empspacing", _wr, repr, doc) );
- table->set_spacings(2);
-
-_wr.setUpdating (true);
+ _wr.setUpdating (true);
_rsu_ox->setDigits(5);
_rsu_ox->setIncrements(0.1, 1.0);
@@ -735,7 +781,6 @@ _wr.setUpdating (true);
new Inkscape::UI::Widget::RegisteredCheckButton( _("_Show dots instead of lines"),
_("If set, displays dots at gridpoints instead of gridlines"),
"dotted", _wr, false, repr, doc) );
-_wr.setUpdating (false);
Gtk::Widget const *const widget_array[] = {
0, _rumg,
@@ -775,10 +820,12 @@ _wr.setUpdating (false);
_rcb_dotted->setActive(render_dotted);
+ _wr.setUpdating (false);
+
_rsu_ox->setProgrammatically = false;
_rsu_oy->setProgrammatically = false;
_rsu_sx->setProgrammatically = false;
- _rsu_sx->setProgrammatically = false;
+ _rsu_sy->setProgrammatically = false;
return table;
}
diff --git a/src/display/canvas-grid.h b/src/display/canvas-grid.h
index bba9b7e95..7eaef407f 100644
--- a/src/display/canvas-grid.h
+++ b/src/display/canvas-grid.h
@@ -61,9 +61,9 @@ public:
virtual ~CanvasGrid();
// TODO: see effect.h and effect.cpp from live_effects how to link enums to SVGname to typename properly. (johan)
- const char * getName();
- const char * getSVGName();
- GridType getGridType();
+ const char * getName() const;
+ const char * getSVGName() const;
+ GridType getGridType() const;
static const char * getName(GridType type);
static const char * getSVGName(GridType type);
static GridType getGridTypeFromSVGName(const char * typestr);
@@ -97,8 +97,8 @@ public:
static void on_repr_attr_changed (Inkscape::XML::Node * repr, const gchar *key, const gchar *oldval, const gchar *newval, bool is_interactive, void * data);
- bool isVisible() { return (isEnabled() &&visible); };
- bool isEnabled();
+ bool isVisible() const { return (isEnabled() &&visible); };
+ bool isEnabled() const;
protected:
CanvasGrid(SPNamedView * nv, Inkscape::XML::Node * in_repr, SPDocument *in_doc, GridType type);
diff --git a/src/display/canvas-text.cpp b/src/display/canvas-text.cpp
index ddc946d5d..fe60d9c65 100644
--- a/src/display/canvas-text.cpp
+++ b/src/display/canvas-text.cpp
@@ -58,9 +58,9 @@ sp_canvastext_get_type (void)
static void sp_canvastext_class_init(SPCanvasTextClass *klass)
{
- SPCanvasItemClass *item_class = (SPCanvasItemClass *) klass;
+ SPCanvasItemClass *item_class = SP_CANVAS_ITEM_CLASS(klass);
- parent_class_ct = (SPCanvasItemClass*)g_type_class_peek_parent (klass);
+ parent_class_ct = SP_CANVAS_ITEM_CLASS(g_type_class_peek_parent(klass));
item_class->destroy = sp_canvastext_destroy;
item_class->update = sp_canvastext_update;
diff --git a/src/display/curve.cpp b/src/display/curve.cpp
index 1a788b59a..ae243853e 100644
--- a/src/display/curve.cpp
+++ b/src/display/curve.cpp
@@ -150,7 +150,7 @@ SPCurve::concat(GSList const *list)
SPCurve *new_curve = new SPCurve();
for (GSList const *l = list; l != NULL; l = l->next) {
- SPCurve *c = (SPCurve *) l->data;
+ SPCurve *c = static_cast<SPCurve *>(l->data);
new_curve->_pathv.insert( new_curve->_pathv.end(), c->get_pathvector().begin(), c->get_pathvector().end() );
}
diff --git a/src/display/drawing-context.h b/src/display/drawing-context.h
index fb6662202..b8c4667c2 100644
--- a/src/display/drawing-context.h
+++ b/src/display/drawing-context.h
@@ -101,6 +101,8 @@ public:
cairo_t *raw() { return _ct; }
cairo_surface_t *rawTarget() { return cairo_get_group_target(_ct); }
+ DrawingSurface *surface() { return _surface; } // Needed to find scale in drawing-item.cpp
+
private:
DrawingContext(cairo_t *ct, DrawingSurface *surface, bool destroy);
diff --git a/src/display/drawing-group.h b/src/display/drawing-group.h
index 974b3c977..775fec8c4 100644
--- a/src/display/drawing-group.h
+++ b/src/display/drawing-group.h
@@ -14,7 +14,7 @@
#include "display/drawing-item.h"
-class SPStyle;
+struct SPStyle;
namespace Inkscape {
diff --git a/src/display/drawing-image.cpp b/src/display/drawing-image.cpp
index 0c8ac9681..3f1a86ee7 100644
--- a/src/display/drawing-image.cpp
+++ b/src/display/drawing-image.cpp
@@ -23,6 +23,7 @@ DrawingImage::DrawingImage(Drawing &drawing)
, _pixbuf(NULL)
, _surface(NULL)
, _style(NULL)
+ , _new_surface(NULL)
{}
DrawingImage::~DrawingImage()
@@ -30,6 +31,7 @@ DrawingImage::~DrawingImage()
if (_style)
sp_style_unref(_style);
if (_pixbuf) {
+ if (_new_surface) cairo_surface_destroy(_new_surface);
cairo_surface_destroy(_surface);
g_object_unref(_pixbuf);
}
@@ -118,26 +120,126 @@ unsigned DrawingImage::_renderItem(DrawingContext &ct, Geom::IntRect const &/*ar
if (!outline) {
if (!_pixbuf) return RENDER_OK;
-
+
Inkscape::DrawingContext::Save save(ct);
ct.transform(_ctm);
ct.newPath();
ct.rectangle(_clipbox);
ct.clip();
- ct.translate(_origin);
- ct.scale(_scale);
- ct.setSource(_surface, 0, 0);
+ /////////////////////////////////////////////////////////////////////////////
+ // BEGIN: Hack to avoid Cairo bug
+ // The total transform (which is RIGHT-multiplied with the item points to get display points) equals:
+ // scale*translate_origin*_ctm = scale*translate(origin)*expansion*expansionInv*_ctm
+ // = scale*expansion*translate(origin*expansion)*expansionInv*_ctm
+ // To avoid a Cairo bug, we handle the scale*expansion part ourselves.
+ // See https://bugs.launchpad.net/inkscape/+bug/804162
+
+ Geom::Scale expansion(_ctm.expansion());
+ int orgwidth = cairo_image_surface_get_width(_surface);
+ int orgheight = cairo_image_surface_get_height(_surface);
+
+ if (_scale[Geom::X]*expansion[Geom::X]*orgwidth*255.0<1.0 || _scale[Geom::Y]*expansion[Geom::Y]*orgheight*255.0<1.0) {
+ // Resized image too small to actually see anything
+ return RENDER_OK;
+ }
+
+ // Split scale*expansion in a part that is <= 1.0 and a part that is >= 1.0. We only take care of the part <= 1.0.
+ Geom::Scale scaleExpansionSmall(std::min<Geom::Coord>(fabs(_scale[Geom::X]*expansion[Geom::X]),1),std::min<Geom::Coord>(fabs(_scale[Geom::Y]*expansion[Geom::Y]),1));
+ Geom::Scale scaleExpansionLarge(_scale[Geom::X]*expansion[Geom::X]/scaleExpansionSmall[Geom::X],_scale[Geom::Y]*expansion[Geom::Y]/scaleExpansionSmall[Geom::Y]);
+
+ Geom::Point newSize(Geom::Point(orgwidth,orgheight)*scaleExpansionSmall);
+ if ((newSize-Geom::Point(orgwidth,orgheight)).length()<0.1) {
+ // Just use _surface directly.
+ ct.scale(expansion.inverse()); // This should not include scale (see derivation above)
+ ct.translate(_origin*expansion);
+ ct.scale(scaleExpansionLarge);
+ ct.setSource(_surface, 0, 0);
+ } else if (!_new_surface || (newSize-_rescaledSize).length()>0.1) {
+ // Rescaled image is sufficiently different from cached image to recompute
+ if (_new_surface) cairo_surface_destroy(_new_surface);
+ _rescaledSize = newSize;
+
+ // This essentially considers an image to be composed of rectangular pixels (box kernel) and computes the least-squares approximation of the original.
+ // When the scale factor is really large or small this essentially results in using a box filter, while for scale factors approaching 1 it is more like a "tent" kernel.
+ // Although the quality of the result is not great, it is typically better than an ordinary box filter, and it is guaranteed to preserve the overall brightness of the image.
+ // The best improvement would probably be to do the same kind of thing based on a tent kernel, but that's quite a bit more complicated, and probably not worth the trouble for a hack like this.
+ int newwidth = static_cast<int>(floor(orgwidth*scaleExpansionSmall[Geom::X])+1);
+ int newheight = static_cast<int>(floor(orgheight*scaleExpansionSmall[Geom::Y])+1);
+ std::vector<int> xBegin(newwidth, -1), yBegin(newheight, -1);
+ std::vector< std::vector<float> > xCoefs(xBegin.size()), yCoefs(yBegin.size());
+ for(int x=0; x<orgwidth; x++) {
+ double coordBegin = x*static_cast<double>(scaleExpansionSmall[Geom::X]); // x-coord in target coordinates where the current source pixel begins
+ double coordEnd = (x+1)*static_cast<double>(scaleExpansionSmall[Geom::X]); // x-coord in target coordinates where the current source pixel ends
+ int begin = static_cast<int>(floor(coordBegin)); // First pixel (x-coord) affected by the current source pixel
+ int end = static_cast<int>(ceil(coordEnd)); // First pixel (x-coord) NOT affected by the current source pixel (a zero contribution is counted as not affecting the pixel)
+ for(int nx=begin; nx<end; nx++) {
+ // Set xBegin if this is the first source pixel contributing to the target pixel.
+ if (xBegin[nx]==-1) xBegin[nx] = x;
+ // This computes the fraction of the current target pixel (at nx) that is covered by the source pixel (at x).
+ xCoefs[nx].push_back(static_cast<float>(std::min<double>(nx+1,coordEnd) - std::max<double>(nx,coordBegin)));
+ }
+ }
+ for(int y=0; y<orgheight; y++) {
+ double coordBegin = y*static_cast<double>(scaleExpansionSmall[Geom::Y]); // y-coord in target coordinates where the current source pixel begins
+ double coordEnd = (y+1)*static_cast<double>(scaleExpansionSmall[Geom::Y]); // y-coord in target coordinates where the current source pixel ends
+ int begin = static_cast<int>(floor(coordBegin)); // First pixel (y-coord) affected by the current source pixel
+ int end = static_cast<int>(ceil(coordEnd)); // First pixel (y-coord) NOT affected by the current source pixel (a zero contribution is counted as not affecting the pixel)
+ for(int ny=begin; ny<end; ny++) {
+ // Set yBegin if this is the first source pixel contributing to the target pixel.
+ if (yBegin[ny]==-1) yBegin[ny] = y;
+ // This computes the fraction of the current target pixel (at ny) that is covered by the source pixel (at y).
+ yCoefs[ny].push_back(static_cast<float>(std::min<double>(ny+1,coordEnd) - std::max<double>(ny,coordBegin)));
+ }
+ }
+
+ _new_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, newwidth,newheight);
+ unsigned char * orgdata = cairo_image_surface_get_data(_surface);
+ unsigned char * newdata = cairo_image_surface_get_data(_new_surface);
+ int orgstride = cairo_image_surface_get_stride(_surface);
+ int newstride = cairo_image_surface_get_stride(_new_surface);
+
+ cairo_surface_flush(_surface);
+ cairo_surface_flush(_new_surface);
+
+ for(int y=0; y<newheight; y++) {
+ for(int x=0; x<newwidth; x++) {
+ float tempSum[4] = {0,0,0,0};
+ for(int oy=0; oy<static_cast<int>(yCoefs[y].size()); oy++) {
+ for(int ox=0; ox<static_cast<int>(xCoefs[x].size()); ox++) {
+ for(int c=0; c<4; c++) {
+ tempSum[c] += xCoefs[x][ox]*yCoefs[y][oy]*orgdata[c+4*(xBegin[x]+ox)+orgstride*(yBegin[y]+oy)];
+ }
+ }
+ }
+ for(int c=0; c<4; c++) {
+ newdata[c+4*x+newstride*y] = static_cast<unsigned char>(tempSum[c]);
+ }
+ }
+ }
+
+ cairo_surface_mark_dirty(_new_surface);
+
+ ct.scale(expansion.inverse()); // This should not include scale (see derivation above)
+ ct.translate(_origin*expansion);
+ ct.scale(scaleExpansionLarge);
+ ct.setSource(_new_surface, 0, 0);
+ } else {
+ // No need to regenerate, but we do draw from _new_surface.
+ ct.scale(expansion.inverse()); // This should not include scale (see derivation above)
+ ct.translate(_origin*expansion);
+ ct.scale(scaleExpansionLarge);
+ ct.setSource(_new_surface, 0, 0);
+ }
+
+ // END: Hack to avoid Cairo bug
+ /////////////////////////////////////////////////////////////////////////////
- cairo_matrix_t tt;
- Geom::Affine total;
- cairo_get_matrix(ct.raw(), &tt);
- ink_matrix_to_2geom(total, tt);
+ // TODO: If Cairo's problems are gone, uncomment the following:
+ //ct.translate(_origin);
+ //ct.scale(_scale);
+ //ct.setSource(_surface, 0, 0);
- if (total.expansionX() > 1.0 || total.expansionY() > 1.0) {
- cairo_pattern_t *p = cairo_get_source(ct.raw());
- cairo_pattern_set_filter(p, CAIRO_FILTER_NEAREST);
- }
//ct.paint(_opacity);
ct.paint();
diff --git a/src/display/drawing-image.h b/src/display/drawing-image.h
index 306096d0e..593185c97 100644
--- a/src/display/drawing-image.h
+++ b/src/display/drawing-image.h
@@ -45,6 +45,9 @@ protected:
cairo_surface_t *_surface;
SPStyle *_style;
+ cairo_surface_t *_new_surface; // Part of hack around Cairo bug
+ Geom::Point _rescaledSize; // Part of hack around Cairo bug
+
// TODO: the following three should probably be merged into a new Geom::Viewbox object
Geom::Rect _clipbox; ///< for preserveAspectRatio
Geom::Point _origin;
diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp
index 0fb1f0018..80664d822 100644
--- a/src/display/drawing-item.cpp
+++ b/src/display/drawing-item.cpp
@@ -550,10 +550,12 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag
// for overlapping clip children. To fix this we use the SOURCE operator
// instead of the default OVER.
ict.setOperator(CAIRO_OPERATOR_SOURCE);
+ ict.paint();
if (_clip) {
+ ict.pushGroup();
_clip->clip(ict, *carea); // fixme: carea or area?
- } else {
- // if there is no clipping path, fill the entire surface with alpha = opacity.
+ ict.popGroupToSource();
+ ict.setOperator(CAIRO_OPERATOR_IN);
ict.paint();
}
ict.setOperator(CAIRO_OPERATOR_OVER); // reset back to default
@@ -667,29 +669,24 @@ DrawingItem::clip(Inkscape::DrawingContext &ct, Geom::IntRect const &area)
if (!_visible) return;
if (!area.intersects(_bbox)) return;
- // The item used as the clipping path itself has a clipping path.
- // Render this item's clipping path onto a temporary surface, then composite it
- // with the item using the IN operator
- if (_clip) {
- ct.pushAlphaGroup();
- { Inkscape::DrawingContext::Save save(ct);
- ct.setSource(0,0,0,1);
- _clip->clip(ct, area);
- }
- ct.pushAlphaGroup();
- }
-
+ ct.setSource(0,0,0,1);
+ ct.pushGroup();
// rasterize the clipping path
_clipItem(ct, area);
-
if (_clip) {
+ // The item used as the clipping path itself has a clipping path.
+ // Render this item's clipping path onto a temporary surface, then composite it
+ // with the item using the IN operator
+ ct.pushGroup();
+ _clip->clip(ct, area);
ct.popGroupToSource();
ct.setOperator(CAIRO_OPERATOR_IN);
ct.paint();
- ct.popGroupToSource();
- ct.setOperator(CAIRO_OPERATOR_SOURCE);
- ct.paint();
}
+ ct.popGroupToSource();
+ ct.setOperator(CAIRO_OPERATOR_OVER);
+ ct.paint();
+ ct.setSource(0,0,0,0);
}
/**
diff --git a/src/display/drawing-item.h b/src/display/drawing-item.h
index 810a61d9d..4a516512b 100644
--- a/src/display/drawing-item.h
+++ b/src/display/drawing-item.h
@@ -20,7 +20,7 @@
#include <2geom/rect.h>
#include <2geom/affine.h>
-class SPStyle;
+struct SPStyle;
namespace Inkscape {
diff --git a/src/display/drawing-shape.cpp b/src/display/drawing-shape.cpp
index 4ca306092..e80f12486 100644
--- a/src/display/drawing-shape.cpp
+++ b/src/display/drawing-shape.cpp
@@ -167,7 +167,7 @@ DrawingShape::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigne
{ Inkscape::DrawingContext::Save save(ct);
ct.setSource(rgba);
ct.setLineWidth(0.5);
- ct.setTolerance(1.25);
+ ct.setTolerance(0.5);
ct.stroke();
}
} else {
diff --git a/src/display/drawing-shape.h b/src/display/drawing-shape.h
index ce9bed2eb..52496d86e 100644
--- a/src/display/drawing-shape.h
+++ b/src/display/drawing-shape.h
@@ -15,7 +15,7 @@
#include "display/drawing-item.h"
#include "display/nr-style.h"
-class SPStyle;
+struct SPStyle;
class SPCurve;
namespace Inkscape {
diff --git a/src/display/drawing-text.cpp b/src/display/drawing-text.cpp
index 7f63c555a..2a6505c67 100644
--- a/src/display/drawing-text.cpp
+++ b/src/display/drawing-text.cpp
@@ -162,7 +162,7 @@ unsigned DrawingText::_renderItem(DrawingContext &ct, Geom::IntRect const &/*are
guint32 rgba = _drawing.outlinecolor;
Inkscape::DrawingContext::Save save(ct);
ct.setSource(rgba);
- ct.setTolerance(1.25); // low quality, but good enough for outline mode
+ ct.setTolerance(0.5); // low quality, but good enough for outline mode
for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) {
DrawingGlyphs *g = dynamic_cast<DrawingGlyphs *>(&*i);
diff --git a/src/display/drawing-text.h b/src/display/drawing-text.h
index 929d2bf2d..79b1b097c 100644
--- a/src/display/drawing-text.h
+++ b/src/display/drawing-text.h
@@ -15,7 +15,7 @@
#include "display/drawing-group.h"
#include "display/nr-style.h"
-class SPStyle;
+struct SPStyle;
class font_instance;
namespace Inkscape {
diff --git a/src/display/drawing.cpp b/src/display/drawing.cpp
index 77f24caf3..c192e4565 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,8 +15,21 @@
#include "nr-filter-gaussian.h"
#include "nr-filter-types.h"
+//grayscale colormode:
+#include "cairo-templates.h"
+#include "drawing-context.h"
+
+
namespace Inkscape {
+// hardcoded grayscale color matrix values as default
+static const gdouble grayscale_value_matrix[20] = {
+ 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
+};
+
Drawing::Drawing(SPCanvasArena *arena)
: _root(NULL)
, outlinecolor(0x000000ff)
@@ -27,6 +41,7 @@ Drawing::Drawing(SPCanvasArena *arena)
, _filter_quality(Filters::FILTER_QUALITY_BEST)
, _cache_score_threshold(50000.0)
, _cache_budget(0)
+ , _grayscale_colormatrix(std::vector<gdouble> (grayscale_value_matrix, grayscale_value_matrix + 20 ))
, _canvasarena(arena)
{
@@ -136,6 +151,12 @@ Drawing::setCacheBudget(size_t bytes)
}
void
+Drawing::setGrayscaleMatrix(gdouble value_matrix[20]) {
+ _grayscale_colormatrix = Filters::FilterColorMatrix::ColorMatrixMatrix(
+ std::vector<gdouble> (value_matrix, value_matrix + 20) );
+}
+
+void
Drawing::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset)
{
if (_root) {
@@ -151,6 +172,20 @@ 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/drawing.h b/src/display/drawing.h
index 8154f0783..74ab57fae 100644
--- a/src/display/drawing.h
+++ b/src/display/drawing.h
@@ -20,7 +20,7 @@
#include <2geom/rect.h>
#include "display/drawing-item.h"
#include "display/rendermode.h"
-
+#include "nr-filter-colormatrix.h"
typedef struct _SPCanvasArena SPCanvasArena;
@@ -65,6 +65,8 @@ public:
OutlineColors const &colors() const { return _colors; }
+ void setGrayscaleMatrix(gdouble value_matrix[20]);
+
void update(Geom::IntRect const &area = Geom::IntRect::infinite(), UpdateContext const &ctx = UpdateContext(), unsigned flags = DrawingItem::STATE_ALL, unsigned reset = 0);
void render(DrawingContext &ct, Geom::IntRect const &area, unsigned flags = 0);
DrawingItem *pick(Geom::Point const &p, double delta, unsigned flags);
@@ -97,6 +99,7 @@ private:
size_t _cache_budget; ///< maximum allowed size of cache
OutlineColors _colors;
+ Filters::FilterColorMatrix::ColorMatrixMatrix _grayscale_colormatrix;
SPCanvasArena *_canvasarena; // may be NULL is this arena is not the screen
// but used for export etc.
diff --git a/src/display/guideline.cpp b/src/display/guideline.cpp
index d3385978a..f71bc82ef 100644
--- a/src/display/guideline.cpp
+++ b/src/display/guideline.cpp
@@ -66,9 +66,9 @@ GType sp_guideline_get_type()
static void sp_guideline_class_init(SPGuideLineClass *c)
{
- parent_class = (SPCanvasItemClass*) g_type_class_peek_parent(c);
+ parent_class = SP_CANVAS_ITEM_CLASS(g_type_class_peek_parent(c));
- SPCanvasItemClass *item_class = (SPCanvasItemClass *) c;
+ SPCanvasItemClass *item_class = SP_CANVAS_ITEM_CLASS(c);
item_class->destroy = sp_guideline_destroy;
item_class->update = sp_guideline_update;
item_class->render = sp_guideline_render;
@@ -191,8 +191,8 @@ static void sp_guideline_update(SPCanvasItem *item, Geom::Affine const &affine,
{
SPGuideLine *gl = SP_GUIDELINE(item);
- if (((SPCanvasItemClass *) parent_class)->update) {
- ((SPCanvasItemClass *) parent_class)->update(item, affine, flags);
+ if ((SP_CANVAS_ITEM_CLASS(parent_class))->update) {
+ (SP_CANVAS_ITEM_CLASS(parent_class))->update(item, affine, flags);
}
gl->affine = affine;
diff --git a/src/display/guideline.h b/src/display/guideline.h
index 164244c46..2d9a87d9b 100644
--- a/src/display/guideline.h
+++ b/src/display/guideline.h
@@ -21,7 +21,7 @@
#define SP_GUIDELINE(o) (G_TYPE_CHECK_INSTANCE_CAST((o), SP_TYPE_GUIDELINE, SPGuideLine))
#define SP_IS_GUIDELINE(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), SP_TYPE_GUIDELINE))
-class SPCtrlPoint;
+struct SPCtrlPoint;
struct SPGuideLine {
SPCanvasItem item;
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 b25ecdf2c..f6decad0d 100644
--- a/src/display/nr-filter-composite.cpp
+++ b/src/display/nr-filter-composite.cpp
@@ -48,10 +48,11 @@ struct ComposeArithmetic {
gint32 go = _k1*ga*gb + _k2*ga + _k3*gb + _k4;
gint32 bo = _k1*ba*bb + _k2*ba + _k3*bb + _k4;
- ao = (pxclamp(ao, 0, 255*255*255) + (255*255/2)) / (255*255);
- ro = (pxclamp(ro, 0, 255*255*255) + (255*255/2)) / (255*255);
- go = (pxclamp(go, 0, 255*255*255) + (255*255/2)) / (255*255);
- bo = (pxclamp(bo, 0, 255*255*255) + (255*255/2)) / (255*255);
+ ao = pxclamp(ao, 0, 255*255*255); // r, g and b are premultiplied, so should be clamped to the alpha channel
+ ro = (pxclamp(ro, 0, ao) + (255*255/2)) / (255*255);
+ go = (pxclamp(go, 0, ao) + (255*255/2)) / (255*255);
+ bo = (pxclamp(bo, 0, ao) + (255*255/2)) / (255*255);
+ ao = (ao + (255*255/2)) / (255*255);
ASSEMBLE_ARGB32(pxout, ao, ro, go, bo)
return pxout;
@@ -65,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..c6724e3ba 100644
--- a/src/display/nr-filter-diffuselighting.cpp
+++ b/src/display/nr-filter-diffuselighting.cpp
@@ -21,6 +21,8 @@
#include "display/nr-filter-units.h"
#include "display/nr-filter-utils.h"
#include "display/nr-light.h"
+#include "svg/svg-icc-color.h"
+#include "svg/svg-color.h"
namespace Inkscape {
namespace Filters {
@@ -126,6 +128,38 @@ 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);
+ double r = SP_RGBA32_R_F(lighting_color);
+ double g = SP_RGBA32_G_F(lighting_color);
+ double b = SP_RGBA32_B_F(lighting_color);
+
+#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
+
+ if (icc) {
+ guchar ru, gu, bu;
+ icc_color_to_sRGB(icc, &ru, &gu, &bu);
+ r = SP_COLOR_U_TO_F(ru);
+ g = SP_COLOR_U_TO_F(gu);
+ b = SP_COLOR_U_TO_F(bu);
+ }
+#endif
+
+ // 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;
+
+ // Lighting color is always defined in terms of sRGB, preconvert to linearRGB
+ // if color_interpolation_filters set to linearRGB (for efficiency assuming
+ // next filter primitive has same value of cif).
+ if( ci_fp == SP_CSS_COLOR_INTERPOLATION_LINEARRGB ) {
+ r = srgb_to_linear( r );
+ g = srgb_to_linear( g );
+ b = srgb_to_linear( b );
+ }
+ }
+ set_cairo_surface_ci(out, ci_fp );
+ guint32 color = SP_RGBA32_F_COMPOSE( r, g, b, 1.0 );
+
Geom::Rect slot_area = slot.get_slot_area();
Geom::Point p = slot_area.min();
Geom::Affine trans = slot.get_units().get_matrix_primitiveunits2pb();
@@ -135,15 +169,15 @@ void FilterDiffuseLighting::render_cairo(FilterSlot &slot)
switch (light_type) {
case DISTANT_LIGHT:
ink_cairo_surface_synthesize(out,
- DiffuseDistantLight(input, light.distant, lighting_color, scale, diffuseConstant));
+ DiffuseDistantLight(input, light.distant, color, scale, diffuseConstant));
break;
case POINT_LIGHT:
ink_cairo_surface_synthesize(out,
- DiffusePointLight(input, light.point, lighting_color, trans, scale, diffuseConstant, x0, y0));
+ DiffusePointLight(input, light.point, color, trans, scale, diffuseConstant, x0, y0));
break;
case SPOT_LIGHT:
ink_cairo_surface_synthesize(out,
- DiffuseSpotLight(input, light.spot, lighting_color, trans, scale, diffuseConstant, x0, y0));
+ DiffuseSpotLight(input, light.spot, color, trans, scale, diffuseConstant, x0, y0));
break;
default: {
cairo_t *ct = cairo_create(out);
@@ -158,6 +192,10 @@ void FilterDiffuseLighting::render_cairo(FilterSlot &slot)
cairo_surface_destroy(out);
}
+void FilterDiffuseLighting::set_icc(SVGICCColor *icc_color) {
+ icc = icc_color;
+}
+
void FilterDiffuseLighting::area_enlarge(Geom::IntRect &area, Geom::Affine const & /*trans*/)
{
// TODO: support kernelUnitLength
diff --git a/src/display/nr-filter-diffuselighting.h b/src/display/nr-filter-diffuselighting.h
index 0da6cc218..15cc8e1ff 100644
--- a/src/display/nr-filter-diffuselighting.h
+++ b/src/display/nr-filter-diffuselighting.h
@@ -19,9 +19,10 @@
#include "display/nr-filter-slot.h"
#include "display/nr-filter-units.h"
-class SPFeDistantLight;
-class SPFePointLight;
-class SPFeSpotLight;
+struct SPFeDistantLight;
+struct SPFePointLight;
+struct SPFeSpotLight;
+struct SVGICCColor;
namespace Inkscape {
namespace Filters {
@@ -32,6 +33,7 @@ public:
static FilterPrimitive *create();
virtual ~FilterDiffuseLighting();
virtual void render_cairo(FilterSlot &slot);
+ virtual void set_icc(SVGICCColor *icc_color);
virtual void area_enlarge(Geom::IntRect &area, Geom::Affine const &trans);
virtual double complexity(Geom::Affine const &ctm);
@@ -46,6 +48,7 @@ public:
guint32 lighting_color;
private:
+ SVGICCColor *icc;
};
} /* namespace Filters */
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 449255133..d1fe3e13f 100644
--- a/src/display/nr-filter-flood.cpp
+++ b/src/display/nr-filter-flood.cpp
@@ -55,11 +55,49 @@ void FilterFlood::render_cairo(FilterSlot &slot)
#endif
cairo_surface_t *out = ink_cairo_surface_create_same_size(input, CAIRO_CONTENT_COLOR_ALPHA);
- cairo_t *ct = cairo_create(out);
- cairo_set_source_rgba(ct, r, g, b, a);
- cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE);
- cairo_paint(ct);
- cairo_destroy(ct);
+
+ SPColorInterpolation ci_fp = SP_CSS_COLOR_INTERPOLATION_AUTO;
+ if( _style ) {
+ ci_fp = (SPColorInterpolation)_style->color_interpolation_filters.computed;
+
+ // Flood color is always defined in terms of sRGB, preconvert to linearRGB
+ // if color_interpolation_filters set to linearRGB (for efficiency assuming
+ // next filter primitive has same value of cif).
+ if( ci_fp == SP_CSS_COLOR_INTERPOLATION_LINEARRGB ) {
+ r = srgb_to_linear( r );
+ g = srgb_to_linear( g );
+ b = srgb_to_linear( b );
+ }
+ }
+ set_cairo_surface_ci(out, ci_fp );
+
+ // Get filter primitive area in user units
+ Geom::Rect fp = filter_primitive_area( slot.get_units() );
+
+ // Convert to Cairo units
+ Geom::Rect fp_cairo = fp * slot.get_units().get_matrix_user2pb();
+
+ // Get area in slot (tile to fill)
+ Geom::Rect sa = slot.get_slot_area();
+
+ // Get overlap
+ Geom::OptRect optoverlap = intersect( fp_cairo, sa );
+ if( optoverlap ) {
+
+ Geom::Rect overlap = *optoverlap;
+
+ double dx = fp_cairo.min()[Geom::X] - sa.min()[Geom::X];
+ double dy = fp_cairo.min()[Geom::Y] - sa.min()[Geom::Y];
+ if( dx < 0.0 ) dx = 0.0;
+ if( dy < 0.0 ) dy = 0.0;
+
+ cairo_t *ct = cairo_create(out);
+ cairo_set_source_rgba(ct, r, g, b, a);
+ cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE);
+ cairo_rectangle(ct, dx, dy, overlap.width(), overlap.height() );
+ cairo_fill(ct);
+ cairo_destroy(ct);
+ }
slot.set(_output, out);
cairo_surface_destroy(out);
diff --git a/src/display/nr-filter-flood.h b/src/display/nr-filter-flood.h
index 8568502ff..9a968047d 100644
--- a/src/display/nr-filter-flood.h
+++ b/src/display/nr-filter-flood.h
@@ -14,7 +14,7 @@
#include "display/nr-filter-primitive.h"
-class SVGICCColor;
+struct SVGICCColor;
namespace Inkscape {
namespace Filters {
diff --git a/src/display/nr-filter-gaussian.cpp b/src/display/nr-filter-gaussian.cpp
index 06c2d2718..9d7c32585 100644
--- a/src/display/nr-filter-gaussian.cpp
+++ b/src/display/nr-filter-gaussian.cpp
@@ -102,15 +102,16 @@ static inline Tt clip_round_cast(Ts const v) {
Ts const minval = std::numeric_limits<Tt>::min();
Ts const maxval = std::numeric_limits<Tt>::max();
Tt const minval_rounded = std::numeric_limits<Tt>::min();
- Ts const maxval_rounded = std::numeric_limits<Tt>::max();
+ Tt const maxval_rounded = std::numeric_limits<Tt>::max();
if ( v < minval ) return minval_rounded;
if ( v > maxval ) return maxval_rounded;
return round_cast<Tt>(v);
}
template<typename Tt, typename Ts>
-static inline Tt clip_round_cast_varmax(Ts const v, Ts const maxval, Tt const maxval_rounded) {
+static inline Tt clip_round_cast_varmax(Ts const v, Tt const maxval_rounded) {
Ts const minval = std::numeric_limits<Tt>::min();
+ Tt const maxval = maxval_rounded;
Tt const minval_rounded = std::numeric_limits<Tt>::min();
if ( v < minval ) return minval_rounded;
if ( v > maxval ) return maxval_rounded;
@@ -145,6 +146,7 @@ static void
_make_kernel(FIRValue *const kernel, double const deviation)
{
int const scr_len = _effect_area_scr(deviation);
+ g_assert(scr_len >= 0);
double const d_sq = sqr(deviation) * 2;
double k[scr_len+1]; // This is only called for small kernel sizes (above approximately 10 coefficients the IIR filter is used)
@@ -338,7 +340,7 @@ filter2D_IIR(PT *const dest, int const dstr1, int const dstr2,
dstimg -= dstr1;
if ( PREMULTIPLIED_ALPHA ) {
dstimg[alpha_PC] = clip_round_cast<PT>(v[0][alpha_PC]);
- PREMUL_ALPHA_LOOP dstimg[c] = clip_round_cast_varmax<PT>(v[0][c], v[0][alpha_PC], dstimg[alpha_PC]);
+ PREMUL_ALPHA_LOOP dstimg[c] = clip_round_cast_varmax<PT>(v[0][c], dstimg[alpha_PC]);
} else {
for(unsigned int c=0; c<PC; c++) dstimg[c] = clip_round_cast<PT>(v[0][c]);
}
@@ -353,7 +355,7 @@ filter2D_IIR(PT *const dest, int const dstr1, int const dstr2,
dstimg -= dstr1;
if ( PREMULTIPLIED_ALPHA ) {
dstimg[alpha_PC] = clip_round_cast<PT>(v[0][alpha_PC]);
- PREMUL_ALPHA_LOOP dstimg[c] = clip_round_cast_varmax<PT>(v[0][c], v[0][alpha_PC], dstimg[alpha_PC]);
+ PREMUL_ALPHA_LOOP dstimg[c] = clip_round_cast_varmax<PT>(v[0][c], dstimg[alpha_PC]);
} else {
for(unsigned int c=0; c<PC; c++) dstimg[c] = clip_round_cast<PT>(v[0][c]);
}
@@ -551,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);
@@ -658,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 a9a5ec3e0..7a27d857e 100644
--- a/src/display/nr-filter-image.cpp
+++ b/src/display/nr-filter-image.cpp
@@ -10,6 +10,7 @@
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
+#include "display/nr-filter-image.h"
#include "document.h"
#include "sp-item.h"
#include "display/cairo-utils.h"
@@ -17,9 +18,9 @@
#include "display/drawing.h"
#include "display/drawing-item.h"
#include "display/nr-filter.h"
-#include "display/nr-filter-image.h"
#include "display/nr-filter-slot.h"
#include "display/nr-filter-units.h"
+#include "enums.h"
#include <glibmm/fileutils.h>
namespace Inkscape {
@@ -50,22 +51,31 @@ void FilterImage::render_cairo(FilterSlot &slot)
//cairo_surface_t *input = slot.getcairo(_input);
+ // Viewport is filter primitive area (in user coordinates).
+ // Note: viewport calculation in non-trivial. Do not rely
+ // on get_matrix_primitiveunits2pb().
+ Geom::Rect vp = filter_primitive_area( slot.get_units() );
+ double feImageX = vp.min()[Geom::X];
+ double feImageY = vp.min()[Geom::Y];
+ double feImageWidth = vp.width();
+ double feImageHeight = vp.height();
+
+ // feImage is suppose to use the same parameters as a normal SVG image.
+ // If a width or height is set to zero, the image is not suppose to be displayed.
+ // This does not seem to be what Firefox or Opera does, nor does the W3C displacement
+ // filter test expect this behavior. If the width and/or height are zero, we use
+ // the width and height of the object bounding box.
Geom::Affine m = slot.get_units().get_matrix_user2filterunits().inverse();
Geom::Point bbox_00 = Geom::Point(0,0) * m;
Geom::Point bbox_w0 = Geom::Point(1,0) * m;
Geom::Point bbox_0h = Geom::Point(0,1) * m;
double bbox_width = Geom::distance(bbox_00, bbox_w0);
double bbox_height = Geom::distance(bbox_00, bbox_0h);
-
- // feImage is suppose to use the same parameters as a normal SVG image.
- // If a width or height is set to zero, the image is not suppose to be displayed.
- // This does not seem to be what Firefox or Opera does, nor does the W3C displacement
- // filter test expect this behavior. If the width and/or height are zero, we use
- // the width and height of the object bounding box.
if( feImageWidth == 0 ) feImageWidth = bbox_width;
if( feImageHeight == 0 ) feImageHeight = bbox_height;
+ // Internal image, like <use>
if (from_element) {
if (!SVGElem) return;
@@ -87,18 +97,20 @@ void FilterImage::render_cairo(FilterSlot &slot)
drawing.setRoot(ai);
Geom::Rect area = *optarea;
- Geom::Affine pu2pb = slot.get_units().get_matrix_primitiveunits2pb();
+ Geom::Affine user2pb = slot.get_units().get_matrix_user2pb();
+ /* FIXME: These variables are currently unused. Why were they calculated?
double scaleX = feImageWidth / area.width();
double scaleY = feImageHeight / area.height();
+ */
Geom::Rect sa = slot.get_slot_area();
cairo_surface_t *out = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
sa.width(), sa.height());
Inkscape::DrawingContext ct(out, sa.min());
- ct.transform(pu2pb); // we are now in primitive units
+ ct.transform(user2pb); // we are now in primitive units
ct.translate(feImageX, feImageY);
- ct.scale(scaleX, scaleY);
+// ct.scale(scaleX, scaleY); No scaling should be done
Geom::IntRect render_rect = area.roundOutwards();
ct.translate(render_rect.min());
@@ -108,11 +120,15 @@ 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;
}
+ // External image, like <image>
if (!image && !broken_ref) {
broken_ref = true;
try {
@@ -158,9 +174,9 @@ void FilterImage::render_cairo(FilterSlot &slot)
}
// Native size of image
- //width = image->get_width();
- //height = image->get_height();
- //rowstride = image->get_rowstride();
+ // width = image->get_width();
+ // height = image->get_height();
+ // rowstride = image->get_rowstride();
convert_pixbuf_normal_to_argb32(image->gobj());
@@ -172,13 +188,99 @@ 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]);
- // now ct is in pb coordinates
- ink_cairo_transform(ct, slot.get_units().get_matrix_primitiveunits2pb());
+
+ // now ct is in pb coordinates, note the feWidth etc. are in user units
+ ink_cairo_transform(ct, slot.get_units().get_matrix_user2pb());
+
// now ct is in the coordinates of feImageX etc.
- // TODO: add preserveAspectRatio support here
+ // Now that we have the viewport, we must map image inside.
+ // Partially copied from sp-image.cpp.
+
+ // Do nothing if preserveAspectRatio is "none".
+ if( aspect_align != SP_ASPECT_NONE ) {
+
+ // Check aspect ratio of image vs. viewport
+ double feAspect = feImageHeight/feImageWidth;
+ double aspect = (double)image->get_height()/(double)image->get_width();
+ bool ratio = (feAspect < aspect);
+
+ double ax, ay; // Align side
+ switch( aspect_align ) {
+ case SP_ASPECT_XMIN_YMIN:
+ ax = 0.0;
+ ay = 0.0;
+ break;
+ case SP_ASPECT_XMID_YMIN:
+ ax = 0.5;
+ ay = 0.0;
+ break;
+ case SP_ASPECT_XMAX_YMIN:
+ ax = 1.0;
+ ay = 0.0;
+ break;
+ case SP_ASPECT_XMIN_YMID:
+ ax = 0.0;
+ ay = 0.5;
+ break;
+ case SP_ASPECT_XMID_YMID:
+ ax = 0.5;
+ ay = 0.5;
+ break;
+ case SP_ASPECT_XMAX_YMID:
+ ax = 1.0;
+ ay = 0.5;
+ break;
+ case SP_ASPECT_XMIN_YMAX:
+ ax = 0.0;
+ ay = 1.0;
+ break;
+ case SP_ASPECT_XMID_YMAX:
+ ax = 0.5;
+ ay = 1.0;
+ break;
+ case SP_ASPECT_XMAX_YMAX:
+ ax = 1.0;
+ ay = 1.0;
+ break;
+ default:
+ ax = 0.0;
+ ay = 0.0;
+ break;
+ }
+
+ if( aspect_clip == SP_ASPECT_SLICE ) {
+ // image clipped by viewbox
+
+ if( ratio ) {
+ // clip top/bottom
+ feImageY -= ay * (feImageWidth * aspect - feImageHeight);
+ feImageHeight = feImageWidth * aspect;
+ } else {
+ // clip sides
+ feImageX -= ax * (feImageHeight / aspect - feImageWidth);
+ feImageWidth = feImageHeight / aspect;
+ }
+
+ } else {
+ // image fits into viewbox
+
+ if( ratio ) {
+ // fit to height
+ feImageX += ax * (feImageWidth - feImageHeight / aspect );
+ feImageWidth = feImageHeight / aspect;
+ } else {
+ // fit to width
+ feImageY += ay * (feImageHeight - feImageWidth * aspect);
+ feImageHeight = feImageWidth * aspect;
+ }
+ }
+ }
double scaleX = feImageWidth / image->get_width();
double scaleY = feImageHeight / image->get_height();
@@ -204,6 +306,7 @@ double FilterImage::complexity(Geom::Affine const &)
}
void FilterImage::set_href(const gchar *href){
+
if (feImageHref) g_free (feImageHref);
feImageHref = (href) ? g_strdup (href) : NULL;
@@ -218,13 +321,6 @@ void FilterImage::set_document(SPDocument *doc){
document = doc;
}
-void FilterImage::set_region(SVGLength x, SVGLength y, SVGLength width, SVGLength height) {
- feImageX=x.computed;
- feImageY=y.computed;
- feImageWidth=width.computed;
- feImageHeight=height.computed;
-}
-
void FilterImage::set_align( unsigned int align ) {
aspect_align = align;
}
diff --git a/src/display/nr-filter-image.h b/src/display/nr-filter-image.h
index c0b9d6e81..05b7d65a8 100644
--- a/src/display/nr-filter-image.h
+++ b/src/display/nr-filter-image.h
@@ -35,7 +35,6 @@ public:
void set_document( SPDocument *document );
void set_href(const gchar *href);
- void set_region(SVGLength x, SVGLength y, SVGLength width, SVGLength height);
void set_align( unsigned int align );
void set_clip( unsigned int clip );
bool from_element;
diff --git a/src/display/nr-filter-merge.cpp b/src/display/nr-filter-merge.cpp
index f1fbd7d33..2b9a24f25 100644
--- a/src/display/nr-filter-merge.cpp
+++ b/src/display/nr-filter-merge.cpp
@@ -31,7 +31,12 @@ FilterMerge::~FilterMerge()
void FilterMerge::render_cairo(FilterSlot &slot)
{
- if (_input_image.size() == 0) return;
+ 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;
@@ -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 c6bd8a74e..fca82c810 100644
--- a/src/display/nr-filter-primitive.cpp
+++ b/src/display/nr-filter-primitive.cpp
@@ -15,6 +15,13 @@
#include "display/nr-filter-types.h"
#include "svg/svg-length.h"
+#include "inkscape.h"
+#include "desktop.h"
+#include "desktop-handles.h"
+#include "document.h"
+#include "sp-root.h"
+#include "style.h"
+
namespace Inkscape {
namespace Filters {
@@ -39,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)
@@ -103,6 +113,18 @@ Geom::Rect FilterPrimitive::filter_primitive_area(FilterUnits const &units)
Geom::OptRect bb = units.get_item_bbox();
Geom::OptRect fa = units.get_filter_area();
+ // This is definitely a hack... but what else to do?
+ // Current viewport might not be document viewport... but how to find?
+ SPDocument* document = inkscape_active_document();
+ SPRoot* root = document->getRoot();
+ Geom::Rect viewport;
+ if( root->viewBox_set ) {
+ viewport = root->viewBox;
+ } else {
+ // Pick some random values
+ viewport = Geom::Rect::from_xywh(0,0,480,360);
+ }
+
/* Update computed values for ex, em, %. For %, assumes primitive unit is objectBoundingBox. */
/* TODO: fetch somehow the object ex and em lengths; 12, 6 are just dummy values. */
double len_x = bb->width();
@@ -144,11 +166,11 @@ Geom::Rect FilterPrimitive::filter_primitive_area(FilterUnits const &units)
if( _subregion_y._set && _subregion_y.unit != SVGLength::PERCENT ) y = _subregion_y.computed;
if( _subregion_width._set && _subregion_width.unit != SVGLength::PERCENT ) width = _subregion_width.computed;
if( _subregion_height._set && _subregion_height.unit != SVGLength::PERCENT ) height = _subregion_height.computed;
- // TODO: add percent of viewport TEMPORARY HACK FOR TESTING...
- if( _subregion_x._set && _subregion_x.unit == SVGLength::PERCENT ) x = _subregion_x.value * 480; // viewport_x
- if( _subregion_y._set && _subregion_y.unit == SVGLength::PERCENT ) y = _subregion_y.value * 360;
- if( _subregion_width._set && _subregion_width.unit == SVGLength::PERCENT ) width = _subregion_width.value * 480;
- if( _subregion_height._set && _subregion_height.unit == SVGLength::PERCENT ) height = _subregion_height.value * 360;
+ // Percent of viewport
+ if( _subregion_x._set && _subregion_x.unit == SVGLength::PERCENT ) x = _subregion_x.value * viewport.width();
+ if( _subregion_y._set && _subregion_y.unit == SVGLength::PERCENT ) y = _subregion_y.value * viewport.height();
+ if( _subregion_width._set && _subregion_width.unit == SVGLength::PERCENT ) width = _subregion_width.value * viewport.width();
+ if( _subregion_height._set && _subregion_height.unit == SVGLength::PERCENT ) height = _subregion_height.value * viewport.height();
}
Geom::Point minp, maxp;
@@ -161,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..94bd6abb0 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"
+struct 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-skeleton.cpp b/src/display/nr-filter-skeleton.cpp
index 0c455a818..86ab8141e 100644
--- a/src/display/nr-filter-skeleton.cpp
+++ b/src/display/nr-filter-skeleton.cpp
@@ -42,7 +42,8 @@ FilterSkeleton::~FilterSkeleton()
void FilterSkeleton::render_cairo(FilterSlot &slot) {
cairo_surface_t *in = slot.getcairo(_input);
cairo_surface_t *out = ink_cairo_surface_create_identical(in);
- cairo_t *ct = cairo_create(out);
+
+// cairo_t *ct = cairo_create(out);
// cairo_set_source_surface(ct, in, offset[X], offset[Y]);
// cairo_paint(ct);
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..2ce02adee 100644
--- a/src/display/nr-filter-specularlighting.cpp
+++ b/src/display/nr-filter-specularlighting.cpp
@@ -21,6 +21,8 @@
#include "display/nr-filter-units.h"
#include "display/nr-filter-utils.h"
#include "display/nr-light.h"
+#include "svg/svg-icc-color.h"
+#include "svg/svg-color.h"
namespace Inkscape {
namespace Filters {
@@ -139,6 +141,38 @@ 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);
+ double r = SP_RGBA32_R_F(lighting_color);
+ double g = SP_RGBA32_G_F(lighting_color);
+ double b = SP_RGBA32_B_F(lighting_color);
+
+#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
+
+ if (icc) {
+ guchar ru, gu, bu;
+ icc_color_to_sRGB(icc, &ru, &gu, &bu);
+ r = SP_COLOR_U_TO_F(ru);
+ g = SP_COLOR_U_TO_F(gu);
+ b = SP_COLOR_U_TO_F(bu);
+ }
+#endif
+
+ // 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;
+
+ // Lighting color is always defined in terms of sRGB, preconvert to linearRGB
+ // if color_interpolation_filters set to linearRGB (for efficiency assuming
+ // next filter primitive has same value of cif).
+ if( ci_fp == SP_CSS_COLOR_INTERPOLATION_LINEARRGB ) {
+ r = srgb_to_linear( r );
+ g = srgb_to_linear( g );
+ b = srgb_to_linear( b );
+ }
+ }
+ set_cairo_surface_ci(out, ci_fp );
+ guint32 color = SP_RGBA32_F_COMPOSE( r, g, b, 1.0 );
+
Geom::Affine trans = slot.get_units().get_matrix_primitiveunits2pb();
Geom::Point p = slot.get_slot_area().min();
double x0 = p[Geom::X];
@@ -150,15 +184,15 @@ void FilterSpecularLighting::render_cairo(FilterSlot &slot)
switch (light_type) {
case DISTANT_LIGHT:
ink_cairo_surface_synthesize(out,
- SpecularDistantLight(input, light.distant, lighting_color, scale, ks, se));
+ SpecularDistantLight(input, light.distant, color, scale, ks, se));
break;
case POINT_LIGHT:
ink_cairo_surface_synthesize(out,
- SpecularPointLight(input, light.point, lighting_color, trans, scale, ks, se, x0, y0));
+ SpecularPointLight(input, light.point, color, trans, scale, ks, se, x0, y0));
break;
case SPOT_LIGHT:
ink_cairo_surface_synthesize(out,
- SpecularSpotLight(input, light.spot, lighting_color, trans, scale, ks, se, x0, y0));
+ SpecularSpotLight(input, light.spot, color, trans, scale, ks, se, x0, y0));
break;
default: {
cairo_t *ct = cairo_create(out);
@@ -173,6 +207,10 @@ void FilterSpecularLighting::render_cairo(FilterSlot &slot)
cairo_surface_destroy(out);
}
+void FilterSpecularLighting::set_icc(SVGICCColor *icc_color) {
+ icc = icc_color;
+}
+
void FilterSpecularLighting::area_enlarge(Geom::IntRect &area, Geom::Affine const & /*trans*/)
{
// TODO: support kernelUnitLength
diff --git a/src/display/nr-filter-specularlighting.h b/src/display/nr-filter-specularlighting.h
index 33ea17a87..0d1c0644f 100644
--- a/src/display/nr-filter-specularlighting.h
+++ b/src/display/nr-filter-specularlighting.h
@@ -17,9 +17,10 @@
#include "display/nr-light-types.h"
#include "display/nr-filter-primitive.h"
-class SPFeDistantLight;
-class SPFePointLight;
-class SPFeSpotLight;
+struct SPFeDistantLight;
+struct SPFePointLight;
+struct SPFeSpotLight;
+struct SVGICCColor;
namespace Inkscape {
namespace Filters {
@@ -33,6 +34,7 @@ public:
virtual ~FilterSpecularLighting();
virtual void render_cairo(FilterSlot &slot);
+ virtual void set_icc(SVGICCColor *icc_color);
virtual void area_enlarge(Geom::IntRect &area, Geom::Affine const &trans);
virtual double complexity(Geom::Affine const &ctm);
@@ -48,6 +50,7 @@ public:
guint32 lighting_color;
private:
+ SVGICCColor *icc;
};
} /* namespace Filters */
diff --git a/src/display/nr-filter-turbulence.cpp b/src/display/nr-filter-turbulence.cpp
index bce532f21..333074f55 100644
--- a/src/display/nr-filter-turbulence.cpp
+++ b/src/display/nr-filter-turbulence.cpp
@@ -283,7 +283,12 @@ private:
// other constants
static int const BSize = 0x100;
static int const BMask = 0xff;
+
+#if __cplusplus < 201103L
static double const PerlinOffset = 4096.0;
+#else
+ static double constexpr PerlinOffset = 4096.0;
+#endif
Geom::Rect _tile;
Geom::Point _baseFreq;
@@ -375,6 +380,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-style.cpp b/src/display/nr-style.cpp
index 86102f9e8..ba2340074 100644
--- a/src/display/nr-style.cpp
+++ b/src/display/nr-style.cpp
@@ -60,7 +60,9 @@ NRStyle::~NRStyle()
{
if (fill_pattern) cairo_pattern_destroy(fill_pattern);
if (stroke_pattern) cairo_pattern_destroy(stroke_pattern);
- if (dash) delete dash;
+ if (dash){
+ delete [] dash;
+ }
}
void NRStyle::set(SPStyle *style)
@@ -126,7 +128,9 @@ void NRStyle::set(SPStyle *style)
}
miter_limit = style->stroke_miterlimit.value;
- if (dash) delete [] dash;
+ if (dash){
+ delete [] dash;
+ }
n_dash = style->stroke_dash.n_dash;
if (n_dash != 0) {
diff --git a/src/display/nr-style.h b/src/display/nr-style.h
index ce154cec0..80547c43e 100644
--- a/src/display/nr-style.h
+++ b/src/display/nr-style.h
@@ -16,9 +16,9 @@
#include <2geom/rect.h>
#include "color.h"
-class SPColor;
-class SPPaintServer;
-class SPStyle;
+struct SPPaintServer;
+struct SPStyle;
+
namespace Inkscape {
class DrawingContext;
}
diff --git a/src/display/nr-svgfonts.cpp b/src/display/nr-svgfonts.cpp
index e095fb9a9..84b4bd080 100644
--- a/src/display/nr-svgfonts.cpp
+++ b/src/display/nr-svgfonts.cpp
@@ -1,5 +1,4 @@
#include "config.h"
-#ifdef ENABLE_SVG_FONTS
/*
* SVGFonts rendering implementation
*
@@ -16,7 +15,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"
@@ -43,10 +42,9 @@
static cairo_user_data_key_t key;
static cairo_status_t font_init_cb (cairo_scaled_font_t *scaled_font,
- cairo_t */*cairo*/, cairo_font_extents_t *metrics){
- cairo_font_face_t* face;
- face = cairo_scaled_font_get_font_face(scaled_font);
- SvgFont* instance = (SvgFont*) cairo_font_face_get_user_data(face, &key);
+ cairo_t * /*cairo*/, cairo_font_extents_t *metrics){
+ cairo_font_face_t* face = cairo_scaled_font_get_font_face(scaled_font);
+ SvgFont* instance = static_cast<SvgFont*>(cairo_font_face_get_user_data(face, &key));
return instance->scaled_font_init(scaled_font, metrics);
}
@@ -58,9 +56,8 @@ static cairo_status_t font_text_to_glyphs_cb ( cairo_scaled_font_t *scaled_font
cairo_text_cluster_t **clusters,
int *num_clusters,
cairo_text_cluster_flags_t *flags){
- cairo_font_face_t* face;
- face = cairo_scaled_font_get_font_face(scaled_font);
- SvgFont* instance = (SvgFont*) cairo_font_face_get_user_data(face, &key);
+ cairo_font_face_t* face = cairo_scaled_font_get_font_face(scaled_font);
+ SvgFont* instance = static_cast<SvgFont*>(cairo_font_face_get_user_data(face, &key));
return instance->scaled_font_text_to_glyphs(scaled_font, utf8, utf8_len, glyphs, num_glyphs, clusters, num_clusters, flags);
}
@@ -68,9 +65,8 @@ static cairo_status_t font_render_glyph_cb (cairo_scaled_font_t *scaled_font,
unsigned long glyph,
cairo_t *cr,
cairo_text_extents_t *metrics){
- cairo_font_face_t* face;
- face = cairo_scaled_font_get_font_face(scaled_font);
- SvgFont* instance = (SvgFont*) cairo_font_face_get_user_data(face, &key);
+ cairo_font_face_t* face = cairo_scaled_font_get_font_face(scaled_font);
+ SvgFont* instance = static_cast<SvgFont*>(cairo_font_face_get_user_data(face, &key));
return instance->scaled_font_render_glyph(scaled_font, glyph, cr, metrics);
}
@@ -116,15 +112,15 @@ unsigned int size_of_substring(const char* substring, gchar* str){
}
//TODO: in these macros, verify what happens when using unicode strings.
-#define Match_VKerning_Rule (((SPVkern*)node)->u1->contains(previous_unicode[0])\
- || ((SPVkern*)node)->g1->contains(previous_glyph_name)) &&\
- (((SPVkern*)node)->u2->contains(this->glyphs[i]->unicode[0])\
- || ((SPVkern*)node)->g2->contains(this->glyphs[i]->glyph_name.c_str()))
+#define Match_VKerning_Rule ((SP_VKERN(node))->u1->contains(previous_unicode[0])\
+ || (SP_VKERN(node))->g1->contains(previous_glyph_name)) &&\
+ ((SP_VKERN(node))->u2->contains(this->glyphs[i]->unicode[0])\
+ || (SP_VKERN(node))->g2->contains(this->glyphs[i]->glyph_name.c_str()))
-#define Match_HKerning_Rule (((SPHkern*)node)->u1->contains(previous_unicode[0])\
- || ((SPHkern*)node)->g1->contains(previous_glyph_name)) &&\
- (((SPHkern*)node)->u2->contains(this->glyphs[i]->unicode[0])\
- || ((SPHkern*)node)->g2->contains(this->glyphs[i]->glyph_name.c_str()))
+#define Match_HKerning_Rule ((SP_HKERN(node))->u1->contains(previous_unicode[0])\
+ || (SP_HKERN(node))->g1->contains(previous_glyph_name)) &&\
+ ((SP_HKERN(node))->u2->contains(this->glyphs[i]->unicode[0])\
+ || (SP_HKERN(node))->g2->contains(this->glyphs[i]->glyph_name.c_str()))
cairo_status_t
SvgFont::scaled_font_text_to_glyphs (cairo_scaled_font_t */*scaled_font*/,
@@ -187,14 +183,14 @@ SvgFont::scaled_font_text_to_glyphs (cairo_scaled_font_t */*scaled_font*/,
for(SPObject* node = this->font->children;previous_unicode && node;node=node->next){
//apply glyph kerning if appropriate
if (SP_IS_HKERN(node) && is_horizontal_text && Match_HKerning_Rule ){
- x -= (((SPHkern*)node)->k / 1000.0);//TODO: use here the height of the font
+ x -= ((SP_HKERN(node))->k / 1000.0);//TODO: use here the height of the font
}
if (SP_IS_VKERN(node) && !is_horizontal_text && Match_VKerning_Rule ){
- y -= (((SPVkern*)node)->k / 1000.0);//TODO: use here the "height" of the font
+ y -= ((SP_VKERN(node))->k / 1000.0);//TODO: use here the "height" of the font
}
}
- previous_unicode = (char*) this->glyphs[i]->unicode.c_str();//used for kerning checking
- previous_glyph_name = (char*) this->glyphs[i]->glyph_name.c_str();//used for kerning checking
+ previous_unicode = const_cast<char*>(this->glyphs[i]->unicode.c_str());//used for kerning checking
+ previous_glyph_name = const_cast<char*>(this->glyphs[i]->glyph_name.c_str());//used for kerning checking
(*glyphs)[count].index = i;
(*glyphs)[count].x = x;
(*glyphs)[count++].y = y;
@@ -251,7 +247,7 @@ Geom::PathVector
SvgFont::flip_coordinate_system(SPFont* spfont, Geom::PathVector pathv){
double units_per_em = 1000;
SPObject* obj;
- for (obj = ((SPObject*) spfont)->children; obj; obj=obj->next){
+ for (obj = (SP_OBJECT(spfont))->children; obj; obj=obj->next){
if (SP_IS_FONTFACE(obj)){
//XML Tree being directly used here while it shouldn't be.
sp_repr_get_double(obj->getRepr(), "units_per_em", &units_per_em);
@@ -282,16 +278,16 @@ SvgFont::scaled_font_render_glyph (cairo_scaled_font_t */*scaled_font*/,
SPObject* node;
if (glyph == this->glyphs.size()){
if (!this->missingglyph) return CAIRO_STATUS_SUCCESS;
- node = (SPObject*) this->missingglyph;
+ node = SP_OBJECT(this->missingglyph);
} else {
- node = (SPObject*) this->glyphs[glyph];
+ node = SP_OBJECT(this->glyphs[glyph]);
}
if (!SP_IS_GLYPH(node) && !SP_IS_MISSING_GLYPH(node)) {
return CAIRO_STATUS_SUCCESS; // FIXME: is this the right code to return?
}
- SPFont* spfont = (SPFont*) node->parent;
+ SPFont* spfont = SP_FONT(node->parent);
if (!spfont) {
return CAIRO_STATUS_SUCCESS; // FIXME: is this the right code to return?
}
@@ -300,12 +296,12 @@ SvgFont::scaled_font_render_glyph (cairo_scaled_font_t */*scaled_font*/,
// or using the d attribute of a glyph node.
// pathv stores the path description from the d attribute:
Geom::PathVector pathv;
- if (SP_IS_GLYPH(node) && ((SPGlyph*)node)->d) {
- pathv = sp_svg_read_pathv(((SPGlyph*)node)->d);
+ if (SP_IS_GLYPH(node) && (SP_GLYPH(node))->d) {
+ pathv = sp_svg_read_pathv((SP_GLYPH(node))->d);
pathv = flip_coordinate_system(spfont, pathv);
this->render_glyph_path(cr, &pathv);
- } else if (SP_IS_MISSING_GLYPH(node) && ((SPMissingGlyph*)node)->d) {
- pathv = sp_svg_read_pathv(((SPMissingGlyph*)node)->d);
+ } else if (SP_IS_MISSING_GLYPH(node) && (SP_MISSING_GLYPH(node))->d) {
+ pathv = sp_svg_read_pathv((SP_MISSING_GLYPH(node))->d);
pathv = flip_coordinate_system(spfont, pathv);
this->render_glyph_path(cr, &pathv);
}
@@ -314,7 +310,7 @@ SvgFont::scaled_font_render_glyph (cairo_scaled_font_t */*scaled_font*/,
//render the SVG described on this glyph's child nodes.
for(node = node->children; node; node=node->next){
if (SP_IS_PATH(node)){
- pathv = ((SPShape*)node)->_curve->get_pathvector();
+ pathv = (SP_SHAPE(node))->_curve->get_pathvector();
pathv = flip_coordinate_system(spfont, pathv);
this->render_glyph_path(cr, &pathv);
}
@@ -324,12 +320,12 @@ SvgFont::scaled_font_render_glyph (cairo_scaled_font_t */*scaled_font*/,
if (SP_IS_USE(node)){
SPItem* item = SP_USE(node)->ref->getObject();
if (SP_IS_PATH(item)){
- pathv = ((SPShape*)item)->_curve->get_pathvector();
+ pathv = (SP_SHAPE(item))->_curve->get_pathvector();
pathv = flip_coordinate_system(spfont, pathv);
this->render_glyph_path(cr, &pathv);
}
- glyph_modified_connection = ((SPObject*) item)->connectModified(sigc::mem_fun(*this, &SvgFont::glyph_modified));
+ glyph_modified_connection = (SP_OBJECT(item))->connectModified(sigc::mem_fun(*this, &SvgFont::glyph_modified));
}
}
}
@@ -342,10 +338,10 @@ SvgFont::get_font_face(){
if (!this->userfont) {
for(SPObject* node = this->font->children;node;node=node->next){
if (SP_IS_GLYPH(node)){
- this->glyphs.push_back((SPGlyph*)node);
+ this->glyphs.push_back(SP_GLYPH(node));
}
if (SP_IS_MISSING_GLYPH(node)){
- this->missingglyph=(SPMissingGlyph*)node;
+ this->missingglyph=SP_MISSING_GLYPH(node);
}
}
this->userfont = new UserFont(this);
@@ -359,8 +355,6 @@ void SvgFont::refresh(){
this->userfont = NULL;
}
-#endif //#ifdef ENABLE_SVG_FONTS
-
/*
Local Variables:
mode:c++
diff --git a/src/display/nr-svgfonts.h b/src/display/nr-svgfonts.h
index 6138e2fbb..1101f93f2 100644
--- a/src/display/nr-svgfonts.h
+++ b/src/display/nr-svgfonts.h
@@ -18,8 +18,8 @@
class SvgFont;
struct SPFont;
-class SPGlyph;
-class SPMissingGlyph;
+struct SPGlyph;
+struct SPMissingGlyph;
struct _GdkEventExpose;
typedef _GdkEventExpose GdkEventExpose;
diff --git a/src/display/sodipodi-ctrl.cpp b/src/display/sodipodi-ctrl.cpp
index e21bdff15..45dc38a37 100644
--- a/src/display/sodipodi-ctrl.cpp
+++ b/src/display/sodipodi-ctrl.cpp
@@ -63,10 +63,10 @@ sp_ctrl_get_type (void)
static void
sp_ctrl_class_init (SPCtrlClass *klass)
{
- SPCanvasItemClass *item_class = (SPCanvasItemClass *) klass;
+ SPCanvasItemClass *item_class = SP_CANVAS_ITEM_CLASS(klass);
GObjectClass *g_object_class = (GObjectClass *) klass;
- parent_class = (SPCanvasItemClass *)g_type_class_peek_parent (klass);
+ parent_class = SP_CANVAS_ITEM_CLASS(g_type_class_peek_parent (klass));
g_object_class->set_property = sp_ctrl_set_property;
g_object_class->get_property = sp_ctrl_get_property;
@@ -287,8 +287,8 @@ sp_ctrl_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int fla
ctrl = SP_CTRL (item);
- if (((SPCanvasItemClass *) parent_class)->update)
- (* ((SPCanvasItemClass *) parent_class)->update) (item, affine, flags);
+ if ((SP_CANVAS_ITEM_CLASS(parent_class))->update)
+ (* (SP_CANVAS_ITEM_CLASS(parent_class))->update) (item, affine, flags);
sp_canvas_item_reset_bounds (item);
diff --git a/src/display/sodipodi-ctrlrect.cpp b/src/display/sodipodi-ctrlrect.cpp
index b0c997a92..c350e4614 100644
--- a/src/display/sodipodi-ctrlrect.cpp
+++ b/src/display/sodipodi-ctrlrect.cpp
@@ -61,9 +61,9 @@ GType sp_ctrlrect_get_type()
static void sp_ctrlrect_class_init(SPCtrlRectClass *c)
{
- SPCanvasItemClass *item_class = (SPCanvasItemClass *) c;
+ SPCanvasItemClass *item_class = SP_CANVAS_ITEM_CLASS(c);
- parent_class = (SPCanvasItemClass*) g_type_class_peek_parent(c);
+ parent_class = SP_CANVAS_ITEM_CLASS(g_type_class_peek_parent(c));
item_class->destroy = sp_ctrlrect_destroy;
item_class->update = sp_ctrlrect_update;
@@ -119,8 +119,6 @@ void CtrlRect::render(SPCanvasBuf *buf)
using Geom::X;
using Geom::Y;
- static double const dashes[2] = {4.0, 4.0};
-
if (!_area) {
return;
}
@@ -129,6 +127,7 @@ void CtrlRect::render(SPCanvasBuf *buf)
area[X].max() + _shadow_size, area[Y].max() + _shadow_size);
if ( area_w_shadow.intersects(buf->rect) )
{
+ static double const dashes[2] = {4.0, 4.0};
cairo_save(buf->ct);
cairo_translate(buf->ct, -buf->rect.left(), -buf->rect.top());
cairo_set_line_width(buf->ct, 1);
@@ -161,8 +160,8 @@ void CtrlRect::update(Geom::Affine const &affine, unsigned int flags)
using Geom::X;
using Geom::Y;
- if (((SPCanvasItemClass *) parent_class)->update) {
- ((SPCanvasItemClass *) parent_class)->update(this, affine, flags);
+ if ((SP_CANVAS_ITEM_CLASS(parent_class))->update) {
+ (SP_CANVAS_ITEM_CLASS(parent_class))->update(this, affine, flags);
}
sp_canvas_item_reset_bounds(this);
diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp
index 6d4d01e33..9d4049512 100644
--- a/src/display/sp-canvas.cpp
+++ b/src/display/sp-canvas.cpp
@@ -19,6 +19,7 @@
# include <config.h>
#endif
+#include <gdkmm/rectangle.h>
#include <cairomm/region.h>
#include "helper/sp-marshal.h"
@@ -35,7 +36,6 @@
#include "debug/gdk-event-latency-tracker.h"
#include "desktop.h"
#include "sp-namedview.h"
-#include <gdkmm/rectangle.h>
using Inkscape::Debug::GdkEventLatencyTracker;
@@ -227,21 +227,6 @@ public:
static int pickCurrentItem(SPCanvas *canvas, GdkEvent *event);
/**
- * Class initialization function for SPCanvasClass.
- */
- static void classInit(SPCanvasClass *klass);
-
- /**
- * Callback: object initialization for SPCanvas.
- */
- static void init(SPCanvas *canvas);
-
- /**
- * Destroy handler for SPCanvas.
- */
- static void dispose(GObject *object);
-
- /**
* The canvas widget's realize callback.
*/
static void realize(GtkWidget *widget);
@@ -291,7 +276,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
/**
@@ -369,25 +354,11 @@ public:
static void add_idle(SPCanvas *canvas);
/**
- * Convenience function to remove the idle handler of a canvas.
- */
- static void remove_idle(SPCanvas *canvas);
-
- /**
- * Removes the transient state of the canvas (idle handler, grabs).
- */
- static void shutdown_transients(SPCanvas *canvas);
-
- /**
* Update callback for canvas widget.
*/
static void requestCanvasUpdate(SPCanvas *canvas);
-
- static GtkWidgetClass *parentClass;
};
-GtkWidgetClass *SPCanvasImpl::parentClass = 0;
-
GType SPCanvasItem::getType()
{
static GType object_type = 0;
@@ -437,9 +408,9 @@ void sp_canvas_item_class_init(SPCanvasItemClass *klass)
G_TYPE_BOOLEAN, 1,
GDK_TYPE_EVENT);
- gobject_class->dispose = sp_canvas_item_dispose;
+ gobject_class->dispose = sp_canvas_item_dispose;
gobject_class->finalize = sp_canvas_item_finalize;
- klass->destroy = sp_canvas_item_real_destroy;
+ klass->destroy = sp_canvas_item_real_destroy;
object_signals[DESTROY] =
g_signal_new ("destroy",
@@ -1081,7 +1052,7 @@ void SPCanvasGroup::update(SPCanvasItem *item, Geom::Affine const &affine, unsig
Geom::OptRect bounds;
for (GList *list = group->items; list; list = list->next) {
- SPCanvasItem *i = (SPCanvasItem *)list->data;
+ SPCanvasItem *i = SP_CANVAS_ITEM(list->data);
sp_canvas_item_invoke_update (i, affine, flags);
@@ -1118,7 +1089,7 @@ double SPCanvasGroup::point(SPCanvasItem *item, Geom::Point p, SPCanvasItem **ac
double dist = 0.0;
for (GList *list = group->items; list; list = list->next) {
- SPCanvasItem *child = (SPCanvasItem *)list->data;
+ SPCanvasItem *child = SP_CANVAS_ITEM(list->data);
if ((child->x1 <= x2) && (child->y1 <= y2) && (child->x2 >= x1) && (child->y2 >= y1)) {
SPCanvasItem *point_item = NULL; // cater for incomplete item implementations
@@ -1152,7 +1123,7 @@ void SPCanvasGroup::render(SPCanvasItem *item, SPCanvasBuf *buf)
SPCanvasGroup const *group = SP_CANVAS_GROUP(item);
for (GList *list = group->items; list; list = list->next) {
- SPCanvasItem *child = (SPCanvasItem *)list->data;
+ SPCanvasItem *child = SP_CANVAS_ITEM(list->data);
if (child->visible) {
if ((child->x1 < buf->rect.right()) &&
(child->y1 < buf->rect.bottom()) &&
@@ -1171,7 +1142,7 @@ void SPCanvasGroup::viewboxChanged(SPCanvasItem *item, Geom::IntRect const &new_
SPCanvasGroup *group = SP_CANVAS_GROUP(item);
for (GList *list = group->items; list; list = list->next) {
- SPCanvasItem *child = (SPCanvasItem *)list->data;
+ SPCanvasItem *child = SP_CANVAS_ITEM(list->data);
if (child->visible) {
if (SP_CANVAS_ITEM_GET_CLASS(child)->viewbox_changed) {
SP_CANVAS_ITEM_GET_CLASS(child)->viewbox_changed(child, new_area);
@@ -1218,68 +1189,46 @@ void SPCanvasGroup::remove(SPCanvasItem *item)
}
}
-/**
- * Registers the SPCanvas class if necessary, and returns the type ID
- * associated to it.
- *
- * @return The type ID of the SPCanvas class.
- */
-GType SPCanvas::getType(void)
-{
- static GType type = 0;
- if (!type) {
- GTypeInfo info = {
- sizeof(SPCanvasClass),
- 0, // base_init
- 0, // base_finalize
- (GClassInitFunc)SPCanvasImpl::classInit,
- 0, // class_finalize
- 0, // class_data
- sizeof(SPCanvas),
- 0, // n_preallocs
- (GInstanceInitFunc)SPCanvasImpl::init,
- 0 // value_table
- };
- type = g_type_register_static(GTK_TYPE_WIDGET, "SPCanvas", &info, static_cast<GTypeFlags>(0));
- }
- return type;
-}
+static void sp_canvas_dispose (GObject *object);
+static void sp_canvas_shutdown_transients(SPCanvas *canvas);
-void SPCanvasImpl::classInit(SPCanvasClass *klass)
-{
- GObjectClass *object_class = (GObjectClass *) klass;
- GtkWidgetClass *widget_class = (GtkWidgetClass *) klass;
+G_DEFINE_TYPE(SPCanvas, sp_canvas, GTK_TYPE_WIDGET);
- parentClass = reinterpret_cast<GtkWidgetClass *>(g_type_class_peek_parent(klass));
+static void
+sp_canvas_class_init(SPCanvasClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
- object_class->dispose = SPCanvasImpl::dispose;
+ object_class->dispose = sp_canvas_dispose;
- widget_class->realize = SPCanvasImpl::realize;
- widget_class->unrealize = SPCanvasImpl::unrealize;
+ widget_class->realize = SPCanvasImpl::realize;
+ widget_class->unrealize = SPCanvasImpl::unrealize;
#if GTK_CHECK_VERSION(3,0,0)
- widget_class->get_preferred_width = SPCanvasImpl::getPreferredWidth;
+ widget_class->get_preferred_width = SPCanvasImpl::getPreferredWidth;
widget_class->get_preferred_height = SPCanvasImpl::getPreferredHeight;
- widget_class->draw = SPCanvasImpl::handleDraw;
+ widget_class->draw = SPCanvasImpl::handleDraw;
#else
- widget_class->size_request = SPCanvasImpl::sizeRequest;
- widget_class->expose_event = SPCanvasImpl::handleExpose;
+ widget_class->size_request = SPCanvasImpl::sizeRequest;
+ widget_class->expose_event = SPCanvasImpl::handleExpose;
#endif
- widget_class->size_allocate = SPCanvasImpl::sizeAllocate;
- widget_class->button_press_event = SPCanvasImpl::button;
+ widget_class->size_allocate = SPCanvasImpl::sizeAllocate;
+ widget_class->button_press_event = SPCanvasImpl::button;
widget_class->button_release_event = SPCanvasImpl::button;
- widget_class->motion_notify_event = SPCanvasImpl::handleMotion;
- widget_class->scroll_event = SPCanvasImpl::handleScroll;
- widget_class->key_press_event = SPCanvasImpl::handleKeyEvent;
- widget_class->key_release_event = SPCanvasImpl::handleKeyEvent;
- widget_class->enter_notify_event = SPCanvasImpl::handleCrossing;
- widget_class->leave_notify_event = SPCanvasImpl::handleCrossing;
- widget_class->focus_in_event = SPCanvasImpl::handleFocusIn;
- widget_class->focus_out_event = SPCanvasImpl::handleFocusOut;
+ widget_class->motion_notify_event = SPCanvasImpl::handleMotion;
+ widget_class->scroll_event = SPCanvasImpl::handleScroll;
+ widget_class->key_press_event = SPCanvasImpl::handleKeyEvent;
+ widget_class->key_release_event = SPCanvasImpl::handleKeyEvent;
+ widget_class->enter_notify_event = SPCanvasImpl::handleCrossing;
+ widget_class->leave_notify_event = SPCanvasImpl::handleCrossing;
+ widget_class->focus_in_event = SPCanvasImpl::handleFocusIn;
+ widget_class->focus_out_event = SPCanvasImpl::handleFocusOut;
}
-void SPCanvasImpl::init(SPCanvas *canvas)
+static void
+sp_canvas_init(SPCanvas *canvas)
{
gtk_widget_set_has_window (GTK_WIDGET (canvas), TRUE);
gtk_widget_set_double_buffered (GTK_WIDGET (canvas), FALSE);
@@ -1318,7 +1267,7 @@ void SPCanvasImpl::init(SPCanvas *canvas)
canvas->is_scrolling = false;
}
-void SPCanvasImpl::remove_idle(SPCanvas *canvas)
+static void sp_canvas_remove_idle(SPCanvas *canvas)
{
if (canvas->idle_id) {
g_source_remove (canvas->idle_id);
@@ -1326,7 +1275,8 @@ void SPCanvasImpl::remove_idle(SPCanvas *canvas)
}
}
-void SPCanvasImpl::shutdown_transients(SPCanvas *canvas)
+static void
+sp_canvas_shutdown_transients(SPCanvas *canvas)
{
// We turn off the need_redraw flag, since if the canvas is mapped again
// it will request a redraw anyways. We do not turn off the need_update
@@ -1352,10 +1302,11 @@ void SPCanvasImpl::shutdown_transients(SPCanvas *canvas)
#endif
}
- remove_idle(canvas);
+ sp_canvas_remove_idle(canvas);
}
-void SPCanvasImpl::dispose(GObject *object)
+static void
+sp_canvas_dispose(GObject *object)
{
SPCanvas *canvas = SP_CANVAS(object);
@@ -1364,12 +1315,12 @@ void SPCanvasImpl::dispose(GObject *object)
canvas->root = NULL;
}
- shutdown_transients(canvas);
+ sp_canvas_shutdown_transients(canvas);
#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
canvas->cms_key.~ustring();
#endif
- if (G_OBJECT_CLASS(parentClass)->dispose) {
- (* G_OBJECT_CLASS(parentClass)->dispose)(object);
+ if (G_OBJECT_CLASS(sp_canvas_parent_class)->dispose) {
+ (* G_OBJECT_CLASS(sp_canvas_parent_class)->dispose)(object);
}
}
@@ -1388,7 +1339,7 @@ void trackLatency(GdkEvent const *event)
GtkWidget *SPCanvas::createAA()
{
- SPCanvas *canvas = reinterpret_cast<SPCanvas *>(g_object_new(SPCanvas::getType(), NULL));
+ SPCanvas *canvas = SP_CANVAS(g_object_new(SP_TYPE_CANVAS, NULL));
return GTK_WIDGET(canvas);
}
@@ -1456,10 +1407,10 @@ void SPCanvasImpl::unrealize(GtkWidget *widget)
canvas->grabbed_item = NULL;
canvas->focused_item = NULL;
- shutdown_transients(canvas);
+ sp_canvas_shutdown_transients(canvas);
- if (GTK_WIDGET_CLASS(parentClass)->unrealize)
- (* GTK_WIDGET_CLASS(parentClass)->unrealize)(widget);
+ if (GTK_WIDGET_CLASS(sp_canvas_parent_class)->unrealize)
+ (* GTK_WIDGET_CLASS(sp_canvas_parent_class)->unrealize)(widget);
}
@@ -1649,7 +1600,6 @@ int SPCanvasImpl::emitEvent(SPCanvas *canvas, GdkEvent *event)
int SPCanvasImpl::pickCurrentItem(SPCanvas *canvas, GdkEvent *event)
{
int button_down = 0;
- double x, y;
if (!canvas->root) // canvas may have already be destroyed by closing desktop durring interrupted display!
return FALSE;
@@ -1709,6 +1659,7 @@ int SPCanvasImpl::pickCurrentItem(SPCanvas *canvas, GdkEvent *event)
// LeaveNotify means that there is no current item, so we don't look for one
if (canvas->pick_event.type != GDK_LEAVE_NOTIFY) {
// these fields don't have the same offsets in both types of events
+ double x, y;
if (canvas->pick_event.type == GDK_ENTER_NOTIFY) {
x = canvas->pick_event.crossing.x;
@@ -2178,23 +2129,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];
- canvas->requestRedraw(r.left(), r.top(), r.right(), r.bottom());
+ 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());
+ }
return FALSE;
}
#else
-gint SPCanvasImpl::handleExpose(GtkWidget *widget, GdkEventExpose *event)
+gboolean SPCanvasImpl::handleExpose(GtkWidget *widget, GdkEventExpose *event)
{
SPCanvas *canvas = SP_CANVAS(widget);
@@ -2203,43 +2155,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
diff --git a/src/display/sp-canvas.h b/src/display/sp-canvas.h
index f0366a2e5..b570b739e 100644
--- a/src/display/sp-canvas.h
+++ b/src/display/sp-canvas.h
@@ -39,7 +39,7 @@
G_BEGIN_DECLS
-#define SP_TYPE_CANVAS (SPCanvas::getType())
+#define SP_TYPE_CANVAS (sp_canvas_get_type())
#define SP_CANVAS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_CANVAS, SPCanvas))
#define SP_IS_CANVAS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_CANVAS))
@@ -71,14 +71,14 @@ G_END_DECLS
class SPCanvasImpl;
+GType sp_canvas_get_type() G_GNUC_CONST;
+
/**
* Port of GnomeCanvas for inkscape needs.
*/
struct SPCanvas {
friend class SPCanvasImpl;
- static GType getType();
-
/**
* Returns new canvas as widget.
*/
diff --git a/src/display/sp-ctrlcurve.h b/src/display/sp-ctrlcurve.h
index 15de20161..90936185c 100644
--- a/src/display/sp-ctrlcurve.h
+++ b/src/display/sp-ctrlcurve.h
@@ -17,7 +17,7 @@
#include "display/sp-ctrlline.h"
-struct SPItem;
+class SPItem;
#define SP_TYPE_CTRLCURVE (SPCtrlCurve::getType())
#define SP_CTRLCURVE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_CTRLCURVE, SPCtrlCurve))
diff --git a/src/display/sp-ctrlpoint.cpp b/src/display/sp-ctrlpoint.cpp
index d07e9385b..026cc7589 100644
--- a/src/display/sp-ctrlpoint.cpp
+++ b/src/display/sp-ctrlpoint.cpp
@@ -52,9 +52,9 @@ sp_ctrlpoint_get_type (void)
static void sp_ctrlpoint_class_init(SPCtrlPointClass *klass)
{
- SPCanvasItemClass *item_class = (SPCanvasItemClass *) klass;
+ SPCanvasItemClass *item_class = SP_CANVAS_ITEM_CLASS(klass);
- parent_class = (SPCanvasItemClass*)g_type_class_peek_parent (klass);
+ parent_class = SP_CANVAS_ITEM_CLASS(g_type_class_peek_parent(klass));
item_class->destroy = sp_ctrlpoint_destroy;
item_class->update = sp_ctrlpoint_update;
diff --git a/src/display/sp-ctrlquadr.cpp b/src/display/sp-ctrlquadr.cpp
index ae15d620a..b6a0da109 100644
--- a/src/display/sp-ctrlquadr.cpp
+++ b/src/display/sp-ctrlquadr.cpp
@@ -61,9 +61,9 @@ sp_ctrlquadr_get_type (void)
static void
sp_ctrlquadr_class_init (SPCtrlQuadrClass *klass)
{
- SPCanvasItemClass *item_class = (SPCanvasItemClass *) klass;
+ SPCanvasItemClass *item_class = SP_CANVAS_ITEM_CLASS(klass);
- parent_class = (SPCanvasItemClass*)g_type_class_peek_parent (klass);
+ parent_class = SP_CANVAS_ITEM_CLASS(g_type_class_peek_parent(klass));
item_class->destroy = sp_ctrlquadr_destroy;
item_class->update = sp_ctrlquadr_update;