summaryrefslogtreecommitdiffstats
path: root/src/display
diff options
context:
space:
mode:
authorNiko Kiirala <niko@kiirala.com>2006-06-21 16:04:22 +0000
committerkiirala <kiirala@users.sourceforge.net>2006-06-21 16:04:22 +0000
commitd331e75a28fc513289d24bc0dc10ef7be26da888 (patch)
tree2b9cae58f7256a2e12625068a54299911859e63e /src/display
parentit seems we don't have "required" anymore (diff)
downloadinkscape-d331e75a28fc513289d24bc0dc10ef7be26da888.tar.gz
inkscape-d331e75a28fc513289d24bc0dc10ef7be26da888.zip
svg-filters branch merged back to head
(bzr r1252)
Diffstat (limited to 'src/display')
-rw-r--r--src/display/Makefile_insert8
-rw-r--r--src/display/nr-arena-glyphs.h2
-rw-r--r--src/display/nr-arena-group.cpp19
-rw-r--r--src/display/nr-arena-group.h3
-rw-r--r--src/display/nr-arena-item.cpp24
-rw-r--r--src/display/nr-arena-item.h12
-rw-r--r--src/display/nr-arena-shape.cpp9
-rw-r--r--src/display/nr-filter-gaussian.cpp394
-rw-r--r--src/display/nr-filter-gaussian.h83
-rw-r--r--src/display/nr-filter-primitive.cpp70
-rw-r--r--src/display/nr-filter-primitive.h108
-rw-r--r--src/display/nr-filter-types.h49
-rw-r--r--src/display/nr-filter.cpp223
-rw-r--r--src/display/nr-filter.h204
14 files changed, 1203 insertions, 5 deletions
diff --git a/src/display/Makefile_insert b/src/display/Makefile_insert
index de6ec85c2..5aec6894f 100644
--- a/src/display/Makefile_insert
+++ b/src/display/Makefile_insert
@@ -60,7 +60,13 @@ display_libspdisplay_a_SOURCES = \
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
diff --git a/src/display/nr-arena-glyphs.h b/src/display/nr-arena-glyphs.h
index 23b74a378..a2dda988b 100644
--- a/src/display/nr-arena-glyphs.h
+++ b/src/display/nr-arena-glyphs.h
@@ -79,7 +79,7 @@ typedef struct NRArenaGlyphsGroupClass NRArenaGlyphsGroupClass;
NRType nr_arena_glyphs_group_get_type (void);
struct NRArenaGlyphsGroup : public NRArenaGroup {
- SPStyle *style;
+ //SPStyle *style;
NRRect paintbox;
/* State data */
SPPainter *fill_painter;
diff --git a/src/display/nr-arena-group.cpp b/src/display/nr-arena-group.cpp
index f15c72e8e..9657715ea 100644
--- a/src/display/nr-arena-group.cpp
+++ b/src/display/nr-arena-group.cpp
@@ -12,7 +12,9 @@
* 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);
@@ -75,6 +77,7 @@ 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)
{
diff --git a/src/display/nr-arena-group.h b/src/display/nr-arena-group.h
index b33495362..9da16908d 100644
--- a/src/display/nr-arena-group.h
+++ b/src/display/nr-arena-group.h
@@ -18,6 +18,7 @@
#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);
@@ -26,6 +27,7 @@ struct NRArenaGroup : public NRArenaItem{
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));
@@ -42,5 +44,6 @@ void nr_arena_group_set_transparent (NRArenaGroup *group, unsigned int transpare
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
diff --git a/src/display/nr-arena-item.cpp b/src/display/nr-arena-item.cpp
index 97c769548..57413ef22 100644
--- a/src/display/nr-arena-item.cpp
+++ b/src/display/nr-arena-item.cpp
@@ -20,9 +20,12 @@
#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);
@@ -93,6 +96,7 @@ nr_arena_item_init (NRArenaItem *item)
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);
diff --git a/src/display/nr-arena-item.h b/src/display/nr-arena-item.h
index 22b992920..7a6c67602 100644
--- a/src/display/nr-arena-item.h
+++ b/src/display/nr-arena-item.h
@@ -58,6 +58,12 @@
#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,
@@ -71,6 +77,7 @@ struct NRGC {
};
struct NRArenaItem : public NRObject {
+
NRArena *arena;
Inkscape::GC::soft_ptr<NRArenaItem> parent;
NRArenaItem *next;
@@ -102,12 +109,17 @@ struct NRArenaItem : public NRObject {
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;
}
diff --git a/src/display/nr-arena-shape.cpp b/src/display/nr-arena-shape.cpp
index d26d1bc27..abe343a1d 100644
--- a/src/display/nr-arena-shape.cpp
+++ b/src/display/nr-arena-shape.cpp
@@ -16,6 +16,7 @@
#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>
@@ -26,6 +27,8 @@
#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);
@@ -1082,6 +1085,12 @@ nr_arena_shape_set_style(NRArenaShape *shape, SPStyle *style)
}
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
new file mode 100644
index 000000000..e31d903f1
--- /dev/null
+++ b/src/display/nr-filter-gaussian.cpp
@@ -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
new file mode 100644
index 000000000..445364a6c
--- /dev/null
+++ b/src/display/nr-filter-gaussian.h
@@ -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
new file mode 100644
index 000000000..6bdbf9a41
--- /dev/null
+++ b/src/display/nr-filter-primitive.cpp
@@ -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
new file mode 100644
index 000000000..a2bd14b61
--- /dev/null
+++ b/src/display/nr-filter-primitive.h
@@ -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
new file mode 100644
index 000000000..a6f539d03
--- /dev/null
+++ b/src/display/nr-filter-types.h
@@ -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
new file mode 100644
index 000000000..35f348389
--- /dev/null
+++ b/src/display/nr-filter.cpp
@@ -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
new file mode 100644
index 000000000..15a852d10
--- /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 :