summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 8084714)
raw | patch | inline | side by side (parent: 8084714)
author | kiirala <kiirala@users.sourceforge.net> | |
Wed, 21 Jun 2006 16:04:22 +0000 (16:04 +0000) | ||
committer | kiirala <kiirala@users.sourceforge.net> | |
Wed, 21 Jun 2006 16:04:22 +0000 (16:04 +0000) |
35 files changed:
diff --git a/doc/nr-filter-interface.txt b/doc/nr-filter-interface.txt
--- /dev/null
@@ -0,0 +1,229 @@
+Public interface for NR::Filter and NR::FilterPrimitive
+
+Constructors
+============
+
+Filter::Filter()
+Creates a new filter with space for one filter element
+
+Filter::Filter(int n)
+Creates a new filter with space for n filter elements. If number of filter
+elements is known beforehand, it's better to use this constructor.
+
+
+Managing filter primitives
+==========================
+
+FilterPrimitive * Filter::add_primitive(FilterPrimitiveType type)
+Creates a new filter primitive under this filter object.
+New primitive is placed so that it will be executed after all filter
+primitives defined beforehand for this filter object.
+Should this filter not have enough space for a new primitive, the filter
+is enlarged to accomodate the new filter element. It may be enlarged by more
+that one element.
+Returns a pointer to the filter primitive created.
+Returns NULL, if type is not valid filter primitive type or filter primitive
+of such type cannot be created.
+
+void Filter::clear_primitives()
+Removes all filter primitives from this filter.
+All pointers to filter primitives inside this filter should be considered
+invalid after calling this function.
+
+FilterPrimitive * Filter::replace_primitive(FilterPrimitive *target,
+ FilterPrimitiveType type)
+Replaces filter primitive pointed by 'target' with a new filter primitive of
+type 'type'
+If 'target' does not correspond to any primitive inside this filter OR
+'type' is not a valid filter primitive type OR
+filter primitive of such type cannot be created,
+this function returns NULL and doesn't change the internal state of this
+filter.
+Otherwise, a new filter primitive is created. Any pointers to filter primitive
+'target' should be considered invalid. A pointer to the newly created
+primitive is returned.
+
+
+Filter primitive types
+======================
+
+enum FilterPrimitiveType is declared in display/nr-filter-types.h
+
+Enumeration value Corresponding filter primitive
+NR_FILTER_BLEND feBlend
+NR_FILTER_COLORMATRIX feColorMatrix
+NR_FILTER_COMPONENTTRANSFER feComponentTransfer
+NR_FILTER_COMPOSITE feComposite
+NR_FILTER_CONVOLVEMATRIX feConvolveMatrix
+NR_FILTER_DIFFUSELIGHTING feDiffuseLighting
+NR_FILTER_DISPLACEMENTMAP feDisplacementMap
+NR_FILTER_FLOOD feFlood
+NR_FILTER_GAUSSIANBLUR feGaussianBlur
+NR_FILTER_IMAGE feImage
+NR_FILTER_MERGE feMerge
+NR_FILTER_MORPHOLOGY feMorphology
+NR_FILTER_OFFSET feOffset
+NR_FILTER_SPECULARLIGHTING feSpecularLighting
+NR_FILTER_TILE feTile
+NR_FILTER_TURBULENCE feTurbulence
+
+
+Setting inputs and outputs for filter primitives
+================================================
+
+Each filter primitive can take one or more images as inputs and produces
+a single image as output. In NR::Filter these are managed as image slots.
+Every slot can hold one image.
+
+There are two types of slots: pre-defined and user defined. Pre-defined
+slots may only be used as inputs, while user defined slots may be used as
+both inputs and outputs. User defined slots are numbered from 0 upwards,
+pre-defined slots are numbered with the following constants:
+
+Constant name Corresponding SVG input name
+NR_FILTER_SOURCEGRAPHIC SourceGraphic
+NR_FILTER_SOURCEALPHA SourceAlpha
+NR_FILTER_BACKGROUNDIMAGE BackgroundImage
+NR_FILTER_BACKGROUNDAPLHA BackgroundAlpha
+NR_FILTER_FILLPAINT FillPaint
+NR_FILTER_SOURCEPAINT SourcePaint
+(defined in display/nr-filter-types.h)
+
+Any user defined slot used as input must be the output of some previous
+filter primitive. Other than that, user defined input slots do not need to be
+used in any particular order.
+
+void FilterPrimitive::set_input(int slot)
+Sets the input slot number 'slot' to be used as input in rendering filter
+primitive 'primitive'
+For filter primitive types accepting more than one input, this sets the
+first input.
+If any of the required input slots is not set, the output of previous filter
+primitive is used, or SourceGraphic if this is the first primitive for this
+filter.
+
+void FilterPrimitive::set_input(int input, int slot)
+Sets the input slot number 'slot' to be user as input number 'input' in
+rendering filter primitive 'primitive'
+First input for a filter primitive is number 0. For primitives with attributes
+'in' and 'in2', these are numbered 0 and 1, respectively.
+If any of required input slots for a filter is not set, the output of
+previous filter primitive is used, or SourceGraphic if this is the first
+filter primitive for this filter.
+
+void FilterPrimitive::set_output(int slot)
+Sets the slot number 'slot' to be used as output from filter primitive
+'primitive'
+If output slot for a filter element is not set, one of the unused image
+slots is used.
+It is an error to specify a pre-defined slot as 'slot'. Such call does
+not have any effect to the state of filter or its primitives.
+
+void Filter::set_output(int slot)
+Sets the slot number 'slot' to be used as result from this filter.
+If output is not set, the output from last filter primitive is used as
+output from the filter.
+It is an error to specify a pre-defined slot as 'slot'. Such call does
+not have any effect to the state of filter or its primitives.
+
+
+Functions for reading filter state
+==================================
+
+int Filter::get_enlarge(Matrix const &m)
+Returns the amount of pixels the rendering area should be enlarged
+to prevent visual artefacts when filter needs to read pixels that
+are outside its output area (e.g. gaussian blur)
+
+void Fiter::bbox_enlarge(NRRectL &bbox)
+Given an object bounding box, this function enlarges it so that it
+contains the filter effect area
+
+
+Filter effects region and filter primitive subregion
+====================================================
+
+void Filter::set_x(SVGLength &lenght)
+void FilterPrimitive::set_x(SVGLength &length)
+
+void Filter::set_y(SVGLength &length)
+void FilterPrimitive::set_y(SVGLength &length)
+
+void Filter::set_width(SVGLength &length)
+void FilterPrimitive::set_width(SVGLength &length)
+
+void Filter::set_height(SVGLength &length)
+void FilterPrimitive::set_width(SVGLength &length)
+
+These functions set the parameters for filter effects region and filter
+primitive subregion.
+Passing an unset length (length._set == false) results in no changes to
+filter state.
+Filter will not hold any references to the passed SVGLength object after
+function returns.
+If any of these parameters does not get set - either because function
+for setting that is not called, or it is called with an unset length -
+the default value, as defined in SVG standard, for that parameter is
+used instead.
+
+void Filter::set_region(SVGLength &x, SVGLength &y,
+ SVGLength &width, SVGLength &height)
+void FilterPrimitive::set_region(SVGLength &x, SVGLength &y,
+ SVGLength &width, SVGLength &height)
+
+This is shorthand for calling set_x(x), set_y(y), set_width(width) and
+set_height(height). The result is as if those four functions had been
+called separately.
+
+void Filter::reset_region()
+void FilterPrimitive::reset_region()
+
+Resets the filter effects region or filter primitive subregion to its
+default value as defined in SVG standard.
+
+void Filter::set_resolution(double x_pixels)
+
+Sets the width of intermediate images in pixels. If not set, suitable
+resolution is determined automatically. If x_pixels is less than zero,
+calling this function results in no changes to filter state.
+
+void Filter::set_resolution(double x_pixels, double y_pixels)
+
+Sets the width and height of intermediate images in pixels. If not set,
+suitable resolution is determined automatically. If either parameter is
+less than zero, calling this function results in no changes to filter
+state.
+
+void Filter::reset_resolution()
+
+Resets the filter resolution to its default value, i.e. automatically
+determined.
+
+void Filter::set_filter_units(SPFilterUnits unit)
+void Filter::set_primitive_units(SPFilterUnits unit)
+
+Set the filterUnits and primitiveUnits -properteries, respectively. If
+not set, the default values are used: objectBoundingBox for filterUnits
+and userSpaceOnUse for primitiveUnits. If the parameter value is not a
+valid enumeration value from SPFilterUnits, no changes to filter state
+are made.
+
+
+Parameters specific to some filter primitive type
+=================================================
+
+Gaussian blur
+-------------
+
+void FilterGaussian::set_deviation(double deviation)
+void FilterGaussian::set_deviation(double x, double y)
+
+Set the standard deviation value for gaussian blur. One-parameter
+version sets deviation along both axis to same value, two-parameter
+version allows setting deviation along x- and y-axis separately.
+Passing either of these functions a negative value, NaN or infinity is
+considered an error and no changes to filter state are made. If not set,
+default value of zero is used, which means the filter results in
+transparent black image.
+(NB: as for now, the default value can be overriden with configuration
+file parameter options.filtertest)
diff --git a/src/Makefile_insert b/src/Makefile_insert
index ceecbd9ce6fdc51524e96aab19f73b7917062f05..a0f2ff527be1728bf8ed2bf3cfa5a01f393229a5 100644 (file)
--- a/src/Makefile_insert
+++ b/src/Makefile_insert
sp-cursor.cpp sp-cursor.h \
sp-defs.cpp sp-defs.h \
sp-ellipse.cpp sp-ellipse.h \
+ sp-filter-fns.h \
+ sp-filter-reference.cpp \
+ sp-filter-reference.h \
+ sp-filter-units.h \
+ sp-filter.cpp sp-filter.h \
sp-flowdiv.h sp-flowdiv.cpp \
sp-flowregion.h sp-flowregion.cpp \
sp-flowtext.h sp-flowtext.cpp \
+ sp-gaussian-blur.cpp sp-gaussian-blur.h \
+ sp-gaussian-blur-fns.h \
sp-gradient-fns.h \
sp-gradient-reference.cpp \
sp-gradient-reference.h \
diff --git a/src/attributes.cpp b/src/attributes.cpp
index 541acfc0cfda10c5752e77a823001e270fe489dd..f0ecc1e415ed13bccc0ac252997375062732699e 100644 (file)
--- a/src/attributes.cpp
+++ b/src/attributes.cpp
{SP_ATTR_STARTOFFSET, "startOffset"},
/* SPStop */
{SP_ATTR_OFFSET, "offset"},
+ /* SPFilter */
+ {SP_ATTR_FILTERUNITS, "filterUnits"},
+ {SP_ATTR_PRIMITIVEUNITS, "primitiveUnits"},
+ {SP_ATTR_FILTERRES, "filterRes"},
+ /* SPGaussianBlur */
+ {SP_ATTR_STDDEVIATION, "stdDeviation"},
/* SPGradient */
{SP_ATTR_GRADIENTUNITS, "gradientUnits"},
{SP_ATTR_GRADIENTTRANSFORM, "gradientTransform"},
diff --git a/src/attributes.h b/src/attributes.h
index bcbed50d0f45aedb3d4bf96189cc8dbe128f44ca..d80e870061defe57d975679914e022f5da32e4c8 100644 (file)
--- a/src/attributes.h
+++ b/src/attributes.h
SP_ATTR_STARTOFFSET,
/* SPStop */
SP_ATTR_OFFSET,
+ /* SPFilter */
+ SP_ATTR_FILTERUNITS,
+ SP_ATTR_PRIMITIVEUNITS,
+ SP_ATTR_FILTERRES,
+ /* SPGaussianBlur */
+ SP_ATTR_STDDEVIATION,
/* SPGradient */
SP_ATTR_GRADIENTUNITS,
SP_ATTR_GRADIENTTRANSFORM,
index de6ec85c2a688cfc0bba5d8cf28dc071e5f082c8..5aec6894f2d28611854769056ce7002e3c744672 100644 (file)
display/sp-ctrlline.cpp \
display/sp-ctrlline.h \
display/sp-ctrlquadr.cpp \
- display/sp-ctrlquadr.h
+ display/sp-ctrlquadr.h \
+ display/nr-filter.cpp \
+ display/nr-filter.h \
+ display/nr-filter-primitive.cpp \
+ display/nr-filter-primitive.h \
+ display/nr-filter-gaussian.cpp \
+ display/nr-filter-gaussian.h
display_bezier_utils_test_SOURCES = display/bezier-utils-test.cpp
display_bezier_utils_test_LDADD = libnr/libnr.a -lglib-2.0
index 23b74a3782fd288b3e144b681e1e988e4303842e..a2dda988b5b59fa58b1f3b23615661a6d63f7563 100644 (file)
NRType nr_arena_glyphs_group_get_type (void);
struct NRArenaGlyphsGroup : public NRArenaGroup {
- SPStyle *style;
+ //SPStyle *style;
NRRect paintbox;
/* State data */
SPPainter *fill_painter;
index f15c72e8e31394392abaf2860a001e93163f4310..9657715ea72a874c8b7303952429e590e63eaac9 100644 (file)
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include "nr-arena-group.h"
+#include "display/nr-arena-group.h"
+#include "display/nr-filter.h"
+#include "style.h"
static void nr_arena_group_class_init (NRArenaGroupClass *klass);
static void nr_arena_group_init (NRArenaGroup *group);
group->transparent = FALSE;
group->children = NULL;
group->last = NULL;
+ group->style = NULL;
nr_matrix_set_identity (&group->child_transform);
#ifdef arena_item_tile_cache
@@ -181,6 +184,20 @@ nr_arena_group_update (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int
return beststate;
}
+void nr_arena_group_set_style (NRArenaGroup *group, SPStyle *style)
+{
+ g_return_if_fail(group != NULL);
+ g_return_if_fail(NR_IS_ARENA_GROUP(group));
+
+ if (style) sp_style_ref(style);
+ if (group->style) sp_style_unref(group->style);
+ group->style = style;
+
+ if (style && style->filter.set && style->filter.filter) {
+ group->filter = new NR::Filter();
+ }
+}
+
static unsigned int
nr_arena_group_render (NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags)
{
index b33495362003f46f188582578ef05503e8df6bfe..9da16908d2a3531880426922ef6e9f4ea83a7ee2 100644 (file)
#define NR_IS_ARENA_GROUP(o) (NR_CHECK_INSTANCE_TYPE ((o), NR_TYPE_ARENA_GROUP))
#include "nr-arena-item.h"
+#include "style.h"
NRType nr_arena_group_get_type (void);
NRArenaItem *children;
NRArenaItem *last;
NRMatrix child_transform;
+ SPStyle *style;
static NRArenaGroup *create(NRArena *arena) {
NRArenaGroup *obj=reinterpret_cast<NRArenaGroup *>(nr_object_new(NR_TYPE_ARENA_GROUP));
void nr_arena_group_set_child_transform(NRArenaGroup *group, NR::Matrix const &t);
void nr_arena_group_set_child_transform(NRArenaGroup *group, NRMatrix const *t);
+void nr_arena_group_set_style(NRArenaGroup *group, SPStyle *style);
#endif
index 97c769548773facd00548f88225a191aaad983c7..57413ef227740b750e756026a2429c061726b3b6 100644 (file)
#include <libnr/nr-pixops.h>
#include "nr-arena.h"
#include "nr-arena-item.h"
-//#include "nr-arena-group.h"
#include "gc-core.h"
+#include "nr-filter.h"
+#include "libnr/nr-rect.h"
+#include "nr-arena-group.h"
+
namespace GC = Inkscape::GC;
static void nr_arena_item_class_init (NRArenaItemClass *klass);
item->mask = NULL;
item->px = NULL;
item->data = NULL;
+ item->filter = NULL;
}
static void
@@ -243,10 +247,17 @@ nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigne
if (item->transform) {
nr_matrix_multiply (&childgc.transform, item->transform, &childgc.transform);
}
+ /* Remember the transformation matrix */
+ item->ctm = childgc.transform;
/* Invoke the real method */
item->state = NR_ARENA_ITEM_VIRTUAL (item, update) (item, area, &childgc, state, reset);
if (item->state & NR_ARENA_ITEM_STATE_INVALID) return item->state;
+ /* Enlarge the bounding box to contain filter effects */
+ if(item->filter) {
+ item->filter->bbox_enlarge(item->bbox);
+ }
+
/* Clipping */
if (item->clip) {
unsigned int newstate;
@@ -300,6 +311,10 @@ unsigned int nr_arena_item_invoke_render(NRArenaItem *item, NRRectL const *area,
if (!item->visible) return item->state | NR_ARENA_ITEM_STATE_RENDER;
nr_rect_l_intersect (&carea, area, &item->bbox);
if (nr_rect_l_test_empty (&carea)) return item->state | NR_ARENA_ITEM_STATE_RENDER;
+ if(item->filter) {
+ nr_rect_l_enlarge(&carea, item->filter->get_enlarge(item->ctm));
+ nr_rect_l_intersect(&carea, &carea, &item->bbox);
+ }
if (item->px) {
/* Has cache pixblock, render this and return */
@@ -537,7 +552,7 @@ unsigned int nr_arena_item_invoke_render(NRArenaItem *item, NRRectL const *area,
#endif
} else {
/* Determine, whether we need temporary buffer */
- if (item->clip || item->mask || ((item->opacity != 255) && !item->render_opacity && item->arena->rendermode != RENDERMODE_OUTLINE)) {
+ if (item->clip || item->mask || ((item->opacity != 255) && !item->render_opacity && item->arena->rendermode != RENDERMODE_OUTLINE) || item->filter) {
NRPixBlock ipb, mpb;
/* Setup and render item buffer */
@@ -553,6 +568,11 @@ unsigned int nr_arena_item_invoke_render(NRArenaItem *item, NRRectL const *area,
}
ipb.empty = FALSE;
+ /* Run filtering test, if a filter is set for this object */
+ if(item->filter) {
+ item->filter->render(item, &ipb);
+ }
+
if (item->clip || item->mask) {
/* Setup mask pixblock */
nr_pixblock_setup_fast (&mpb, NR_PIXBLOCK_MODE_A8, carea.x0, carea.y0, carea.x1, carea.y1, TRUE);
index 22b9929206acfc1be9b9867c3ae8e1ed4d9dbe14..7a6c676024e96cf18c03ab30e7c20addf36c75be 100644 (file)
#include <libnr/nr-object.h>
#include "gc-soft-ptr.h"
#include "nr-arena-forward.h"
+#include "display/nr-filter.h"
+/* TODO: without this, gcc barfs on clause "NR::Filter *filter" later on.
+ * Obviously we shouldn't need to have the next three rows */
+namespace NR {
+class Filter;
+}
// My testing shows that disabling cache reduces the amount
// of leaked memory when many documents are loaded one from the other,
};
struct NRArenaItem : public NRObject {
+
NRArena *arena;
Inkscape::GC::soft_ptr<NRArenaItem> parent;
NRArenaItem *next;
NRArenaItem *clip;
/* Mask item */
NRArenaItem *mask;
+ /* Filter to be applied after rendering this object, NULL if none */
+ NR::Filter *filter;
/* Rendered buffer */
unsigned char *px;
/* Single data member */
void *data;
+ /* Current Transformation Matrix */
+ NR::Matrix ctm;
+
void init(NRArena *arena) {
this->arena = arena;
}
index d26d1bc2792fb73c7b314dd70a9e3f732ffbaf84..abe343a1dac834e7107faccc7390b6ba121d3471 100644 (file)
#include <display/nr-arena.h>
#include <display/nr-arena-shape.h>
+#include "display/nr-filter.h"
#include <libnr/n-art-bpath.h>
#include <libnr/nr-path.h>
#include <libnr/nr-pixops.h>
#include <livarot/float-line.h>
#include <livarot/int-line.h>
#include <style.h>
+/* prefs-utils used for deciding, whether to run filtering test or not */
+#include "prefs-utils.h"
//int showRuns=0;
void nr_pixblock_render_shape_mask_or(NRPixBlock &m,Shape* theS);
}
shape->setMitreLimit(style->stroke_miterlimit.value);
+ /* TODO: after SPStyle handles filters, get the correct filter
+ * from there. */
+ //if (prefs_get_double_attribute("options.filtertest", "value", 0) != 0)
+ if (style->filter.set && style->filter.filter)
+ shape->filter = new NR::Filter();
+
nr_arena_item_request_update(shape, NR_ARENA_ITEM_STATE_ALL, FALSE);
}
diff --git a/src/display/nr-filter-gaussian.cpp b/src/display/nr-filter-gaussian.cpp
--- /dev/null
@@ -0,0 +1,394 @@
+#define __NR_FILTER_GAUSSIAN_CPP__
+
+/*
+ * Gaussian blur renderer
+ *
+ * Author:
+ * Niko Kiirala <niko@kiirala.com>
+ *
+ * Copyright (C) 2006 Niko Kiirala
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <cmath>
+
+using std::isnormal;
+
+#include "display/nr-filter-primitive.h"
+#include "display/nr-filter-gaussian.h"
+#include "libnr/nr-pixblock.h"
+#include "libnr/nr-matrix.h"
+#include "prefs-utils.h"
+
+namespace NR {
+
+FilterGaussian::FilterGaussian()
+{
+ _deviation_x = _deviation_y = prefs_get_double_attribute("options.filtertest", "value", 0.0);
+}
+
+FilterPrimitive *FilterGaussian::create()
+{
+ return new FilterGaussian();
+}
+
+int FilterGaussian::_kernel_size(Matrix const &trans)
+{
+ int length_x = _effect_area_scr_x(trans);
+ int length_y = _effect_area_scr_y(trans);
+ return _max(length_x, length_y) * 2 + 1;
+}
+
+void FilterGaussian::_make_kernel(double *kernel, double deviation, double expansion)
+{
+ double length = deviation * 3.0;
+ int scr_len = (int)std::floor(length * expansion);
+ if(scr_len < 1) scr_len = 1;
+ double d_sq = deviation * deviation * 2;
+ double step = length / scr_len;
+
+ double sum = 0;
+ for ( int i = 0; i < scr_len * 2 + 1 ; i++ ) {
+ double i_sq = (step * i - length) * (step * i - length);
+ sum += (std::exp(-i_sq / d_sq) / std::sqrt(M_PI * d_sq));
+ }
+
+ for ( int i = 0; i < scr_len * 2 + 1 ; i++ ) {
+ double i_sq = (step * i - length) * (step * i - length);
+ kernel[i] = (std::exp(-i_sq / d_sq) / std::sqrt(M_PI * d_sq)) / sum;
+ }
+}
+
+int FilterGaussian::_effect_area_scr_x(Matrix const &trans)
+{
+ int ret = (int)std::floor(_deviation_x * 3.0 * trans.expansionX());
+ if(ret < 1) ret = 1;
+ return ret;
+}
+
+int FilterGaussian::_effect_area_scr_y(Matrix const &trans)
+{
+ int ret = (int)std::floor(_deviation_y * 3.0 * trans.expansionY());
+ if(ret < 1) ret = 1;
+ return ret;
+}
+
+int FilterGaussian::_effect_subsample_step(int scr_len_x)
+{
+ if (scr_len_x < 16) {
+ return 1;
+ } else if (scr_len_x < 80) {
+ return 4;
+ } else if (scr_len_x < 160) {
+ return 8;
+ } else if (scr_len_x < 320) {
+ return 32;
+ } else if (scr_len_x < 640) {
+ return 64;
+ } else if (scr_len_x < 1280) {
+ return 256;
+ } else if (scr_len_x < 2560) {
+ return 1024;
+ } else {
+ return 65536;
+ }
+}
+
+int FilterGaussian::_effect_subsample_step_log2(int scr_len_x)
+{
+ if (scr_len_x < 16) {
+ return 0;
+ } else if (scr_len_x < 80) {
+ return 2;
+ } else if (scr_len_x < 160) {
+ return 3;
+ } else if (scr_len_x < 320) {
+ return 5;
+ } else if (scr_len_x < 640) {
+ return 6;
+ } else if (scr_len_x < 1280) {
+ return 8;
+ } else if (scr_len_x < 2560) {
+ return 10;
+ } else {
+ return 16;
+ }
+}
+
+
+int FilterGaussian::render(NRPixBlock **pb, Matrix const &trans)
+{
+ /* in holds the input pixblock */
+ NRPixBlock *in = pb[0];
+
+ /* Blur radius in screen units (pixels) */
+ int scr_len_x = _effect_area_scr_x(trans);
+ int scr_len_y = _effect_area_scr_y(trans);
+
+ // subsampling step; it depends on the radius, but somewhat nonlinearly, to make high zooms
+ // workable
+ int stepx = _effect_subsample_step(scr_len_x);
+ int stepx_l2 = _effect_subsample_step_log2(scr_len_x);
+ int stepy = _effect_subsample_step(scr_len_y);
+ int stepy_l2 = _effect_subsample_step_log2(scr_len_y);
+ int stepx2 = stepx >> 1;
+ int stepy2 = stepy >> 1;
+
+ /* buffer for x-axis blur */
+ NRPixBlock *bufx = new NRPixBlock;
+ /* buffer for y-axis blur */
+ NRPixBlock *bufy = new NRPixBlock;
+
+ // boundaries of the subsampled (smaller, unless step==1) buffers
+ int xd0 = (in->area.x0 >> stepx_l2);
+ int xd1 = (in->area.x1 >> stepx_l2) + 1;
+ int yd0 = (in->area.y0 >> stepy_l2);
+ int yd1 = (in->area.y1 >> stepy_l2) + 1;
+
+ // set up subsampled buffers
+ nr_pixblock_setup_fast(bufx, in->mode, xd0, yd0, xd1, yd1, true);
+ nr_pixblock_setup_fast(bufy, in->mode, xd0, yd0, xd1, yd1, true);
+
+ //mid->visible_area = in->visible_area;
+ //out->visible_area = in->visible_area;
+
+ /* Array for filter kernel, big enough to fit kernels for both X and Y
+ * direction kernel, one at time */
+ double kernel[_kernel_size(trans)];
+
+ /* 1. Blur in direction of X-axis, from in to bufx (they have different resolution)*/
+ _make_kernel(kernel, _deviation_x, trans.expansionX());
+
+ for ( int y = bufx->area.y0 ; y < bufx->area.y1; y++ ) {
+
+ // corresponding line in the source buffer
+ int in_line;
+ if ((y << stepy_l2) >= in->area.y1) {
+ in_line = (in->area.y1 - in->area.y0 - 1) * in->rs;
+ } else {
+ in_line = ((y << stepy_l2) - (in->area.y0)) * in->rs;
+ if (in_line < 0)
+ in_line = 0;
+ }
+
+ // current line in bufx
+ int bufx_line = (y - yd0) * bufx->rs;
+
+ int skipbuf[4] = {INT_MIN, INT_MIN, INT_MIN, INT_MIN};
+
+ for ( int x = bufx->area.x0 ; x < bufx->area.x1 ; x++ ) {
+
+ // for all bytes of the pixel
+ for ( int byte = 0 ; byte < NR_PIXBLOCK_BPP(in) ; byte++) {
+
+ if(skipbuf[byte] > x) continue;
+
+ double sum = 0;
+ int last_in = -1;
+ int different_count = 0;
+
+ // go over our point's neighborhood on x axis in the in buffer, with stepx increment
+ for ( int i = -scr_len_x ; i <= scr_len_x ; i += stepx ) {
+
+ // the pixel we're looking at
+ int x_in = (((x << stepx_l2) + i + stepx2) >> stepx_l2) << stepx_l2;
+
+ // distance from it to the current x,y
+ int dist = x_in - (x << stepx_l2);
+ if (dist < -scr_len_x)
+ dist = -scr_len_x;
+ if (dist > scr_len_x)
+ dist = scr_len_x;
+
+ if (x_in >= in->area.x1) {
+ x_in = (in->area.x1 - in->area.x0 - 1);
+ } else {
+ x_in = (x_in - in->area.x0);
+ if (x_in < 0)
+ x_in = 0;
+ }
+
+ // value at the pixel
+ unsigned char in_byte = NR_PIXBLOCK_PX(in)[in_line + NR_PIXBLOCK_BPP(in) * x_in + byte];
+
+ // is it the same as last one we saw?
+ if(in_byte != last_in) different_count++;
+ last_in = in_byte;
+
+ // sum pixels weighted by the kernel; multiply by stepx because we're skipping stepx pixels
+ sum += stepx * in_byte * kernel[scr_len_x + dist];
+ }
+
+ // store the result in bufx
+ NR_PIXBLOCK_PX(bufx)[bufx_line + NR_PIXBLOCK_BPP(bufx) * (x - xd0) + byte] = (unsigned char)sum;
+
+ // optimization: if there was no variation within this point's neighborhood,
+ // skip ahead while we keep seeing the same last_in byte:
+ // blurring flat color would not change it anyway
+ if (different_count <= 1) {
+ int pos = x + 1;
+ while(((pos << stepx_l2) + scr_len_x) < in->area.x1 &&
+ NR_PIXBLOCK_PX(in)[in_line + NR_PIXBLOCK_BPP(in) * ((pos << stepx_l2) + scr_len_x - in->area.x0) + byte] == last_in)
+ {
+ NR_PIXBLOCK_PX(bufx)[bufx_line + NR_PIXBLOCK_BPP(bufx) * (pos - xd0) + byte] = last_in;
+ pos++;
+ }
+ skipbuf[byte] = pos;
+ }
+ }
+ }
+ }
+
+
+ /* 2. Blur in direction of Y-axis, from bufx to bufy (they have the same resolution) */
+ _make_kernel(kernel, _deviation_y, trans.expansionY());
+
+ for ( int x = bufy->area.x0 ; x < bufy->area.x1; x++ ) {
+
+ int bufy_disp = NR_PIXBLOCK_BPP(bufy) * (x - xd0);
+ int bufx_disp = NR_PIXBLOCK_BPP(bufx) * (x - xd0);
+
+ int skipbuf[4] = {INT_MIN, INT_MIN, INT_MIN, INT_MIN};
+
+ for ( int y = bufy->area.y0; y < bufy->area.y1; y++ ) {
+
+ int bufy_line = (y - yd0) * bufy->rs;
+
+ for ( int byte = 0 ; byte < NR_PIXBLOCK_BPP(bufx) ; byte++) {
+
+ if (skipbuf[byte] > y) continue;
+
+ double sum = 0;
+ int last_in = -1;
+ int different_count = 0;
+
+ for ( int i = -scr_len_y ; i <= scr_len_y ; i += stepy ) {
+
+ int y_in = ((((y << stepy_l2) + i + stepy2) >> stepy_l2) - yd0);
+
+ int dist = ((y_in + yd0) << stepy_l2) - (y << stepy_l2);
+ if (dist < -scr_len_y)
+ dist = -scr_len_y;
+ if (dist > scr_len_y)
+ dist = scr_len_y;
+
+ if (y_in > (yd1 - yd0)) y_in = (yd1 - yd0);
+ if (y_in < 0) y_in = 0;
+
+ unsigned char in_byte = NR_PIXBLOCK_PX(bufx)[y_in * bufx->rs + NR_PIXBLOCK_BPP(bufx) * (x - xd0) + byte];
+ if(in_byte != last_in) different_count++;
+ last_in = in_byte;
+ sum += stepy * in_byte * kernel[scr_len_y + dist];
+ }
+
+ NR_PIXBLOCK_PX(bufy)[bufy_line + bufy_disp + byte] = (unsigned char)sum;
+
+ if (different_count <= 1) {
+ int pos = y + 1;
+ while((pos + (scr_len_y >> stepy_l2) + 1) < yd1 &&
+ NR_PIXBLOCK_PX(bufx)[(pos + (scr_len_y >> stepy_l2) + 1 - yd0) * bufx->rs + bufx_disp + byte] == last_in)
+ {
+ NR_PIXBLOCK_PX(bufy)[(pos - yd0) * bufy->rs + bufy_disp + byte] = last_in;
+ pos++;
+ }
+ skipbuf[byte] = pos;
+ }
+
+ }
+ }
+ }
+
+ // we don't need bufx anymore
+ nr_pixblock_release(bufx);
+ delete bufx;
+
+ // interpolation will need to divide by stepx * stepy
+ int divisor = stepx_l2 + stepy_l2;
+
+ // new buffer for the final output, same resolution as the in buffer
+ NRPixBlock *out = new NRPixBlock;
+ nr_pixblock_setup_fast(out, in->mode, in->area.x0, in->area.y0,
+ in->area.x1, in->area.y1, true);
+
+ for ( int y = yd0 ; y < yd1 - 1; y++ ) {
+ for ( int x = xd0 ; x < xd1 - 1; x++ ) {
+ for ( int byte = 0 ; byte < NR_PIXBLOCK_BPP(bufy) ; byte++) {
+
+ // get 4 values at the corners of the pixel from bufy
+ unsigned char a00 = NR_PIXBLOCK_PX(bufy)[((y - yd0) * bufy->rs) + NR_PIXBLOCK_BPP(bufy) * (x - xd0) + byte];
+ if (stepx == 1 && stepy == 1) { // if there was no subsampling, just use a00
+ NR_PIXBLOCK_PX(out)[((y - yd0) * out->rs) + NR_PIXBLOCK_BPP(out) * (x - xd0) + byte] = a00;
+ continue;
+ }
+ unsigned char a10 = NR_PIXBLOCK_PX(bufy)[((y - yd0) * bufy->rs) + NR_PIXBLOCK_BPP(bufy) * (x + 1 - xd0) + byte];
+ unsigned char a01 = NR_PIXBLOCK_PX(bufy)[((y + 1 - yd0) * bufy->rs) + NR_PIXBLOCK_BPP(bufy) * (x - xd0) + byte];
+ unsigned char a11 = NR_PIXBLOCK_PX(bufy)[((y + 1 - yd0) * bufy->rs) + NR_PIXBLOCK_BPP(bufy) * (x + 1 - xd0) + byte];
+
+ // iterate over the rectangle to be interpolated
+ for ( int yi = 0 ; yi < stepy; yi++ ) {
+ int iy = stepy - yi;
+ int y_out = (y << stepy_l2) + yi;
+ if ((y_out < out->area.y0) || (y_out >= out->area.y1))
+ continue;
+ int out_line = (y_out - out->area.y0) * out->rs;
+
+ for ( int xi = 0 ; xi < stepx; xi++ ) {
+ int ix = stepx - xi;
+ int x_out = (x << stepx_l2) + xi;
+ if ((x_out < out->area.x0) || (x_out >= out->area.x1))
+ continue;
+
+ // simple linear interpolation
+ int a = (a00*ix*iy + a10*xi*iy + a01*ix*yi + a11*xi*yi) >> divisor;
+
+ NR_PIXBLOCK_PX(out)[out_line + NR_PIXBLOCK_BPP(out) * (x_out - out->area.x0) + byte] = (unsigned char) a;
+ }
+ }
+ }
+ }
+ }
+
+ nr_pixblock_release(bufy);
+ delete bufy;
+
+ out->empty = FALSE;
+ pb[1] = out;
+
+ return 0;
+}
+
+int FilterGaussian::get_enlarge(Matrix const &trans)
+{
+ int area_x = _effect_area_scr_x(trans);
+ int area_y = _effect_area_scr_y(trans);
+ return _max(area_x, area_y);
+}
+
+void FilterGaussian::set_deviation(double deviation)
+{
+ if(isnormal(deviation) && deviation >= 0) {
+ _deviation_x = _deviation_y = deviation;
+ }
+}
+
+void FilterGaussian::set_deviation(double x, double y)
+{
+ if(isnormal(x) && x >= 0 && isnormal(y) && y >= 0) {
+ _deviation_x = x;
+ _deviation_y = y;
+ }
+}
+
+} /* namespace NR */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/display/nr-filter-gaussian.h b/src/display/nr-filter-gaussian.h
--- /dev/null
@@ -0,0 +1,83 @@
+#ifndef __NR_FILTER_GAUSSIAN_H__
+#define __NR_FILTER_GAUSSIAN_H__
+
+/*
+ * Gaussian blur renderer
+ *
+ * Author:
+ * Niko Kiirala <niko@kiirala.com>
+ *
+ * Copyright (C) 2006 Niko Kiirala
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "display/nr-filter-primitive.h"
+#include "libnr/nr-pixblock.h"
+#include "libnr/nr-matrix.h"
+
+namespace NR {
+
+class FilterGaussian : public FilterPrimitive {
+public:
+ FilterGaussian();
+ static FilterPrimitive *create();
+
+ virtual int render(NRPixBlock **pb, Matrix const &trans);
+ virtual int get_enlarge(Matrix const &m);
+
+ /**
+ * Set the standard deviation value for gaussian blur. Deviation along
+ * both axis is set to the provided value.
+ * Negative value, NaN and infinity are considered an error and no
+ * changes to filter state are made. If not set, default value of zero
+ * is used, which means the filter results in transparent black image.
+ */
+ void set_deviation(double deviation);
+ /**
+ * Set the standard deviation value for gaussian blur. First parameter
+ * sets the deviation alogn x-axis, second along y-axis.
+ * Negative value, NaN and infinity are considered an error and no
+ * changes to filter state are made. If not set, default value of zero
+ * is used, which means the filter results in transparent black image.
+ */
+ void set_deviation(double x, double y);
+
+private:
+ double _deviation_x;
+ double _deviation_y;
+
+ int _kernel_size(Matrix const &trans);
+ void _make_kernel(double *kernel, double deviation, double expansion);
+ int _effect_area_scr_x(Matrix const &trans);
+ int _effect_area_scr_y(Matrix const &trans);
+ int _effect_subsample_step(int scr_len_x);
+ int _effect_subsample_step_log2(int scr_len_x);
+
+ inline int _min(int const a, int const b)
+ {
+ return ((a < b) ? a : b);
+ }
+ inline int _max(int const a, int const b)
+ {
+ return ((a > b) ? a : b);
+ }
+};
+
+
+} /* namespace NR */
+
+
+
+
+#endif /* __NR_FILTER_GAUSSIAN_H__ */
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/display/nr-filter-primitive.cpp b/src/display/nr-filter-primitive.cpp
--- /dev/null
@@ -0,0 +1,70 @@
+#define __NR_FILTER_PRIMITIVE_CPP__
+
+/*
+ * SVG filters rendering
+ *
+ * Author:
+ * Niko Kiirala <niko@kiirala.com>
+ *
+ * Copyright (C) 2006 Niko Kiirala
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "display/nr-filter-primitive.h"
+#include "display/nr-filter-types.h"
+#include "libnr/nr-pixblock.h"
+#include "svg/svg-length.h"
+
+namespace NR {
+
+FilterPrimitive::FilterPrimitive()
+{
+ _input = NR_FILTER_SLOT_NOT_SET;
+ _output = NR_FILTER_SLOT_NOT_SET;
+
+ _region_x.set(SVGLength::PERCENT, 0, 0);
+ _region_y.set(SVGLength::PERCENT, 0, 0);
+ _region_width.set(SVGLength::PERCENT, 100, 0);
+ _region_height.set(SVGLength::PERCENT, 100, 0);
+}
+
+int FilterPrimitive::render(NRPixBlock **pb, NRMatrix const *trans) {
+ if(trans) {
+ return this->render(pb, *trans);
+ } else {
+ Matrix tmp;
+ tmp.set_identity();
+ return this->render(pb, tmp);
+ }
+}
+
+int FilterPrimitive::get_enlarge(Matrix const &m)
+{
+ return 0;
+}
+
+void FilterPrimitive::set_input(int slot) {
+ set_input(0, slot);
+}
+
+void FilterPrimitive::set_input(int input, int slot) {
+ if (slot == 0) _input = slot;
+}
+
+void FilterPrimitive::set_output(int slot) {
+ if (slot >= 0) _output = slot;
+}
+
+} /* namespace NR */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/display/nr-filter-primitive.h b/src/display/nr-filter-primitive.h
--- /dev/null
@@ -0,0 +1,108 @@
+#ifndef __NR_FILTER_PRIMITIVE_H__
+#define __NR_FILTER_PRIMITIVE_H__
+
+/*
+ * SVG filters rendering
+ *
+ * Author:
+ * Niko Kiirala <niko@kiirala.com>
+ *
+ * Copyright (C) 2006 Niko Kiirala
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "libnr/nr-pixblock.h"
+#include "libnr/nr-matrix.h"
+#include "svg/svg-length.h"
+
+namespace NR {
+
+class FilterPrimitive {
+public:
+ FilterPrimitive();
+ int render(NRPixBlock **pb, NRMatrix const *trans);
+ virtual int render(NRPixBlock **pb, Matrix const &trans) = 0;
+ virtual int get_enlarge(Matrix const &m);
+
+ /**
+ * Sets the input slot number 'slot' to be used as input in rendering
+ * filter primitive 'primitive'
+ * For filter primitive types accepting more than one input, this sets the
+ * first input.
+ * If any of the required input slots is not set, the output of previous
+ * filter primitive is used, or SourceGraphic if this is the first
+ * primitive for this filter.
+ */
+ virtual void set_input(int slot);
+
+ /**
+ * Sets the input slot number 'slot' to be user as input number 'input' in
+ * rendering filter primitive 'primitive'
+ * First input for a filter primitive is number 0. For primitives with
+ * attributes 'in' and 'in2', these are numbered 0 and 1, respectively.
+ * If any of required input slots for a filter is not set, the output of
+ * previous filter primitive is used, or SourceGraphic if this is the first
+ * filter primitive for this filter.
+ */
+ virtual void set_input(int input, int slot);
+
+ /**
+ * Sets the slot number 'slot' to be used as output from filter primitive
+ * 'primitive'
+ * If output slot for a filter element is not set, one of the unused image
+ * slots is used.
+ * It is an error to specify a pre-defined slot as 'slot'. Such call does
+ * not have any effect to the state of filter or its primitives.
+ */
+ virtual void set_output(int slot);
+
+ void set_x(SVGLength &length);
+ void set_y(SVGLength &length);
+ void set_width(SVGLength &length);
+ void set_height(SVGLength &length);
+
+ /**
+ * Sets the filter primitive subregion. Passing an unset length
+ * (length._set == false) as any parameter results in that parameter
+ * not being changed.
+ * Filter primitive will not hold any references to the passed
+ * SVGLength object after function returns.
+ * If any of the parameters does not get set the default value, as
+ * defined in SVG standard, for that parameter is used instead.
+ */
+ void set_region(SVGLength &x, SVGLength &y,
+ SVGLength &width, SVGLength &height);
+
+ /**
+ * Resets the filter primitive subregion to its default value
+ */
+ void reset_region();
+
+protected:
+ int _input;
+ int _output;
+
+ SVGLength _region_x;
+ SVGLength _region_y;
+ SVGLength _region_width;
+ SVGLength _region_height;
+};
+
+
+} /* namespace NR */
+
+
+
+
+#endif /* __NR_FILTER_PRIMITIVE_H__ */
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/display/nr-filter-types.h b/src/display/nr-filter-types.h
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef __NR_FILTER_TYPES_H__
+#define __NR_FILTER_TYPES_H__
+
+namespace NR {
+
+enum FilterPrimitiveType {
+ NR_FILTER_BLEND,
+ NR_FILTER_COLORMATRIX,
+ NR_FILTER_COMPONENTTRANSFER,
+ NR_FILTER_COMPOSITE,
+ NR_FILTER_CONVOLVEMATRIX,
+ NR_FILTER_DIFFUSELIGHTING,
+ NR_FILTER_DISPLACEMENTMAP,
+ NR_FILTER_FLOOD,
+ NR_FILTER_GAUSSIANBLUR,
+ NR_FILTER_IMAGE,
+ NR_FILTER_MERGE,
+ NR_FILTER_MORPHOLOGY,
+ NR_FILTER_OFFSET,
+ NR_FILTER_SPECULARLIGHTING,
+ NR_FILTER_TILE,
+ NR_FILTER_TURBULENCE,
+ NR_FILTER_ENDPRIMITIVETYPE // This must be last
+};
+//const int Filter::_filter_primitive_type_count = 16;
+
+enum {
+ NR_FILTER_SLOT_NOT_SET = -1,
+ NR_FILTER_SOURCEGRAPHIC = -2,
+ NR_FILTER_SOURCEALPHA = -3,
+ NR_FILTER_BACKGROUNDIMAGE = -4,
+ NR_FILTER_BACKGROUNDAPLHA = -5,
+ NR_FILTER_FILLPAINT = -6,
+ NR_FILTER_SOURCEPAINT = -7
+};
+
+} /* namespace NR */
+
+#endif // __NR_FILTER_TYPES_H__
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp
--- /dev/null
@@ -0,0 +1,223 @@
+#define __NR_FILTER_CPP__
+
+/*
+ * SVG filters rendering
+ *
+ * Author:
+ * Niko Kiirala <niko@kiirala.com>
+ *
+ * Copyright (C) 2006 Niko Kiirala
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "display/nr-filter.h"
+#include "display/nr-filter-primitive.h"
+#include "display/nr-filter-gaussian.h"
+
+#include "display/nr-arena-item.h"
+#include "libnr/nr-pixblock.h"
+#include "libnr/nr-blit.h"
+#include "svg/svg-length.h"
+#include "sp-filter-units.h"
+
+//#include "display/nr-arena-shape.h"
+
+namespace NR {
+
+Filter::Filter()
+{
+ _primitive_count = 1;
+ _primitive_table_size = 1;
+ _primitive = new FilterPrimitive*[1];
+ _primitive[0] = new FilterGaussian;
+ _common_init();
+}
+
+Filter::Filter(int n)
+{
+ _primitive_count = 0;
+ _primitive_table_size = n;
+ _primitive = new FilterPrimitive*[n];
+ for ( int i = 0 ; i < n ; i++ ) {
+ _primitive[i] = NULL;
+ }
+ _common_init();
+}
+
+void Filter::_common_init() {
+ _slot_count = 1;
+ _output_slot = -1;
+
+ _region_x.set(SVGLength::PERCENT, -10, 0);
+ _region_y.set(SVGLength::PERCENT, -10, 0);
+ _region_width.set(SVGLength::PERCENT, 120, 0);
+ _region_height.set(SVGLength::PERCENT, 120, 0);
+
+ _x_pixels = -1.0;
+ _y_pixels = -1.0;
+
+ _filter_units = SP_FILTER_UNITS_OBJECTBOUNDINGBOX;
+ _primitive_units = SP_FILTER_UNITS_USERSPACEONUSE;
+}
+
+Filter::~Filter()
+{
+ clear_primitives();
+ delete[] _primitive;
+}
+
+
+int Filter::render(NRArenaItem const *item, NRPixBlock *pb)
+{
+ NRPixBlock *slot[2];
+ slot[0] = pb;
+ slot[1] = NULL;
+
+ _primitive[0]->render(slot, *item->ctm);
+
+
+ int size = (slot[0]->area.x1 - slot[0]->area.x0)
+ * (slot[0]->area.y1 - slot[0]->area.y0)
+ * NR_PIXBLOCK_BPP(slot[0]);
+ memset(NR_PIXBLOCK_PX(slot[0]), 0, size);
+
+ nr_blit_pixblock_pixblock(slot[0], slot[1]);
+
+ slot[0]->visible_area = slot[0]->area;
+
+ nr_pixblock_release(slot[1]);
+
+ return 0;
+}
+
+int Filter::get_enlarge(Matrix const &m)
+{
+ int enlarge = 0;
+ for ( int i = 0 ; i < _primitive_count ; i++ ) {
+ if(_primitive[i]) enlarge += _primitive[i]->get_enlarge(m);
+ }
+ return enlarge;
+}
+
+void Filter::bbox_enlarge(NRRectL &bbox)
+{
+ int len_x = bbox.x1 - bbox.x0;
+ int len_y = bbox.y1 - bbox.y0;
+ int enlarge_x = (int)std::ceil(len_x / 10.0);
+ int enlarge_y = (int)std::ceil(len_y / 10.0);
+ bbox.x0 -= enlarge_x;
+ bbox.x1 += enlarge_x;
+ bbox.y0 -= enlarge_y;
+ bbox.y1 += enlarge_y;
+}
+
+typedef FilterPrimitive*(*FilterConstructor)();
+static FilterConstructor _constructor[NR_FILTER_ENDPRIMITIVETYPE];
+
+void Filter::_create_constructor_table()
+{
+ static bool created = false;
+ if(created) return;
+
+ /* Filter effects not yet implemented are set to NULL */
+ _constructor[NR_FILTER_BLEND] = NULL;
+ _constructor[NR_FILTER_COLORMATRIX] = NULL;
+ _constructor[NR_FILTER_COMPONENTTRANSFER] = NULL;
+ _constructor[NR_FILTER_COMPOSITE] = NULL;
+ _constructor[NR_FILTER_CONVOLVEMATRIX] = NULL;
+ _constructor[NR_FILTER_DIFFUSELIGHTING] = NULL;
+ _constructor[NR_FILTER_DISPLACEMENTMAP] = NULL;
+ _constructor[NR_FILTER_FLOOD] = NULL;
+ _constructor[NR_FILTER_GAUSSIANBLUR] = &FilterGaussian::create;
+ _constructor[NR_FILTER_IMAGE] = NULL;
+ _constructor[NR_FILTER_MERGE] = NULL;
+ _constructor[NR_FILTER_MORPHOLOGY] = NULL;
+ _constructor[NR_FILTER_OFFSET] = NULL;
+ _constructor[NR_FILTER_SPECULARLIGHTING] = NULL;
+ _constructor[NR_FILTER_TILE] = NULL;
+ _constructor[NR_FILTER_TURBULENCE] = NULL;
+}
+
+void Filter::_enlarge_primitive_table() {
+ FilterPrimitive **new_tbl = new FilterPrimitive*[_primitive_table_size * 2];
+ for (int i = 0 ; i < _primitive_count ; i++) {
+ new_tbl[i] = _primitive[i];
+ }
+ _primitive_table_size *= 2;
+ for (int i = _primitive_count ; i < _primitive_table_size ; i++) {
+ new_tbl[i] = NULL;
+ }
+ delete[] _primitive;
+ _primitive = new_tbl;
+}
+
+FilterPrimitive *Filter::add_primitive(FilterPrimitiveType type)
+{
+ _create_constructor_table();
+
+ // Check that we can create a new filter of specified type
+ if (type < 0 || type >= NR_FILTER_ENDPRIMITIVETYPE)
+ return NULL;
+ if (!_constructor[type]) return NULL;
+ FilterPrimitive *created = _constructor[type]();
+
+ // If there is no space for new filter primitive, enlarge the table
+ if (_primitive_count >= _primitive_table_size) {
+ _enlarge_primitive_table();
+ }
+
+ _primitive[_primitive_count] = created;
+ return created;
+}
+
+FilterPrimitive *Filter::replace_primitive(FilterPrimitive *target, FilterPrimitiveType type)
+{
+ _create_constructor_table();
+
+ // Check that target is valid primitive inside this filter
+ int place = -1;
+ for (int i = 0 ; i < _primitive_count ; i++) {
+ if (target == _primitive[i]) {
+ place = i;
+ break;
+ }
+ }
+ if (place < 0) return NULL;
+
+ // Check that we can create a new filter of specified type
+ if (type < 0 || type >= NR_FILTER_ENDPRIMITIVETYPE)
+ return NULL;
+ if (!_constructor[type]) return NULL;
+ FilterPrimitive *created = _constructor[type]();
+
+ // If there is no space for new filter primitive, enlarge the table
+ if (_primitive_count >= _primitive_table_size) {
+ _enlarge_primitive_table();
+ }
+
+ delete target;
+ _primitive[place] = created;
+ return created;
+}
+
+void Filter::clear_primitives()
+{
+ for (int i = 0 ; i < _primitive_count ; i++) {
+ if (_primitive[i]) delete _primitive[i];
+ }
+ _primitive_count = 0;
+}
+
+} /* namespace NR */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/display/nr-filter.h b/src/display/nr-filter.h
--- /dev/null
+++ b/src/display/nr-filter.h
@@ -0,0 +1,204 @@
+#ifndef __NR_FILTER_H__
+#define __NR_FILTER_H__
+
+/*
+ * SVG filters rendering
+ *
+ * Author:
+ * Niko Kiirala <niko@kiirala.com>
+ *
+ * Copyright (C) 2006 Niko Kiirala
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "display/nr-arena-item.h"
+#include "display/nr-filter-primitive.h"
+#include "display/nr-filter-types.h"
+#include "libnr/nr-pixblock.h"
+#include "libnr/nr-matrix.h"
+#include "libnr/nr-rect.h"
+#include "svg/svg-length.h"
+#include "sp-filter-units.h"
+#include "gc-managed.h"
+
+namespace NR {
+
+class Filter : public Inkscape::GC::Managed<> {
+public:
+ int render(NRArenaItem const *item, NRPixBlock *pb);
+
+ /**
+ * Creates a new filter primitive under this filter object.
+ * New primitive is placed so that it will be executed after all filter
+ * primitives defined beforehand for this filter object.
+ * Should this filter not have enough space for a new primitive, the filter
+ * is enlarged to accomodate the new filter element. It may be enlarged by
+ * more that one element.
+ * Returns a pointer to the filter primitive created.
+ * Returns NULL, if type is not valid filter primitive type or filter
+ * primitive of such type cannot be created.
+ */
+ FilterPrimitive *add_primitive(FilterPrimitiveType type);
+ /**
+ * Removes all filter primitives from this filter.
+ * All pointers to filter primitives inside this filter should be
+ * considered invalid after calling this function.
+ */
+ void clear_primitives();
+ /**
+ * Replaces filter primitive pointed by 'target' with a new filter
+ * primitive of type 'type'
+ * If 'target' does not correspond to any primitive inside this filter OR
+ * 'type' is not a valid filter primitive type OR
+ * filter primitive of such type cannot be created,
+ * this function returns NULL and doesn't change the internal state of this
+ * filter.
+ * Otherwise, a new filter primitive is created. Any pointers to filter
+ * primitive 'target' should be considered invalid. A pointer to the
+ * newly created primitive is returned.
+ */
+ FilterPrimitive *replace_primitive(FilterPrimitive *primitive,
+ FilterPrimitiveType type);
+
+ /**
+ * Sets the slot number 'slot' to be used as result from this filter.
+ * If output is not set, the output from last filter primitive is used as
+ * output from the filter.
+ * It is an error to specify a pre-defined slot as 'slot'. Such call does
+ * not have any effect to the state of filter or its primitives.
+ */
+ void set_output(int slot);
+
+ void set_x(SVGLength &lenght);
+ void set_y(SVGLength &length);
+ void set_width(SVGLength &length);
+ void set_height(SVGLength &length);
+
+ /**
+ * Sets the filter effects region.
+ * Passing an unset length (length._set == false) as any of the parameters
+ * results in that parameter not being changed.
+ * Filter will not hold any references to the passed SVGLength object after
+ * function returns.
+ * If any of these parameters does not get set, the default value, as
+ * defined in SVG standard, for that parameter is used instead.
+ */
+ void set_region(SVGLength &x, SVGLength &y,
+ SVGLength &width, SVGLength &height);
+
+ /**
+ * Resets the filter effects region to its default value as defined
+ * in SVG standard.
+ */
+ void reset_region();
+
+ /**
+ * Sets the width of intermediate images in pixels. If not set, suitable
+ * resolution is determined automatically. If x_pixels is less than zero,
+ * calling this function results in no changes to filter state.
+ */
+ void set_resolution(double x_pixels);
+
+ /**
+ * Sets the width and height of intermediate images in pixels. If not set,
+ * suitable resolution is determined automatically. If either parameter is
+ * less than zero, calling this function results in no changes to filter
+ * state.
+ */
+ void set_resolution(double x_pixels, double y_pixels);
+
+ /**
+ * Resets the filter resolution to its default value, i.e. automatically
+ * determined.
+ */
+ void reset_resolution();
+
+ /**
+ * Set the filterUnits-property. If not set, the default value of
+ * objectBoundingBox is used. If the parameter value is not a
+ * valid enumeration value from SPFilterUnits, no changes to filter state
+ * are made.
+ */
+ void set_filter_units(SPFilterUnits unit);
+
+ /**
+ * Set the primitiveUnits-properterty. If not set, the default value of
+ * userSpaceOnUseis used. If the parameter value is not a valid
+ * enumeration value from SPFilterUnits, no changes to filter state
+ * are made.
+ */
+ void set_primitive_units(SPFilterUnits unit);
+
+ /**
+ * Returns the amount of pixels the rendering area should be enlarged
+ * to prevent visual artefacts when filter needs to read pixels that
+ * are outside its output area (e.g. gaussian blur)
+ */
+ int get_enlarge(Matrix const &m);
+ /**
+ * Given an object bounding box, this function enlarges it so that
+ * it contains the filter effect area.
+ */
+ void bbox_enlarge(NRRectL &bbox);
+
+ /** Creates a new filter with space for one filter element */
+ Filter();
+ /**
+ * Creates a new filter with space for n filter elements. If number of
+ * filter elements is known beforehand, it's better to use this
+ * constructor.
+ */
+ Filter(int n);
+ /** Destroys the filter and all its primitives */
+ ~Filter();
+
+private:
+ int _primitive_count;
+ int _primitive_table_size;
+
+ /** Amount of image slots used, when this filter was rendered last time */
+ int _slot_count;
+
+ /** Image slot, from which filter output should be read.
+ * Negative values mean 'not set' */
+ int _output_slot;
+
+ SVGLength _region_x;
+ SVGLength _region_y;
+ SVGLength _region_width;
+ SVGLength _region_height;
+
+ /* x- and y-resolutions for filter rendering.
+ * Negative values mean 'not set'.
+ * If _y_pixels is set, _x_pixels should be set, too. */
+ double _x_pixels;
+ double _y_pixels;
+
+ SPFilterUnits _filter_units;
+ SPFilterUnits _primitive_units;
+
+ FilterPrimitive ** _primitive;
+
+ void _create_constructor_table();
+ void _enlarge_primitive_table();
+ void _common_init();
+};
+
+
+} /* namespace NR */
+
+
+
+
+#endif /* __NR_FILTER_H__ */
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/libnr/nr-rect.cpp b/src/libnr/nr-rect.cpp
index 0a8287bdea1b77b73cd83122d9639b0ae6bde8f8..6d881e7b0a75fac20b9740d84bb8862c2b521d8c 100644 (file)
--- a/src/libnr/nr-rect.cpp
+++ b/src/libnr/nr-rect.cpp
return nr_rect_d_matrix_transform(d, s, *m);
}
+/** Enlarges the rectangle given amount of pixels to all directions */
+NRRectL *
+nr_rect_l_enlarge(NRRectL *d, int amount)
+{
+ d->x0 -= amount;
+ d->y0 -= amount;
+ d->x1 += amount;
+ d->y1 += amount;
+ return d;
+}
+
namespace NR {
Rect::Rect(const Point &p0, const Point &p1)
diff --git a/src/libnr/nr-rect.h b/src/libnr/nr-rect.h
index 767eab90243fdde17bc77723453f1506a3ba46d8..ab78c1651c53372eb9005d55520ba323c5929c58 100644 (file)
--- a/src/libnr/nr-rect.h
+++ b/src/libnr/nr-rect.h
NRRect *nr_rect_d_matrix_transform(NRRect *d, NRRect const *s, NR::Matrix const &m);
NRRect *nr_rect_d_matrix_transform(NRRect *d, NRRect const *s, NRMatrix const *m);
+NRRectL *nr_rect_l_enlarge(NRRectL *d, int amount);
namespace NR {
diff --git a/src/number-opt-number.h b/src/number-opt-number.h
--- /dev/null
+++ b/src/number-opt-number.h
@@ -0,0 +1,108 @@
+#ifndef SEEN_NUMBER_OPT_NUMBER_H
+#define SEEN_NUMBER_OPT_NUMBER_H
+
+/** \file
+ * <number-opt-number> implementation.
+ */
+/*
+ * Authors:
+ * Hugo Rodrigues <haa.rodrigues@gmail.com>
+ *
+ * Copyright (C) 2006 Hugo Rodrigues
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <glib.h>
+#include <glib/gprintf.h>
+//todo: use glib instead of stdlib
+#include <stdlib.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+class NumberOptNumber {
+
+public:
+
+ gfloat number;
+
+ gfloat optNumber;
+
+ guint _set : 1;
+
+ guint optNumber_set : 1;
+
+ NumberOptNumber()
+ {
+ number = 0.0;
+ optNumber = 0.0;
+
+ _set = FALSE;
+ optNumber_set = FALSE;
+ }
+
+ gfloat getNumber()
+ { return number; }
+
+ gfloat getOptNumber()
+ { return optNumber; }
+
+ gchar *getValueString(gchar *str)
+ {
+ if( _set )
+ {
+
+ if( optNumber_set )
+ {
+ g_sprintf(str, "%lf %lf", number, optNumber);
+ }
+ else {
+ g_sprintf(str, "%lf", number);
+ }
+ }
+ return str;
+ }
+
+ void set(gchar const *str)
+ {
+ if(!str)
+ return;
+
+ gchar **values = g_strsplit(str, " ", 2);
+
+ if( values[0] != NULL )
+ {
+ number = strtof(values[0], NULL);
+ _set = TRUE;
+
+ if( values[1] != NULL )
+ {
+ // optNumber = g_ascii_strtod(values[1], NULL);
+ optNumber = strtof(values[1], NULL);
+ optNumber_set = TRUE;
+ }
+ else
+ optNumber_set = FALSE;
+ }
+ else {
+ _set = FALSE;
+ optNumber_set = FALSE;
+ }
+ }
+
+};
+
+#endif /* !SEEN_NUMBER_OPT_NUMBER_H */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/sp-filter-fns.h b/src/sp-filter-fns.h
--- /dev/null
+++ b/src/sp-filter-fns.h
@@ -0,0 +1,49 @@
+#ifndef SEEN_SP_FILTER_FNS_H
+#define SEEN_SP_FILTER_FNS_H
+
+/** \file
+ * Macros and fn declarations related to filters.
+ */
+
+#include <glib/gtypes.h>
+#include <glib-object.h>
+#include "libnr/nr-forward.h"
+#include "sp-filter-units.h"
+
+class SPFilter;
+
+namespace Inkscape {
+namespace XML {
+class Node;
+}
+}
+
+#define SP_TYPE_FILTER (sp_filter_get_type())
+#define SP_FILTER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FILTER, SPFilter))
+#define SP_FILTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FILTER, SPFilterClass))
+#define SP_IS_FILTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FILTER))
+#define SP_IS_FILTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FILTER))
+
+#define SP_FILTER_FILTER_UNITS(f) (SP_FILTER(f)->filterUnits)
+#define SP_FILTER_PRIMITIVE_UNITS(f) (SP_FILTER(f)->primitiveUnits)
+
+GType sp_filter_get_type();
+
+//need to define function
+void sp_filter_set_filter_units(SPFilter *filter, SPFilterUnits filterUnits);
+//need to define function
+void sp_filter_set_primitive_units(SPFilter *filter, SPFilterUnits filterUnits);
+
+
+#endif /* !SEEN_SP_FILTER_FNS_H */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/sp-filter-reference.cpp b/src/sp-filter-reference.cpp
--- /dev/null
@@ -0,0 +1,21 @@
+#include "sp-filter-reference.h"
+
+bool
+SPFilterReference::_acceptObject(SPObject *obj) const
+{
+ return SP_IS_FILTER(obj);
+ /* effic: Don't bother making this an inline function: _acceptObject is a virtual function,
+ typically called from a context where the runtime type is not known at compile time. */
+}
+
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/sp-filter-reference.h b/src/sp-filter-reference.h
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef SEEN_SP_FILTER_REFERENCE_H
+#define SEEN_SP_FILTER_REFERENCE_H
+
+#include "uri-references.h"
+#include "sp-filter-fns.h"
+class SPObject;
+
+class SPFilterReference : public Inkscape::URIReference {
+public:
+ SPFilterReference(SPObject *obj) : URIReference(obj) {}
+
+ SPFilter *getObject() const {
+ return (SPFilter *)URIReference::getObject();
+ }
+
+protected:
+ virtual bool _acceptObject(SPObject *obj) const;
+};
+
+
+#endif /* !SEEN_SP_FILTER_REFERENCE_H */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/sp-filter-units.h b/src/sp-filter-units.h
--- /dev/null
+++ b/src/sp-filter-units.h
@@ -0,0 +1,21 @@
+#ifndef SEEN_SP_FILTER_UNITS_H
+#define SEEN_SP_FILTER_UNITS_H
+
+enum SPFilterUnits {
+ SP_FILTER_UNITS_OBJECTBOUNDINGBOX,
+ SP_FILTER_UNITS_USERSPACEONUSE
+};
+
+
+#endif /* !SEEN_SP_GRADIENT_UNITS_H */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/sp-filter.cpp b/src/sp-filter.cpp
--- /dev/null
+++ b/src/sp-filter.cpp
@@ -0,0 +1,424 @@
+#define __SP_FILTER_CPP__
+
+/** \file
+ * SVG <filter> implementation.
+ */
+/*
+ * Authors:
+ * Hugo Rodrigues <haa.rodrigues@gmail.com>
+ *
+ * Copyright (C) 2006 Hugo Rodrigues
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "attributes.h"
+#include "document.h"
+#include "sp-filter.h"
+#include "sp-filter-reference.h"
+#include "uri.h"
+#include "xml/repr.h"
+
+#define SP_MACROS_SILENT
+#include "macros.h"
+
+#define DEBUG_FILTER
+#ifdef DEBUG_FILTER
+# define debug(f, a...) { g_print("%s(%d) %s:", \
+ __FILE__,__LINE__,__FUNCTION__); \
+ g_print(f, ## a); \
+ g_print("\n"); \
+ }
+#else
+# define debug(f, a...) /**/
+#endif
+
+
+/*
+ * For debugging purposes only
+ */
+void printfilter(SPFilter *filter)
+{
+ if(filter->filterUnits==SP_FILTER_UNITS_USERSPACEONUSE)
+ g_print("filterUnits=SP_FILTER_UNITS_USERSPACEONUSE\n");
+ else if(filter->filterUnits==SP_FILTER_UNITS_OBJECTBOUNDINGBOX)
+ g_print("filterUnits=SP_FILTER_UNITS_OBJECTBOUNDINGBOX\n");
+ else
+ g_print("filterUnits=UNKNOWN!!!\n");
+
+ if(filter->primitiveUnits==SP_FILTER_UNITS_USERSPACEONUSE)
+ g_print("primitiveUnits=SP_FILTER_UNITS_USERSPACEONUSE\n");
+ else if(filter->primitiveUnits==SP_FILTER_UNITS_OBJECTBOUNDINGBOX)
+ g_print("primitiveUnits=SP_FILTER_UNITS_OBJECTBOUNDINGBOX\n");
+ else
+ g_print("primitiveUnits=UNKNOWN!!!\n");
+
+//TODO: print X, Y, W and H units
+ g_print("x=%lf\n", filter->x.computed);
+ g_print("y=%lf\n", filter->y.computed);
+ g_print("width=%lf\n", filter->width.computed);
+ g_print("height=%lf\n", filter->height.computed);
+ g_print("filterRes=(%lf %lf)\n", filter->filterRes.getNumber(), filter->filterRes.getOptNumber());
+
+}
+
+
+
+/* Filter base class */
+
+static void sp_filter_class_init(SPFilterClass *klass);
+static void sp_filter_init(SPFilter *filter);
+
+static void sp_filter_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr);
+static void sp_filter_release(SPObject *object);
+static void sp_filter_set(SPObject *object, unsigned int key, gchar const *value);
+static void sp_filter_update(SPObject *object, SPCtx *ctx, guint flags);
+static Inkscape::XML::Node *sp_filter_write(SPObject *object, Inkscape::XML::Node *repr, guint flags);
+
+static void filter_ref_changed(SPObject *old_ref, SPObject *ref, SPFilter *filter);
+static void filter_ref_modified(SPObject *href, SPFilter *filter);
+
+static SPObjectClass *filter_parent_class;
+
+GType
+sp_filter_get_type()
+{
+ static GType filter_type = 0;
+
+ if (!filter_type) {
+ GTypeInfo filter_info = {
+ sizeof(SPFilterClass),
+ NULL, NULL,
+ (GClassInitFunc) sp_filter_class_init,
+ NULL, NULL,
+ sizeof(SPFilter),
+ 16,
+ (GInstanceInitFunc) sp_filter_init,
+ NULL, /* value_table */
+ };
+ filter_type = g_type_register_static(SP_TYPE_OBJECT, "SPFilter", &filter_info, (GTypeFlags)0);
+ }
+ return filter_type;
+}
+
+static void
+sp_filter_class_init(SPFilterClass *klass)
+{
+
+ SPObjectClass *sp_object_class = (SPObjectClass *)klass;
+
+ filter_parent_class = (SPObjectClass*)g_type_class_peek_parent(klass);
+
+ sp_object_class->build = sp_filter_build;
+ sp_object_class->release = sp_filter_release;
+ sp_object_class->write = sp_filter_write;
+ sp_object_class->set = sp_filter_set;
+ sp_object_class->update = sp_filter_update;
+}
+
+static void
+sp_filter_init(SPFilter *filter)
+{
+ filter->href = new SPFilterReference(SP_OBJECT(filter));
+ filter->href->changedSignal().connect(sigc::bind(sigc::ptr_fun(filter_ref_changed), filter));
+
+ filter->x = 0;
+ filter->y = 0;
+ filter->width = 0;
+ filter->height = 0;
+
+ filter->filterUnits = SP_FILTER_UNITS_OBJECTBOUNDINGBOX;
+ filter->primitiveUnits = SP_FILTER_UNITS_OBJECTBOUNDINGBOX;
+ filter->filterUnits_set = FALSE;
+ filter->primitiveUnits_set = FALSE;
+
+}
+
+/**
+ * Reads the Inkscape::XML::Node, and initializes SPFilter variables. For this to get called,
+ * our name must be associated with a repr via "sp_object_type_register". Best done through
+ * sp-object-repr.cpp's repr_name_entries array.
+ */
+static void
+sp_filter_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr)
+{
+ debug("0x%p",object);
+ if (((SPObjectClass *) filter_parent_class)->build) {
+ ((SPObjectClass *) filter_parent_class)->build(object, document, repr);
+ }
+
+ //Read values of key attributes from XML nodes into object.
+ sp_object_read_attr(object, "filterUnits");
+ sp_object_read_attr(object, "primitiveUnits");
+ sp_object_read_attr(object, "x");
+ sp_object_read_attr(object, "y");
+ sp_object_read_attr(object, "width");
+ sp_object_read_attr(object, "height");
+ sp_object_read_attr(object, "filterRes");
+ sp_object_read_attr(object, "xlink:href");
+
+//is this necessary?
+ sp_document_add_resource(document, "filter", object);
+}
+
+/**
+ * Drops any allocated memory.
+ */
+static void
+sp_filter_release(SPObject *object)
+{
+ debug("0x%p",object);
+ SPFilter *filter = SP_FILTER(object);
+
+ if (SP_OBJECT_DOCUMENT(object)) {
+ /* Unregister ourselves */
+ sp_document_remove_resource(SP_OBJECT_DOCUMENT(object), "filter", SP_OBJECT(object));
+ }
+
+//TODO: release resources here
+
+ //release href
+ if (filter->href) {
+ if (filter->href->getObject()) {
+ sp_signal_disconnect_by_data(filter->href->getObject(), filter);
+ }
+ filter->href->detach();
+ delete filter->href;
+ filter->href = NULL;
+ }
+
+ if (((SPObjectClass *) filter_parent_class)->release)
+ ((SPObjectClass *) filter_parent_class)->release(object);
+}
+
+/**
+ * Sets a specific value in the SPFilter.
+ */
+static void
+sp_filter_set(SPObject *object, unsigned int key, gchar const *value)
+{
+ debug("0x%p %s(%u): '%s'",object,
+ sp_attribute_name(key),key,value);
+ SPFilter *filter = SP_FILTER(object);
+
+ switch (key) {
+ case SP_ATTR_FILTERUNITS:
+ if (value) {
+ if (!strcmp(value, "userSpaceOnUse")) {
+ filter->filterUnits = SP_FILTER_UNITS_USERSPACEONUSE;
+ } else {
+ filter->filterUnits = SP_FILTER_UNITS_OBJECTBOUNDINGBOX;
+ }
+ filter->filterUnits_set = TRUE;
+ } else {
+ filter->filterUnits = SP_FILTER_UNITS_OBJECTBOUNDINGBOX;
+ filter->filterUnits_set = FALSE;
+ }
+ object->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ break;
+ case SP_ATTR_PRIMITIVEUNITS:
+ if (value) {
+ if (!strcmp(value, "userSpaceOnUse")) {
+ filter->primitiveUnits = SP_FILTER_UNITS_USERSPACEONUSE;
+ } else {
+ filter->primitiveUnits = SP_FILTER_UNITS_OBJECTBOUNDINGBOX;
+ }
+ filter->primitiveUnits_set = TRUE;
+ } else {
+ filter->primitiveUnits = SP_FILTER_UNITS_OBJECTBOUNDINGBOX;
+ filter->primitiveUnits_set = FALSE;
+ }
+ object->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ break;
+ case SP_ATTR_X:
+ filter->x.readOrUnset(value);
+ object->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ break;
+ case SP_ATTR_Y:
+ filter->y.readOrUnset(value);
+ object->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ break;
+ case SP_ATTR_WIDTH:
+ filter->width.readOrUnset(value);
+ object->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ break;
+ case SP_ATTR_HEIGHT:
+ filter->height.readOrUnset(value);
+ object->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ break;
+ case SP_ATTR_FILTERRES:
+ filter->filterRes.set(value);
+ break;
+ case SP_ATTR_XLINK_HREF:
+ if (value) {
+ try {
+ filter->href->attach(Inkscape::URI(value));
+ } catch (Inkscape::BadURIException &e) {
+ g_warning("%s", e.what());
+ filter->href->detach();
+ }
+ } else {
+ filter->href->detach();
+ }
+ break;
+ default:
+ /* See if any parents need this value. */
+ if (((SPObjectClass *) filter_parent_class)->set) {
+ ((SPObjectClass *) filter_parent_class)->set(object, key, value);
+ }
+ break;
+ }
+}
+
+/**
+ * Receives update notifications.
+ */
+static void
+sp_filter_update(SPObject *object, SPCtx *ctx, guint flags)
+{
+ debug("0x%p",object);
+ //SPFilter *filter = SP_FILTER(object);
+
+ if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG |
+ SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
+
+ /* do something to trigger redisplay, updates? */
+
+ }
+
+ if (((SPObjectClass *) filter_parent_class)->update) {
+ ((SPObjectClass *) filter_parent_class)->update(object, ctx, flags);
+ }
+}
+
+/**
+ * Writes its settings to an incoming repr object, if any.
+ */
+static Inkscape::XML::Node *
+sp_filter_write(SPObject *object, Inkscape::XML::Node *repr, guint flags)
+{
+ debug("0x%p",object);
+ SPFilter *filter = SP_FILTER(object);
+
+ // Inkscape-only object, not copied during an "plain SVG" dump:
+/* if (flags & SP_OBJECT_WRITE_EXT) {
+ if (repr) {
+ // is this sane?
+ repr->mergeFrom(SP_OBJECT_REPR(object), "id");
+ } else {
+ repr = SP_OBJECT_REPR(object)->duplicate();
+ }
+ }
+*/
+
+
+//FIXME: repr node is null at this point,
+// preventing plain svg save. Need to fix this.
+
+
+ if ((flags & SP_OBJECT_WRITE_ALL) || filter->filterUnits_set) {
+ switch (filter->filterUnits) {
+ case SP_FILTER_UNITS_USERSPACEONUSE:
+ repr->setAttribute("filterUnits", "userSpaceOnUse");
+ break;
+ default:
+ repr->setAttribute("filterUnits", "objectBoundingBox");
+ break;
+ }
+ }
+
+ if ((flags & SP_OBJECT_WRITE_ALL) || filter->primitiveUnits_set) {
+ switch (filter->primitiveUnits) {
+ case SP_FILTER_UNITS_USERSPACEONUSE:
+ repr->setAttribute("primitiveUnits", "userSpaceOnUse");
+ break;
+ default:
+ repr->setAttribute("primitiveUnits", "objectBoundingBox");
+ break;
+ }
+ }
+
+ if (filter->x._set) {
+ sp_repr_set_svg_double(repr, "x", filter->x.computed);
+ } else {
+ repr->setAttribute("x", NULL);
+ }
+
+ if (filter->y._set) {
+ sp_repr_set_svg_double(repr, "y", filter->y.computed);
+ } else {
+ repr->setAttribute("y", NULL);
+ }
+
+ if (filter->width._set) {
+ sp_repr_set_svg_double(repr, "width", filter->width.computed);
+ } else {
+ repr->setAttribute("width", NULL);
+ }
+
+ if (filter->height._set) {
+ sp_repr_set_svg_double(repr, "height", filter->height.computed);
+ } else {
+ repr->setAttribute("height", NULL);
+ }
+
+ if (filter->filterRes._set) {
+ char filterRes[32];
+ repr->setAttribute("filterRes", filter->filterRes.getValueString(filterRes));
+ } else {
+ repr->setAttribute("filterRes", NULL);
+ }
+
+ if (filter->href->getURI()) {
+ gchar *uri_string = filter->href->getURI()->toString();
+ repr->setAttribute("xlink:href", uri_string);
+ g_free(uri_string);
+ }
+
+ if (((SPObjectClass *) filter_parent_class)->write) {
+ ((SPObjectClass *) filter_parent_class)->write(object, repr, flags);
+ }
+
+ return repr;
+}
+
+
+/**
+ * Gets called when the filter is (re)attached to another filter.
+ */
+static void
+filter_ref_changed(SPObject *old_ref, SPObject *ref, SPFilter *filter)
+{
+ if (old_ref) {
+ sp_signal_disconnect_by_data(old_ref, filter);
+ }
+ if ( SP_IS_FILTER(ref)
+ && ref != filter )
+ {
+ g_signal_connect(G_OBJECT(ref), "modified", G_CALLBACK(filter_ref_modified), filter);
+ }
+
+ filter_ref_modified(ref, filter);
+}
+
+static void
+filter_ref_modified(SPObject *href, SPFilter *filter)
+{
+ SP_OBJECT(filter)->requestModified(SP_OBJECT_MODIFIED_FLAG);
+}
+
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/sp-filter.h b/src/sp-filter.h
--- /dev/null
+++ b/src/sp-filter.h
@@ -0,0 +1,70 @@
+#ifndef SP_FILTER_H_SEEN
+#define SP_FILTER_H_SEEN
+
+/** \file
+ * SVG <filter> implementation, see sp-filter.cpp.
+ */
+/*
+ * Authors:
+ * Hugo Rodrigues <haa.rodrigues@gmail.com>
+ *
+ * Copyright (C) 2006 Hugo Rodrigues
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "number-opt-number.h"
+#include "sp-object.h"
+#include "sp-filter-units.h"
+#include "svg/svg-length.h"
+
+/* Filter base class */
+
+/* MACROS DEFINED IN FILE sp-filter-fns.h */
+
+struct SPFilterReference;
+
+class SPFilter;
+class SPFilterClass;
+
+struct SPFilter : public SPObject {
+
+ /** filterUnits attribute */
+ SPFilterUnits filterUnits;
+ guint filterUnits_set : 1;
+ /** primitiveUnits attribute */
+ SPFilterUnits primitiveUnits;
+ guint primitiveUnits_set : 1;
+ /** X attribute */
+ SVGLength x;
+ /** Y attribute */
+ SVGLength y;
+ /** WIDTH attribute */
+ SVGLength width;
+ /** HEIGHT attribute */
+ SVGLength height;
+ /** FILTERRES attribute */
+ NumberOptNumber filterRes;
+ /** HREF attribute */
+ SPFilterReference *href;
+};
+
+struct SPFilterClass {
+ SPObjectClass parent_class;
+};
+
+#include "sp-filter-fns.h"
+
+
+#endif /* !SP_FILTER_H_SEEN */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/sp-gaussian-blur-fns.h b/src/sp-gaussian-blur-fns.h
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef SP_GAUSSIANBLUR_FNS_H
+#define SP_GAUSSIANBLUR_FNS_H
+
+/** \file
+ * Macros and fn declarations related to gaussian blur filter.
+ */
+
+#include <glib-object.h>
+#include <glib/gtypes.h>
+
+namespace Inkscape {
+namespace XML {
+class Node;
+}
+}
+
+class SPGaussianBlur;
+
+#define SP_TYPE_GAUSSIANBLUR (sp_gaussianBlur_get_type())
+#define SP_GAUSSIANBLUR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_GAUSSIANBLUR, SPGaussianBlur))
+#define SP_GAUSSIANBLUR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_GAUSSIANBLUR, SPGaussianBlurClass))
+#define SP_IS_GAUSSIANBLUR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_GAUSSIANBLUR))
+#define SP_IS_GAUSSIANBLUR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_GAUSSIANBLUR))
+
+GType sp_gaussianBlur_get_type();
+
+#endif /* !SP_GAUSSIANBLUR_FNS_H */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/sp-gaussian-blur.cpp b/src/sp-gaussian-blur.cpp
--- /dev/null
+++ b/src/sp-gaussian-blur.cpp
@@ -0,0 +1,201 @@
+#define __SP_GAUSSIANBLUR_CPP__
+
+/** \file
+ * SVG <gaussianBlur> implementation.
+ *
+ */
+/*
+ * Authors:
+ * hugo Rodrigues <haa.rodrigues@gmail.com>
+ *
+ * Copyright (C) 2006 Hugo Rodrigues
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "attributes.h"
+#include "svg/svg.h"
+#include "sp-gaussian-blur.h"
+#include "xml/repr.h"
+
+//#define SP_MACROS_SILENT
+//#include "macros.h"
+
+#define DEBUG_GAUSSIANBLUR
+#ifdef DEBUG_GAUSSIANBLUR
+# define debug(f, a...) { g_print("%s(%d) %s:", \
+ __FILE__,__LINE__,__FUNCTION__); \
+ g_print(f, ## a); \
+ g_print("\n"); \
+ }
+#else
+# define debug(f, a...) /**/
+#endif
+
+/* GaussianBlur base class */
+
+static void sp_gaussianBlur_class_init(SPGaussianBlurClass *klass);
+static void sp_gaussianBlur_init(SPGaussianBlur *gaussianBlur);
+
+static void sp_gaussianBlur_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr);
+static void sp_gaussianBlur_release(SPObject *object);
+static void sp_gaussianBlur_set(SPObject *object, unsigned int key, gchar const *value);
+static void sp_gaussianBlur_update(SPObject *object, SPCtx *ctx, guint flags);
+static Inkscape::XML::Node *sp_gaussianBlur_write(SPObject *object, Inkscape::XML::Node *repr, guint flags);
+
+static SPObjectClass *gaussianBlur_parent_class;
+
+GType
+sp_gaussianBlur_get_type()
+{
+ static GType gaussianBlur_type = 0;
+
+ if (!gaussianBlur_type) {
+ GTypeInfo gaussianBlur_info = {
+ sizeof(SPGaussianBlurClass),
+ NULL, NULL,
+ (GClassInitFunc) sp_gaussianBlur_class_init,
+ NULL, NULL,
+ sizeof(SPGaussianBlur),
+ 16,
+ (GInstanceInitFunc) sp_gaussianBlur_init,
+ NULL, /* value_table */
+ };
+ gaussianBlur_type = g_type_register_static(SP_TYPE_OBJECT, "SPGaussianBlur", &gaussianBlur_info, (GTypeFlags)0);
+ }
+ return gaussianBlur_type;
+}
+
+static void
+sp_gaussianBlur_class_init(SPGaussianBlurClass *klass)
+{
+ SPObjectClass *sp_object_class = (SPObjectClass *)klass;
+
+ gaussianBlur_parent_class = (SPObjectClass*)g_type_class_peek_parent(klass);
+
+ sp_object_class->build = sp_gaussianBlur_build;
+ sp_object_class->release = sp_gaussianBlur_release;
+ sp_object_class->write = sp_gaussianBlur_write;
+ sp_object_class->set = sp_gaussianBlur_set;
+ sp_object_class->update = sp_gaussianBlur_update;
+}
+
+static void
+sp_gaussianBlur_init(SPGaussianBlur *gaussianBlur)
+{
+ debug("0x%p",gaussianBlur);
+
+// gaussianBlur->stdDeviation = 1;
+}
+
+/**
+ * Reads the Inkscape::XML::Node, and initializes SPGaussianBlur variables. For this to get called,
+ * our name must be associated with a repr via "sp_object_type_register". Best done through
+ * sp-object-repr.cpp's repr_name_entries array.
+ */
+static void
+sp_gaussianBlur_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr)
+{
+ debug("0x%p",object);
+ if (((SPObjectClass *) gaussianBlur_parent_class)->build) {
+ ((SPObjectClass *) gaussianBlur_parent_class)->build(object, document, repr);
+ }
+
+ sp_object_read_attr(object, "stdDeviation");
+
+}
+
+/**
+ * Drops any allocated memory.
+ */
+static void
+sp_gaussianBlur_release(SPObject *object)
+{
+ debug("0x%p",object);
+
+ if (((SPObjectClass *) gaussianBlur_parent_class)->release)
+ ((SPObjectClass *) gaussianBlur_parent_class)->release(object);
+}
+
+/**
+ * Sets a specific value in the SPGaussianBlur.
+ */
+static void
+sp_gaussianBlur_set(SPObject *object, unsigned int key, gchar const *value)
+{
+ debug("0x%p %s(%u): '%s'",object,
+ sp_attribute_name(key),key,value);
+ SPGaussianBlur *gaussianBlur = SP_GAUSSIANBLUR(object);
+
+ switch(key) {
+ case SP_ATTR_STDDEVIATION:
+ gaussianBlur->stdDeviation.set(value);
+ break;
+ default:
+ if (((SPObjectClass *) gaussianBlur_parent_class)->set)
+ ((SPObjectClass *) gaussianBlur_parent_class)->set(object, key, value);
+ break;
+ }
+
+}
+
+/**
+ * Receives update notifications.
+ */
+static void
+sp_gaussianBlur_update(SPObject *object, SPCtx *ctx, guint flags)
+{
+ debug("0x%p",object);
+
+ if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG |
+ SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
+
+ /* do something to trigger redisplay, updates? */
+
+ }
+
+ if (((SPObjectClass *) gaussianBlur_parent_class)->update) {
+ ((SPObjectClass *) gaussianBlur_parent_class)->update(object, ctx, flags);
+ }
+}
+
+/**
+ * Writes its settings to an incoming repr object, if any.
+ */
+static Inkscape::XML::Node *
+sp_gaussianBlur_write(SPObject *object, Inkscape::XML::Node *repr, guint flags)
+{
+ debug("0x%p",object);
+
+ // Inkscape-only object, not copied during an "plain SVG" dump:
+ if (flags & SP_OBJECT_WRITE_EXT) {
+ if (repr) {
+ // is this sane?
+ repr->mergeFrom(SP_OBJECT_REPR(object), "id");
+ } else {
+ repr = SP_OBJECT_REPR(object)->duplicate();
+ }
+ }
+
+ if (((SPObjectClass *) gaussianBlur_parent_class)->write) {
+ ((SPObjectClass *) gaussianBlur_parent_class)->write(object, repr, flags);
+ }
+
+ return repr;
+}
+
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/sp-gaussian-blur.h b/src/sp-gaussian-blur.h
--- /dev/null
+++ b/src/sp-gaussian-blur.h
@@ -0,0 +1,45 @@
+#ifndef SP_GAUSSIANBLUR_H_SEEN
+#define SP_GAUSSIANBLUR_H_SEEN
+
+/** \file
+ * SVG <gaussianBlur> implementation, see sp-gaussianBlur.cpp.
+ */
+/*
+ * Authors:
+ * Hugo Rodrigues <haa.rodrigues@gmail.com>
+ *
+ * Copyright (C) 2006 Hugo Rodrigues
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "sp-filter.h"
+#include "sp-gaussian-blur-fns.h"
+
+/* GaussianBlur base class */
+class SPGaussianBlurClass;
+
+struct SPGaussianBlur : public SPFilter {
+ /** stdDeviation attribute */
+ NumberOptNumber stdDeviation;
+};
+
+struct SPGaussianBlurClass {
+ SPFilterClass parent_class;
+};
+
+GType sp_gaussianBlur_get_type();
+
+
+#endif /* !SP_GAUSSIANBLUR_H_SEEN */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/sp-item-group.cpp b/src/sp-item-group.cpp
index 0f288a372a9600f562afc47c51a1db1c17eb183f..a4aa83ad2f569c85d74f4f79ee1209fb7ebaf460 100644 (file)
--- a/src/sp-item-group.cpp
+++ b/src/sp-item-group.cpp
if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
flags &= SP_OBJECT_MODIFIED_CASCADE;
+ if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) {
+ SPObject *object = SP_OBJECT(_group);
+ for (SPItemView *v = SP_ITEM(_group)->display; v != NULL; v = v->next) {
+ nr_arena_group_set_style(NR_ARENA_GROUP(v->arenaitem), SP_OBJECT_STYLE(object));
+ }
+ }
+
GSList *l = g_slist_reverse(_childList(true, ActionUpdate));
while (l) {
child = SP_OBJECT (l->data);
if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
flags &= SP_OBJECT_MODIFIED_CASCADE;
+ if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) {
+ SPObject *object = SP_OBJECT(_group);
+ for (SPItemView *v = SP_ITEM(_group)->display; v != NULL; v = v->next) {
+ nr_arena_group_set_style(NR_ARENA_GROUP(v->arenaitem), SP_OBJECT_STYLE(object));
+ }
+ }
+
GSList *l = g_slist_reverse(_childList(true));
while (l) {
child = SP_OBJECT (l->data);
NRArenaItem *CGroup::show (NRArena *arena, unsigned int key, unsigned int flags) {
NRArenaItem *ai;
+ SPObject *object = SP_OBJECT(_group);
ai = NRArenaGroup::create(arena);
+
nr_arena_group_set_transparent(NR_ARENA_GROUP (ai),
_group->effectiveLayerMode(key) ==
SPGroup::LAYER);
+ nr_arena_group_set_style(NR_ARENA_GROUP(ai), SP_OBJECT_STYLE(object));
_showChildren(arena, ai, key, flags);
return ai;
diff --git a/src/sp-object-repr.cpp b/src/sp-object-repr.cpp
index 0f2ff9e6a5f7439c318b85459116e726c2cd0ddc..4ffbce04f72ab32674d69ce6ffdfe72693f507bd 100644 (file)
--- a/src/sp-object-repr.cpp
+++ b/src/sp-object-repr.cpp
#include "sp-switch.h"
#include "color-profile-fns.h"
#include "xml/repr.h"
+#include "sp-filter.h"
+#include "sp-gaussian-blur.h"
enum NameType { REPR_NAME, SODIPODI_TYPE };
static unsigned const N_NAME_TYPES = SODIPODI_TYPE + 1;
{ "svg:clipPath", SP_TYPE_CLIPPATH },
{ "svg:defs", SP_TYPE_DEFS },
{ "svg:ellipse", SP_TYPE_ELLIPSE },
+ { "svg:filter", SP_TYPE_FILTER },
/* Note: flow* elements are proposed additions for SVG 1.2, they aren't in
SVG 1.1. */
{ "svg:flowDiv", SP_TYPE_FLOWDIV },
{ "svg:flowRoot", SP_TYPE_FLOWTEXT },
{ "svg:flowSpan", SP_TYPE_FLOWTSPAN },
{ "svg:g", SP_TYPE_GROUP },
+ { "svg:gaussianBlur", SP_TYPE_GAUSSIANBLUR },
{ "svg:image", SP_TYPE_IMAGE },
{ "svg:line", SP_TYPE_LINE },
{ "svg:linearGradient", SP_TYPE_LINEARGRADIENT },
diff --git a/src/sp-text.cpp b/src/sp-text.cpp
index f9be549444d5986d804031f806a9f45edcf9c85a..c9811ec6e18420d291de0efbd875a55beaadf6ef 100644 (file)
--- a/src/sp-text.cpp
+++ b/src/sp-text.cpp
@@ -375,6 +375,8 @@ sp_text_show(SPItem *item, NRArena *arena, unsigned /* key*/, unsigned /*flags*/
NRArenaGroup *flowed = NRArenaGroup::create(arena);
nr_arena_group_set_transparent (flowed, FALSE);
+ nr_arena_group_set_style(flowed, group->style);
+
// pass the bbox of the text object as paintbox (used for paintserver fills)
NRRect paintbox;
sp_item_invoke_bbox(item, &paintbox, NR::identity(), TRUE);
diff --git a/src/style.cpp b/src/style.cpp
index 2a0a30bd165b91fb4b12171307aa3bb3463b90da..d97dac316e031bb725be46e508234855817d27b3 100644 (file)
--- a/src/style.cpp
+++ b/src/style.cpp
static void sp_style_merge_property(SPStyle *style, gint id, gchar const *val);
static void sp_style_merge_ipaint(SPStyle *style, SPIPaint *paint, SPIPaint const *parent);
+static void sp_style_merge_ifilter(SPIFilter *child, SPIFilter const *parent);
static void sp_style_read_dash(SPStyle *style, gchar const *str);
static SPTextStyle *sp_text_style_new(void);
@@ -134,6 +135,7 @@ static void sp_style_read_itextdecoration(SPITextDecoration *val, gchar const *s
static void sp_style_read_icolor(SPIPaint *paint, gchar const *str, SPStyle *style, SPDocument *document);
static void sp_style_read_ipaint(SPIPaint *paint, gchar const *str, SPStyle *style, SPDocument *document);
static void sp_style_read_ifontsize(SPIFontSize *val, gchar const *str);
+static void sp_style_read_ifilter(SPIFilter *f, gchar const *str, SPDocument *document);
static void sp_style_read_penum(SPIEnum *val, Inkscape::XML::Node *repr, gchar const *key, SPStyleEnum const *dict, bool can_explicitly_inherit);
static void sp_style_read_plength(SPILength *val, Inkscape::XML::Node *repr, gchar const *key);
}
}
+ /* filter effects */
+ if (!style->filter.set) {
+ val = repr->attribute("filter");
+ if (val) {
+ sp_style_read_ifilter(&style->filter, val, (object) ? SP_OBJECT_DOCUMENT(object) : NULL);
+ }
+ }
+
/* 3. Merge from parent */
if (object) {
if (object->parent) {
sp_style_read_iscale24(&style->opacity, val);
}
break;
- /* Filter */
case SP_PROP_ENABLE_BACKGROUND:
g_warning("Unimplemented style property SP_PROP_ENABLE_BACKGROUND: value: %s", val);
break;
+ /* Filter */
case SP_PROP_FILTER:
- g_warning("Unimplemented style property SP_PROP_FILTER: value: %s", val);
+ if (style->filter.set && style->filter.inherit) {
+ sp_style_read_ifilter(&style->filter, val, (style->object) ? SP_OBJECT_DOCUMENT(style->object) : NULL);
+ }
break;
case SP_PROP_FLOOD_COLOR:
g_warning("Unimplemented style property SP_PROP_FLOOD_COLOR: value: %s", val);
@@ -1415,6 +1427,11 @@ sp_style_merge_from_parent(SPStyle *const style, SPStyle const *const parent)
style->marker[i].value = g_strdup(parent->marker[i].value);
}
}
+
+ /* Filter effects */
+ if(style->filter.set && style->filter.inherit) {
+ sp_style_merge_ifilter(&style->filter, &parent->filter);
+ }
}
template <typename T>
@@ -2042,6 +2059,19 @@ sp_style_merge_ipaint(SPStyle *style, SPIPaint *paint, SPIPaint const *parent)
}
+/**
+ * Merge filter style from parent.
+ * Filter effects do not inherit by default
+ */
+static void
+sp_style_merge_ifilter(SPIFilter *child, SPIFilter const *parent)
+{
+ child->set = parent->set;
+ child->inherit = parent->inherit;
+ child->filter = parent->filter;
+ child->uri = parent->uri;
+}
+
/**
* Dumps the style to a CSS string, with either SP_STYLE_FLAG_IFSET or
* SP_STYLE_FLAG_ALWAYS flags. Used with Always for copying an object's
+/**
+ * Set SPIFilter object from string.
+ */
+static void
+sp_style_read_ifilter(SPIFilter *f, gchar const *str, SPDocument *document)
+{
+ /* Try all possible values: inherit, none, uri */
+ if (streq(str, "inherit")) {
+ f->set = TRUE;
+ f->inherit = TRUE;
+ f->filter = NULL;
+ } else if(streq(str, "none")) {
+ f->set = TRUE;
+ f->inherit = FALSE;
+ f->filter = NULL;
+ } else if (strneq(str, "url", 3)) {
+ f->uri = extract_uri(str);
+ if(f->uri == NULL || f->uri[0] == '\0') {
+ g_warning("Specified filter url is empty");
+ f->set = TRUE;
+ f->inherit = FALSE;
+ f->filter = NULL;
+ return;
+ }
+ f->set = TRUE;
+ f->inherit = FALSE;
+ f->filter = NULL;
+ if (document) {
+ SPObject *obj;
+ obj = sp_uri_reference_resolve(document, str);
+ if (SP_IS_FILTER(obj)) {
+ f->filter = SP_FILTER(obj);
+ //g_signal_connect(G_OBJECT(f->filter), "release",
+ // G_CALLBACK(sp_style_filter_release), style);
+ //g_signal_connect(G_OBJECT(f->filter), "modified",
+ // G_CALLBACK(sp_style_filter_modified), style);
+ } else {
+ g_warning("Element '%s' not found or is not a filter", f->uri);
+ }
+ }
+
+ } else {
+ /* We shouldn't reach this if SVG input is well-formed */
+ f->set = FALSE;
+ f->inherit = FALSE;
+ f->filter = NULL;
+ f->uri = NULL;
+ }
+}
+
/**
* Set SPIEnum object from repr attribute.
*/
diff --git a/src/style.h b/src/style.h
index 703a55fdb9c8bfb3b0b2e69b66927a036c291088..3c070a22a6714281e644d6059ea1e42a8e94f122 100644 (file)
--- a/src/style.h
+++ b/src/style.h
#include "color.h"
#include "forward.h"
#include "sp-marker-loc.h"
+#include "sp-filter.h"
namespace Inkscape {
namespace XML {
SVGICCColor *iccColor;
};
+/// Filter type internal to SPStyle
+struct SPIFilter {
+ unsigned set : 1;
+ unsigned inherit : 1;
+ SPFilter *filter;
+ gchar *uri;
+};
+
enum {
SP_FONT_SIZE_LITERAL,
SP_FONT_SIZE_LENGTH,
/** Marker list */
SPIString marker[SP_MARKER_LOC_QTY];
+ /** Filter effect */
+ SPIFilter filter;
+
/// style belongs to a cloned object, must not href anything
bool cloned;
/// style has hreffed its fill/stroke paintservers, needs to release.