summaryrefslogtreecommitdiffstats
path: root/src/display
diff options
context:
space:
mode:
authorKrzysztof Kosi??ski <tweenk.pl@gmail.com>2010-07-14 02:32:10 +0000
committerKrzysztof KosiƄski <tweenk.pl@gmail.com>2010-07-14 02:32:10 +0000
commitbb8404b19557519bd828113fa93604b10e9e7fe3 (patch)
tree01fd9c531829445801184b172fd7636cde1ab86e /src/display
parentGaussian blur (diff)
downloadinkscape-bb8404b19557519bd828113fa93604b10e9e7fe3.tar.gz
inkscape-bb8404b19557519bd828113fa93604b10e9e7fe3.zip
Merge redundant *-fns.h into respective filter headers.
Move gaussian blur to filters directory. Blend filter effect. (bzr r9508.1.16)
Diffstat (limited to 'src/display')
-rw-r--r--src/display/cairo-utils.cpp20
-rw-r--r--src/display/nr-arena-group.cpp2
-rw-r--r--src/display/nr-arena-image.cpp4
-rw-r--r--src/display/nr-arena-item.h31
-rw-r--r--src/display/nr-filter-blend.cpp253
-rw-r--r--src/display/nr-filter-blend.h2
-rw-r--r--src/display/nr-filter-gaussian.cpp429
-rw-r--r--src/display/nr-filter-gaussian.h3
-rw-r--r--src/display/nr-filter-primitive.h16
-rw-r--r--src/display/nr-filter-slot.cpp39
10 files changed, 341 insertions, 458 deletions
diff --git a/src/display/cairo-utils.cpp b/src/display/cairo-utils.cpp
index a063a62bb..36202f42e 100644
--- a/src/display/cairo-utils.cpp
+++ b/src/display/cairo-utils.cpp
@@ -337,11 +337,21 @@ ink_cairo_surface_copy(cairo_surface_t *s)
{
cairo_surface_t *ns = ink_cairo_surface_create_identical(s);
- cairo_t *ct = cairo_create(ns);
- cairo_set_source_surface(ct, s, 0, 0);
- cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE);
- cairo_paint(ct);
- cairo_destroy(ct);
+ if (cairo_surface_get_type(s) == CAIRO_SURFACE_TYPE_IMAGE) {
+ // use memory copy instead of using a Cairo context
+ cairo_surface_flush(s);
+ int stride = cairo_image_surface_get_stride(s);
+ int h = cairo_image_surface_get_height(s);
+ memcpy(cairo_image_surface_get_data(ns), cairo_image_surface_get_data(s), stride * h);
+ cairo_surface_mark_dirty(ns);
+ } else {
+ // generic implementation
+ cairo_t *ct = cairo_create(ns);
+ cairo_set_source_surface(ct, s, 0, 0);
+ cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE);
+ cairo_paint(ct);
+ cairo_destroy(ct);
+ }
return ns;
}
diff --git a/src/display/nr-arena-group.cpp b/src/display/nr-arena-group.cpp
index 0fa5f332a..3bc78ea56 100644
--- a/src/display/nr-arena-group.cpp
+++ b/src/display/nr-arena-group.cpp
@@ -14,12 +14,10 @@
#include "display/nr-arena-group.h"
#include "display/nr-filter.h"
-#include "display/nr-filter-gaussian.h"
#include "display/nr-filter-types.h"
#include "style.h"
#include "sp-filter.h"
#include "sp-filter-reference.h"
-#include "sp-gaussian-blur.h"
#include "filters/blend.h"
#include "display/nr-filter-blend.h"
#include "helper/geom.h"
diff --git a/src/display/nr-arena-image.cpp b/src/display/nr-arena-image.cpp
index 325cff65a..422b691b7 100644
--- a/src/display/nr-arena-image.cpp
+++ b/src/display/nr-arena-image.cpp
@@ -21,12 +21,8 @@
#include "display/cairo-utils.h"
#include "display/nr-arena.h"
#include "display/nr-filter.h"
-#include "display/nr-filter-gaussian.h"
#include "sp-filter.h"
#include "sp-filter-reference.h"
-#include "sp-gaussian-blur.h"
-#include "filters/blend.h"
-#include "display/nr-filter-blend.h"
int nr_arena_image_x_sample = 1;
int nr_arena_image_y_sample = 1;
diff --git a/src/display/nr-arena-item.h b/src/display/nr-arena-item.h
index 468d352bc..447307535 100644
--- a/src/display/nr-arena-item.h
+++ b/src/display/nr-arena-item.h
@@ -1,6 +1,3 @@
-#ifndef __NR_ARENA_ITEM_H__
-#define __NR_ARENA_ITEM_H__
-
/*
* RGBA display list system for inkscape
*
@@ -13,6 +10,22 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
+#ifndef SEEN_DISPLAY_NR_ARENA_ITEM_H
+#define SEEN_DISPLAY_NR_ARENA_ITEM_H
+
+#include <cairo.h>
+#include <2geom/matrix.h>
+#include <libnr/nr-rect-l.h>
+#include <libnr/nr-pixblock.h>
+#include <libnr/nr-object.h>
+#include "gc-soft-ptr.h"
+#include "nr-arena-forward.h"
+
+namespace Inkscape {
+namespace Filters {
+class Filter;
+} }
+
#define NR_TYPE_ARENA_ITEM (nr_arena_item_get_type ())
#define NR_ARENA_ITEM(o) (NR_CHECK_INSTANCE_CAST ((o), NR_TYPE_ARENA_ITEM, NRArenaItem))
#define NR_IS_ARENA_ITEM(o) (NR_CHECK_INSTANCE_TYPE ((o), NR_TYPE_ARENA_ITEM))
@@ -52,15 +65,6 @@
#define NR_ARENA_ITEM_RENDER_NO_CACHE (1 << 0)
-#include <2geom/matrix.h>
-#include <libnr/nr-rect-l.h>
-#include <libnr/nr-pixblock.h>
-#include <libnr/nr-object.h>
-#include "gc-soft-ptr.h"
-#include "nr-arena-forward.h"
-#include "display/nr-filter.h"
-#include <cairo.h>
-
struct NRGC {
NRGC(NRGC const *p) : parent(p) {}
NRGC const *parent;
@@ -181,8 +185,7 @@ NRArenaItem *nr_arena_item_detach (NRArenaItem *parent, NRArenaItem *child);
#define NR_ARENA_ITEM_SET_KEY(i,k) (((NRArenaItem *) (i))->key = (k))
#define NR_ARENA_ITEM_GET_KEY(i) (((NRArenaItem *) (i))->key)
-
-#endif /* !__NR_ARENA_ITEM_H__ */
+#endif /* !SEEN_DISPLAY_NR_ARENA_ITEM_H */
/*
Local Variables:
diff --git a/src/display/nr-filter-blend.cpp b/src/display/nr-filter-blend.cpp
index 4645d9bc0..4ce37ae3b 100644
--- a/src/display/nr-filter-blend.cpp
+++ b/src/display/nr-filter-blend.cpp
@@ -15,6 +15,11 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "display/cairo-utils.h"
#include "display/nr-filter-blend.h"
#include "display/nr-filter-pixops.h"
#include "display/nr-filter-primitive.h"
@@ -24,6 +29,7 @@
#include "libnr/nr-pixblock.h"
#include "libnr/nr-blit.h"
#include "libnr/nr-pixops.h"
+#include "preferences.h"
namespace Inkscape {
namespace Filters {
@@ -125,6 +131,247 @@ FilterPrimitive * FilterBlend::create() {
FilterBlend::~FilterBlend()
{}
+#define EXTRACT_ARGB32(px,a,r,g,b) \
+ guint32 a, r, g, b; \
+ a = (px & 0xff000000) >> 24; \
+ r = (px & 0x00ff0000) >> 16; \
+ g = (px & 0x0000ff00) >> 8; \
+ b = (px & 0x000000ff);
+
+#define ASSEMBLE_ARGB32(px,a,r,g,b) \
+ guint32 px = (a << 24) | (r << 16) | (g << 8) | b;
+
+// cr = (1-qa)*cb + (1-qb)*ca + ca*cb
+struct BlendMultiply {
+ void operator()(guint32 in1, guint32 in2, guint32 *out)
+ {
+ EXTRACT_ARGB32(in1, aa, ra, ga, ba)
+ EXTRACT_ARGB32(in2, ab, rb, gb, bb)
+
+ guint32 ao = 255*255 - (255-aa)*(255-ab); ao = (ao + 127) / 255;
+ guint32 ro = (255-aa)*rb + (255-ab)*ra + ra*rb; ro = (ro + 127) / 255;
+ guint32 go = (255-aa)*gb + (255-ab)*ga + ga*gb; go = (go + 127) / 255;
+ guint32 bo = (255-aa)*bb + (255-ab)*ba + ba*bb; bo = (bo + 127) / 255;
+
+ ASSEMBLE_ARGB32(pxout, ao, ro, go, bo)
+ *out = pxout;
+ }
+};
+
+// cr = cb + ca - ca * cb
+struct BlendScreen {
+ void operator()(guint32 in1, guint32 in2, guint32 *out)
+ {
+ EXTRACT_ARGB32(in1, aa, ra, ga, ba)
+ EXTRACT_ARGB32(in2, ab, rb, gb, bb)
+
+ guint32 ao = 255*255 - (255-aa)*(255-ab); ao = (ao + 127) / 255;
+ guint32 ro = 255*(rb + ra) - ra * rb; ro = (ro + 127) / 255;
+ guint32 go = 255*(gb + ga) - ga * gb; go = (go + 127) / 255;
+ guint32 bo = 255*(bb + ba) - ba * bb; bo = (bo + 127) / 255;
+
+ ASSEMBLE_ARGB32(pxout, ao, ro, go, bo)
+ *out = pxout;
+ }
+};
+
+// cr = Min ((1 - qa) * cb + ca, (1 - qb) * ca + cb)
+struct BlendDarken {
+ void operator()(guint32 in1, guint32 in2, guint32 *out)
+ {
+ EXTRACT_ARGB32(in1, aa, ra, ga, ba)
+ EXTRACT_ARGB32(in2, ab, rb, gb, bb)
+
+ guint32 ao = 255*255 - (255-aa)*(255-ab); ao = (ao + 127) / 255;
+ guint32 ro = std::min((255-aa)*rb + 255*ra, (255-ab)*ra + 255*rb); ro = (ro + 127) / 255;
+ guint32 go = std::min((255-aa)*gb + 255*ga, (255-ab)*ga + 255*gb); go = (go + 127) / 255;
+ guint32 bo = std::min((255-aa)*bb + 255*ba, (255-ab)*ba + 255*bb); bo = (bo + 127) / 255;
+
+ ASSEMBLE_ARGB32(pxout, ao, ro, go, bo)
+ *out = pxout;
+ }
+};
+
+// cr = Max ((1 - qa) * cb + ca, (1 - qb) * ca + cb)
+struct BlendLighten {
+ void operator()(guint32 in1, guint32 in2, guint32 *out)
+ {
+ EXTRACT_ARGB32(in1, aa, ra, ga, ba)
+ EXTRACT_ARGB32(in2, ab, rb, gb, bb)
+
+ guint32 ao = 255*255 - (255-aa)*(255-ab); ao = (ao + 127) / 255;
+ guint32 ro = std::max((255-aa)*rb + 255*ra, (255-ab)*ra + 255*rb); ro = (ro + 127) / 255;
+ guint32 go = std::max((255-aa)*gb + 255*ga, (255-ab)*ga + 255*gb); go = (go + 127) / 255;
+ guint32 bo = std::max((255-aa)*bb + 255*ba, (255-ab)*ba + 255*bb); bo = (bo + 127) / 255;
+
+ ASSEMBLE_ARGB32(pxout, ao, ro, go, bo)
+ *out = pxout;
+ }
+};
+
+/*
+struct BlendAlpha
+static inline void blend_alpha(guint32 in1, guint32 in2, guint32 *out)
+{
+ EXTRACT_ARGB32(in1, a1, a2, a3, a4);
+ EXTRACT_ARGB32(in2, b1, b2, b3, b4);
+
+ guint32 o1 = 255*255 - (255-a1)*(255-b1); o1 = (o1+127) / 255;
+ guint32 o2 = 255*255 - (255-a2)*(255-b2); o2 = (o2+127) / 255;
+ guint32 o3 = 255*255 - (255-a3)*(255-b3); o3 = (o3+127) / 255;
+ guint32 o4 = 255*255 - (255-a4)*(255-b4); o4 = (o4+127) / 255;
+
+ ASSEMBLE_ARGB32(pxout, o1, o2, o3, o4);
+ *out = pxout;
+}
+*/
+
+template <typename Blend>
+void surface_blend(cairo_surface_t *in1, cairo_surface_t *in2, cairo_surface_t *out)
+{
+ cairo_surface_flush(in1);
+ cairo_surface_flush(in2);
+
+ // WARNING: code below assumes that:
+ // 1. Cairo ARGB32 surface strides are always divisible by 4
+ // 2. We can only receive CAIRO_FORMAT_ARGB32 or CAIRO_FORMAT_A8 surfaces
+
+ int w = cairo_image_surface_get_width(in2);
+ int h = cairo_image_surface_get_height(in2);
+ int stride1 = cairo_image_surface_get_stride(in1);
+ int stride2 = cairo_image_surface_get_stride(in2);
+ int strideout = cairo_image_surface_get_stride(out);
+ int bpp1 = cairo_image_surface_get_format(in1) == CAIRO_FORMAT_A8 ? 1 : 4;
+ int bpp2 = cairo_image_surface_get_format(in2) == CAIRO_FORMAT_A8 ? 1 : 4;
+ // assumption: out surface is CAIRO_FORMAT_ARGB32 if at least one input is ARGB32
+
+ guint32 *const in1_data = (guint32*) cairo_image_surface_get_data(in1);
+ guint32 *const in2_data = (guint32*) cairo_image_surface_get_data(in2);
+ guint32 *const out_data = (guint32*) cairo_image_surface_get_data(out);
+
+ #if HAVE_OPENMP
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ int num_threads = prefs->getIntLimited("/options/threading/numthreads", omp_get_num_procs(), 1, 256);
+ #endif
+
+ if (bpp1 == 4) {
+ if (bpp2 == 4) {
+ #if HAVE_OPENMP
+ #pragma omp parallel for num_threads(num_threads)
+ #endif
+ for (int i = 0; i < h; ++i) {
+ guint32 *in1_p = in1_data + i * stride1/4;
+ guint32 *in2_p = in2_data + i * stride2/4;
+ guint32 *out_p = out_data + i * strideout/4;
+ for (int j = 0; j < w; ++j) {
+ Blend()(*in1_p, *in2_p, out_p);
+ ++in1_p;
+ ++in2_p;
+ ++out_p;
+ }
+ }
+ } else {
+ // bpp2 == 1
+ #if HAVE_OPENMP
+ #pragma omp parallel for num_threads(num_threads)
+ #endif
+ for (int i = 0; i < h; ++i) {
+ guint32 *in1_p = in1_data + i * stride1/4;
+ guint8 *in2_p = reinterpret_cast<guint8*>(in2_data) + i * stride2;
+ guint32 *out_p = out_data + i * strideout/4;
+ for (int j = 0; j < w; ++j) {
+ guint32 in2_px = *in2_p;
+ in2_px <<= 24;
+ Blend()(*in1_p, in2_px, out_p);
+ ++in1_p;
+ ++in2_p;
+ ++out_p;
+ }
+ }
+ }
+ } else {
+ if (bpp2 == 4) {
+ // bpp1 == 1
+ #if HAVE_OPENMP
+ #pragma omp parallel for num_threads(num_threads)
+ #endif
+ for (int i = 0; i < h; ++i) {
+ guint8 *in1_p = reinterpret_cast<guint8*>(in1_data) + i * stride1;
+ guint32 *in2_p = in2_data + i * stride2/4;
+ guint32 *out_p = out_data + i * strideout/4;
+ for (int j = 0; j < w; ++j) {
+ guint32 in1_px = *in1_p;
+ in1_px <<= 24;
+ Blend()(in1_px, *in2_p, out_p);
+ ++in1_p;
+ ++in2_p;
+ ++out_p;
+ }
+ }
+ } else {
+ // bpp1 == 1 && bpp2 == 1
+ // don't do anything - this should have been handled via Cairo blending
+ g_assert_not_reached();
+ }
+ }
+
+ cairo_surface_mark_dirty(out);
+}
+
+void FilterBlend::render_cairo(FilterSlot &slot)
+{
+ cairo_surface_t *input1 = slot.getcairo(_input);
+ cairo_surface_t *input2 = slot.getcairo(_input2);
+
+ cairo_content_t ct1 = cairo_surface_get_content(input1);
+ cairo_content_t ct2 = cairo_surface_get_content(input2);
+
+ // input2 is the "background" image
+ // out should be ARGB32 if any of the inputs is ARGB32
+ cairo_surface_t *out = NULL;
+ if ((ct1 == CAIRO_CONTENT_ALPHA && ct2 == CAIRO_CONTENT_ALPHA)
+ || _blend_mode == BLEND_NORMAL)
+ {
+ out = ink_cairo_surface_copy(input2);
+ cairo_t *out_ct = cairo_create(out);
+ cairo_set_source_surface(out_ct, input1, 0, 0);
+ cairo_paint(out_ct);
+ cairo_destroy(out_ct);
+ } else {
+ // blend mode != normal and at least 1 surface is not pure alpha
+ // create surface identical to the ARGB32 surface
+ if (ct1 == CAIRO_CONTENT_ALPHA) {
+ out = ink_cairo_surface_create_identical(input2);
+ } else {
+ out = ink_cairo_surface_create_identical(input1);
+ }
+
+ // TODO: convert to Cairo blending operators once we start using the 1.10 series
+ switch (_blend_mode) {
+ case BLEND_MULTIPLY:
+ surface_blend<BlendMultiply>(input1, input2, out);
+ break;
+ case BLEND_SCREEN:
+ surface_blend<BlendScreen>(input1, input2, out);
+ break;
+ case BLEND_DARKEN:
+ surface_blend<BlendDarken>(input1, input2, out);
+ break;
+ case BLEND_LIGHTEN:
+ surface_blend<BlendLighten>(input1, input2, out);
+ break;
+ case BLEND_NORMAL:
+ default:
+ // this was handled before
+ g_assert_not_reached();
+ break;
+ }
+ }
+
+ slot.set(_output, out);
+ cairo_surface_destroy(out);
+}
+
int FilterBlend::render(FilterSlot &slot, FilterUnits const & /*units*/) {
NRPixBlock *in1 = slot.get(_input);
NRPixBlock *in2 = slot.get(_input2);
@@ -202,6 +449,12 @@ int FilterBlend::render(FilterSlot &slot, FilterUnits const & /*units*/) {
return 0;
}
+bool FilterBlend::can_handle_affine(Geom::Matrix const &)
+{
+ // blend is a per-pixel primitive and is immutable under transformations
+ return true;
+}
+
void FilterBlend::set_input(int slot) {
_input = slot;
}
diff --git a/src/display/nr-filter-blend.h b/src/display/nr-filter-blend.h
index ffdd62118..45da07f27 100644
--- a/src/display/nr-filter-blend.h
+++ b/src/display/nr-filter-blend.h
@@ -39,7 +39,9 @@ public:
static FilterPrimitive *create();
virtual ~FilterBlend();
+ virtual void render_cairo(FilterSlot &slot);
virtual int render(FilterSlot &slot, FilterUnits const &units);
+ virtual bool can_handle_affine(Geom::Matrix const &);
virtual void set_input(int slot);
virtual void set_input(int input, int slot);
diff --git a/src/display/nr-filter-gaussian.cpp b/src/display/nr-filter-gaussian.cpp
index 2e6bed070..1e59748c4 100644
--- a/src/display/nr-filter-gaussian.cpp
+++ b/src/display/nr-filter-gaussian.cpp
@@ -32,8 +32,6 @@
#include "display/nr-filter-gaussian.h"
#include "display/nr-filter-types.h"
#include "display/nr-filter-units.h"
-#include "libnr/nr-blit.h"
-#include "libnr/nr-pixblock.h"
#include <2geom/matrix.h>
#include "util/fixed_point.h"
#include "preferences.h"
@@ -193,21 +191,6 @@ _effect_subsample_step_log2(double const deviation, int const quality)
return stepsize_l2;
}
-/**
- * Sanity check function for indexing pixblocks.
- * Catches reading and writing outside the pixblock area.
- * When enabled, decreases filter rendering speed massively.
- */
-static inline void
-_check_index(NRPixBlock const * const pb, int const location, int const line)
-{
- if (false) {
- int max_loc = pb->rs * (pb->area.y1 - pb->area.y0);
- if (location < 0 || location >= max_loc)
- g_warning("Location %d out of bounds (0 ... %d) at line %d", location, max_loc, line);
- }
-}
-
static void calcFilter(double const sigma, double b[N]) {
assert(N==3);
std::complex<double> const d1_org(1.40098, 1.00236);
@@ -287,8 +270,10 @@ filter2D_IIR(PT *const dest, int const dstr1, int const dstr2,
{
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
static unsigned int const alpha_PC = PC-1;
+ #define PREMUL_ALPHA_LOOP for(unsigned int c=0; c<PC-1; ++c)
#else
static unsigned int const alpha_PC = 0;
+ #define PREMUL_ALPHA_LOOP for(unsigned int c=1; c<PC; ++c)
#endif
#if HAVE_OPENMP
@@ -327,7 +312,7 @@ filter2D_IIR(PT *const dest, int const dstr1, int const dstr2,
dstimg -= dstr1;
if ( PREMULTIPLIED_ALPHA ) {
dstimg[alpha_PC] = clip_round_cast<PT>(v[0][alpha_PC]);
- for(unsigned int c=0; c<alpha_PC; c++) dstimg[c] = clip_round_cast<PT>(v[0][c], std::numeric_limits<PT>::min(), dstimg[alpha_PC]);
+ PREMUL_ALPHA_LOOP dstimg[c] = clip_round_cast<PT>(v[0][c], std::numeric_limits<PT>::min(), dstimg[alpha_PC]);
} else {
for(unsigned int c=0; c<PC; c++) dstimg[c] = clip_round_cast<PT>(v[0][c]);
}
@@ -342,7 +327,7 @@ filter2D_IIR(PT *const dest, int const dstr1, int const dstr2,
dstimg -= dstr1;
if ( PREMULTIPLIED_ALPHA ) {
dstimg[alpha_PC] = clip_round_cast<PT>(v[0][alpha_PC]);
- for(unsigned int c=0; c<alpha_PC; c++) dstimg[c] = clip_round_cast<PT>(v[0][c], std::numeric_limits<PT>::min(), dstimg[alpha_PC]);
+ PREMUL_ALPHA_LOOP dstimg[c] = clip_round_cast<PT>(v[0][c], std::numeric_limits<PT>::min(), dstimg[alpha_PC]);
} else {
for(unsigned int c=0; c<PC; c++) dstimg[c] = clip_round_cast<PT>(v[0][c]);
}
@@ -457,93 +442,6 @@ filter2D_FIR(PT *const dst, int const dstr1, int const dstr2,
}
}
-template<typename PT, unsigned int PC>
-static void
-downsample(PT *const dst, int const dstr1, int const dstr2, int const dn1, int const dn2,
- PT const *const src, int const sstr1, int const sstr2, int const sn1, int const sn2,
- int const step1_l2, int const step2_l2)
-{
- unsigned int const divisor_l2 = step1_l2+step2_l2; // step1*step2=2^(step1_l2+step2_l2)
- unsigned int const round_offset = (1<<divisor_l2)/2;
- int const step1 = 1<<step1_l2;
- int const step2 = 1<<step2_l2;
- int const step1_2 = step1/2;
- int const step2_2 = step2/2;
- for(int dc2 = 0 ; dc2 < dn2 ; dc2++) {
- int const sc2_begin = (dc2<<step2_l2)-step2_2;
- int const sc2_end = sc2_begin+step2;
- for(int dc1 = 0 ; dc1 < dn1 ; dc1++) {
- int const sc1_begin = (dc1<<step1_l2)-step1_2;
- int const sc1_end = sc1_begin+step1;
- unsigned int sum[PC];
- std::fill_n(sum, PC, 0);
- for(int sc2 = sc2_begin ; sc2 < sc2_end ; sc2++) {
- for(int sc1 = sc1_begin ; sc1 < sc1_end ; sc1++) {
- for(unsigned int ch = 0 ; ch < PC ; ch++) {
- sum[ch] += src[clip(sc2,0,sn2-1)*sstr2+clip(sc1,0,sn1-1)*sstr1+ch];
- }
- }
- }
- for(unsigned int ch = 0 ; ch < PC ; ch++) {
- dst[dc2*dstr2+dc1*dstr1+ch] = static_cast<PT>((sum[ch]+round_offset)>>divisor_l2);
- }
- }
- }
-}
-
-template<typename PT, unsigned int PC>
-static void
-upsample(PT *const dst, int const dstr1, int const dstr2, unsigned int const dn1, unsigned int const dn2,
- PT const *const src, int const sstr1, int const sstr2, unsigned int const sn1, unsigned int const sn2,
- unsigned int const step1_l2, unsigned int const step2_l2)
-{
- assert(((sn1-1)<<step1_l2)>=dn1 && ((sn2-1)<<step2_l2)>=dn2); // The last pixel of the source image should fall outside the destination image
- unsigned int const divisor_l2 = step1_l2+step2_l2; // step1*step2=2^(step1_l2+step2_l2)
- unsigned int const round_offset = (1<<divisor_l2)/2;
- unsigned int const step1 = 1<<step1_l2;
- unsigned int const step2 = 1<<step2_l2;
- for ( unsigned int sc2 = 0 ; sc2 < sn2-1 ; sc2++ ) {
- unsigned int const dc2_begin = (sc2 << step2_l2);
- unsigned int const dc2_end = std::min(dn2, dc2_begin+step2);
- for ( unsigned int sc1 = 0 ; sc1 < sn1-1 ; sc1++ ) {
- unsigned int const dc1_begin = (sc1 << step1_l2);
- unsigned int const dc1_end = std::min(dn1, dc1_begin+step1);
- for ( unsigned int byte = 0 ; byte < PC ; byte++) {
-
- // get 4 values at the corners of the pixel from src
- PT a00 = src[sstr2* sc2 + sstr1* sc1 + byte];
- PT a10 = src[sstr2* sc2 + sstr1*(sc1+1) + byte];
- PT a01 = src[sstr2*(sc2+1) + sstr1* sc1 + byte];
- PT a11 = src[sstr2*(sc2+1) + sstr1*(sc1+1) + byte];
-
- // initialize values for linear interpolation
- unsigned int a0 = a00*step2/*+a01*0*/;
- unsigned int a1 = a10*step2/*+a11*0*/;
-
- // iterate over the rectangle to be interpolated
- for ( unsigned int dc2 = dc2_begin ; dc2 < dc2_end ; dc2++ ) {
-
- // prepare linear interpolation for this row
- unsigned int a = a0*step1/*+a1*0*/+round_offset;
-
- for ( unsigned int dc1 = dc1_begin ; dc1 < dc1_end ; dc1++ ) {
-
- // simple linear interpolation
- dst[dstr2*dc2 + dstr1*dc1 + byte] = static_cast<PT>(a>>divisor_l2);
-
- // compute a = a0*(ix-1)+a1*(xi+1)+round_offset
- a = a - a0 + a1;
- }
-
- // compute a0 = a00*(iy-1)+a01*(yi+1) and similar for a1
- a0 = a0 - a00 + a01;
- a1 = a1 - a10 + a11;
- }
- }
- }
- }
-}
-
static void
gaussian_pass_IIR(Geom::Dim2 d, double deviation, cairo_surface_t *src, cairo_surface_t *dest,
IIRValue **tmpdata, int num_threads)
@@ -735,315 +633,6 @@ void FilterGaussian::render_cairo(FilterSlot &slot)
}
}
-int FilterGaussian::render(FilterSlot &slot, FilterUnits const &units)
-{
- // TODO: Meaningful return values? (If they're checked at all.)
-
- /* in holds the input pixblock */
- NRPixBlock *original_in = slot.get(_input);
-
- /* If to either direction, the standard deviation is zero or
- * input image is not defined,
- * a transparent black image should be returned. */
- if (_deviation_x <= 0 || _deviation_y <= 0 || original_in == NULL) {
- NRPixBlock *src = original_in;
- if (src == NULL) {
- g_warning("Missing source image for feGaussianBlur (in=%d)", _input);
- // A bit guessing here, but source graphic is likely to be of
- // right size
- src = slot.get(NR_FILTER_SOURCEGRAPHIC);
- }
- NRPixBlock *out = new NRPixBlock;
- nr_pixblock_setup_fast(out, src->mode, src->area.x0, src->area.y0,
- src->area.x1, src->area.y1, true);
- if (out->size != NR_PIXBLOCK_SIZE_TINY && out->data.px != NULL) {
- out->empty = false;
- slot.set(_output, out);
- }
- return 0;
- }
-
- // Gaussian blur is defined to operate on non-premultiplied color values.
- // So, convert the input first it uses non-premultiplied color values.
- // And please note that this should not be done AFTER resampling, as resampling a non-premultiplied image
- // does not simply yield a non-premultiplied version of the resampled premultiplied image!!!
- NRPixBlock *in = original_in;
- if (in->mode == NR_PIXBLOCK_MODE_R8G8B8A8N) {
- in = nr_pixblock_new_fast(NR_PIXBLOCK_MODE_R8G8B8A8P,
- original_in->area.x0, original_in->area.y0,
- original_in->area.x1, original_in->area.y1,
- false);
- if (!in) {
- // ran out of memory
- return 0;
- }
- nr_blit_pixblock_pixblock(in, original_in);
- }
-
- Geom::Matrix trans = units.get_matrix_primitiveunits2pb();
-
- // Some common constants
- int const width_org = in->area.x1-in->area.x0, height_org = in->area.y1-in->area.y0;
- double const deviation_x_org = _deviation_x * trans.expansionX();
- double const deviation_y_org = _deviation_y * trans.expansionY();
- int const PC = NR_PIXBLOCK_BPP(in);
-#if HAVE_OPENMP
- int const NTHREADS = std::max(1,std::min(8, Inkscape::Preferences::get()->getInt("/options/threading/numthreads", omp_get_num_procs())));
-#else
- int const NTHREADS = 1;
-#endif // HAVE_OPENMP
-
- // Subsampling constants
- int const quality = slot.get_blurquality();
- int const x_step_l2 = _effect_subsample_step_log2(deviation_x_org, quality);
- int const y_step_l2 = _effect_subsample_step_log2(deviation_y_org, quality);
- int const x_step = 1<<x_step_l2;
- int const y_step = 1<<y_step_l2;
- bool const resampling = x_step > 1 || y_step > 1;
- int const width = resampling ? static_cast<int>(ceil(static_cast<double>(width_org)/x_step))+1 : width_org;
- int const height = resampling ? static_cast<int>(ceil(static_cast<double>(height_org)/y_step))+1 : height_org;
- double const deviation_x = deviation_x_org / x_step;
- double const deviation_y = deviation_y_org / y_step;
- int const scr_len_x = _effect_area_scr(deviation_x);
- int const scr_len_y = _effect_area_scr(deviation_y);
-
- // Decide which filter to use for X and Y
- // This threshold was determined by trial-and-error for one specific machine,
- // so there's a good chance that it's not optimal.
- // Whatever you do, don't go below 1 (and preferrably not even below 2), as
- // the IIR filter gets unstable there.
- bool const use_IIR_x = deviation_x > 3;
- bool const use_IIR_y = deviation_y > 3;
-
- // new buffer for the subsampled output
- NRPixBlock *out = new NRPixBlock;
- nr_pixblock_setup_fast(out, in->mode, in->area.x0/x_step, in->area.y0/y_step,
- in->area.x0/x_step+width, in->area.y0/y_step+height, true);
- if (out->size != NR_PIXBLOCK_SIZE_TINY && out->data.px == NULL) {
- // alas, we've accomplished a lot, but ran out of memory - so abort
- if (in != original_in) nr_pixblock_free(in);
- delete out;
- return 0;
- }
- // Temporary storage for IIR filter
- // NOTE: This can be eliminated, but it reduces the precision a bit
- IIRValue * tmpdata[NTHREADS];
- std::fill_n(tmpdata, NTHREADS, (IIRValue*)0);
- if ( use_IIR_x || use_IIR_y ) {
- for(int i=0; i<NTHREADS; i++) {
- tmpdata[i] = new IIRValue[std::max(width,height)*PC];
- if (tmpdata[i] == NULL) {
- if (in != original_in) nr_pixblock_free(in);
- nr_pixblock_release(out);
- while(i-->0) {
- delete[] tmpdata[i];
- }
- delete out;
- return 0;
- }
- }
- }
-
- // Resampling (if necessary), goes from in -> out (setting ssin to out if used)
- NRPixBlock *ssin = in;
- if ( resampling ) {
- ssin = out;
- // Downsample
- switch(in->mode) {
- case NR_PIXBLOCK_MODE_A8: ///< Grayscale
- downsample<unsigned char,1>(NR_PIXBLOCK_PX(out), 1, out->rs, width, height, NR_PIXBLOCK_PX(in), 1, in->rs, width_org, height_org, x_step_l2, y_step_l2);
- break;
- case NR_PIXBLOCK_MODE_R8G8B8: ///< 8 bit RGB
- downsample<unsigned char,3>(NR_PIXBLOCK_PX(out), 3, out->rs, width, height, NR_PIXBLOCK_PX(in), 3, in->rs, width_org, height_org, x_step_l2, y_step_l2);
- break;
- //case NR_PIXBLOCK_MODE_R8G8B8A8N: ///< Normal 8 bit RGBA
- // downsample<unsigned char,4>(NR_PIXBLOCK_PX(out), 4, out->rs, width, height, NR_PIXBLOCK_PX(in), 4, in->rs, width_org, height_org, x_step_l2, y_step_l2);
- // break;
- case NR_PIXBLOCK_MODE_R8G8B8A8P: ///< Premultiplied 8 bit RGBA
- downsample<unsigned char,4>(NR_PIXBLOCK_PX(out), 4, out->rs, width, height, NR_PIXBLOCK_PX(in), 4, in->rs, width_org, height_org, x_step_l2, y_step_l2);
- break;
- default:
- assert(false);
- };
- }
-
- // Horizontal filtering, goes from ssin -> out (ssin might be equal to out, but these algorithms can be used in-place)
- if (use_IIR_x) {
- // Filter variables
- IIRValue b[N+1]; // scaling coefficient + filter coefficients (can be 10.21 fixed point)
- double bf[N]; // computed filter coefficients
- double M[N*N]; // matrix used for initialization procedure (has to be double)
-
- // Compute filter (x)
- calcFilter(deviation_x, bf);
- for(size_t i=0; i<N; i++) bf[i] = -bf[i];
- b[0] = 1; // b[0] == alpha (scaling coefficient)
- for(size_t i=0; i<N; i++) {
- b[i+1] = bf[i];
- b[0] -= b[i+1];
- }
-
- // Compute initialization matrix (x)
- calcTriggsSdikaM(bf, M);
-
- // Filter (x)
- switch(in->mode) {
- case NR_PIXBLOCK_MODE_A8: ///< Grayscale
- filter2D_IIR<unsigned char,1,false>(NR_PIXBLOCK_PX(out), 1, out->rs, NR_PIXBLOCK_PX(ssin), 1, ssin->rs, width, height, b, M, tmpdata, NTHREADS);
- break;
- case NR_PIXBLOCK_MODE_R8G8B8: ///< 8 bit RGB
- filter2D_IIR<unsigned char,3,false>(NR_PIXBLOCK_PX(out), 3, out->rs, NR_PIXBLOCK_PX(ssin), 3, ssin->rs, width, height, b, M, tmpdata, NTHREADS);
- break;
- //case NR_PIXBLOCK_MODE_R8G8B8A8N: ///< Normal 8 bit RGBA
- // filter2D_IIR<unsigned char,4,false>(NR_PIXBLOCK_PX(out), 4, out->rs, NR_PIXBLOCK_PX(ssin), 4, ssin->rs, width, height, b, M, tmpdata, NTHREADS);
- // break;
- case NR_PIXBLOCK_MODE_R8G8B8A8P: ///< Premultiplied 8 bit RGBA
- filter2D_IIR<unsigned char,4,true >(NR_PIXBLOCK_PX(out), 4, out->rs, NR_PIXBLOCK_PX(ssin), 4, ssin->rs, width, height, b, M, tmpdata, NTHREADS);
- break;
- default:
- assert(false);
- };
- } else if ( scr_len_x > 0 ) { // !use_IIR_x
- // Filter kernel for x direction
- FIRValue kernel[scr_len_x+1];
- _make_kernel(kernel, deviation_x);
-
- // Filter (x)
- switch(in->mode) {
- case NR_PIXBLOCK_MODE_A8: ///< Grayscale
- filter2D_FIR<unsigned char,1>(NR_PIXBLOCK_PX(out), 1, out->rs, NR_PIXBLOCK_PX(ssin), 1, ssin->rs, width, height, kernel, scr_len_x, NTHREADS);
- break;
- case NR_PIXBLOCK_MODE_R8G8B8: ///< 8 bit RGB
- filter2D_FIR<unsigned char,3>(NR_PIXBLOCK_PX(out), 3, out->rs, NR_PIXBLOCK_PX(ssin), 3, ssin->rs, width, height, kernel, scr_len_x, NTHREADS);
- break;
- //case NR_PIXBLOCK_MODE_R8G8B8A8N: ///< Normal 8 bit RGBA
- // filter2D_FIR<unsigned char,4>(NR_PIXBLOCK_PX(out), 4, out->rs, NR_PIXBLOCK_PX(ssin), 4, ssin->rs, width, height, kernel, scr_len_x, NTHREADS);
- // break;
- case NR_PIXBLOCK_MODE_R8G8B8A8P: ///< Premultiplied 8 bit RGBA
- filter2D_FIR<unsigned char,4>(NR_PIXBLOCK_PX(out), 4, out->rs, NR_PIXBLOCK_PX(ssin), 4, ssin->rs, width, height, kernel, scr_len_x, NTHREADS);
- break;
- default:
- assert(false);
- };
- } else if ( out != ssin ) { // out can be equal to ssin if resampling is used
- nr_blit_pixblock_pixblock(out, ssin);
- }
-
- // Vertical filtering, goes from out -> out
- if (use_IIR_y) {
- // Filter variables
- IIRValue b[N+1]; // scaling coefficient + filter coefficients (can be 10.21 fixed point)
- double bf[N]; // computed filter coefficients
- double M[N*N]; // matrix used for initialization procedure (has to be double)
-
- // Compute filter (y)
- calcFilter(deviation_y, bf);
- for(size_t i=0; i<N; i++) bf[i] = -bf[i];
- b[0] = 1; // b[0] == alpha (scaling coefficient)
- for(size_t i=0; i<N; i++) {
- b[i+1] = bf[i];
- b[0] -= b[i+1];
- }
-
- // Compute initialization matrix (y)
- calcTriggsSdikaM(bf, M);
-
- // Filter (y)
- switch(in->mode) {
- case NR_PIXBLOCK_MODE_A8: ///< Grayscale
- filter2D_IIR<unsigned char,1,false>(NR_PIXBLOCK_PX(out), out->rs, 1, NR_PIXBLOCK_PX(out), out->rs, 1, height, width, b, M, tmpdata, NTHREADS);
- break;
- case NR_PIXBLOCK_MODE_R8G8B8: ///< 8 bit RGB
- filter2D_IIR<unsigned char,3,false>(NR_PIXBLOCK_PX(out), out->rs, 3, NR_PIXBLOCK_PX(out), out->rs, 3, height, width, b, M, tmpdata, NTHREADS);
- break;
- //case NR_PIXBLOCK_MODE_R8G8B8A8N: ///< Normal 8 bit RGBA
- // filter2D_IIR<unsigned char,4,false>(NR_PIXBLOCK_PX(out), out->rs, 4, NR_PIXBLOCK_PX(out), out->rs, 4, height, width, b, M, tmpdata, NTHREADS);
- // break;
- case NR_PIXBLOCK_MODE_R8G8B8A8P: ///< Premultiplied 8 bit RGBA
- filter2D_IIR<unsigned char,4,true >(NR_PIXBLOCK_PX(out), out->rs, 4, NR_PIXBLOCK_PX(out), out->rs, 4, height, width, b, M, tmpdata, NTHREADS);
- break;
- default:
- assert(false);
- };
- } else if ( scr_len_y > 0 ) { // !use_IIR_y
- // Filter kernel for y direction
- FIRValue kernel[scr_len_y+1];
- _make_kernel(kernel, deviation_y);
-
- // Filter (y)
- switch(in->mode) {
- case NR_PIXBLOCK_MODE_A8: ///< Grayscale
- filter2D_FIR<unsigned char,1>(NR_PIXBLOCK_PX(out), out->rs, 1, NR_PIXBLOCK_PX(out), out->rs, 1, height, width, kernel, scr_len_y, NTHREADS);
- break;
- case NR_PIXBLOCK_MODE_R8G8B8: ///< 8 bit RGB
- filter2D_FIR<unsigned char,3>(NR_PIXBLOCK_PX(out), out->rs, 3, NR_PIXBLOCK_PX(out), out->rs, 3, height, width, kernel, scr_len_y, NTHREADS);
- break;
- //case NR_PIXBLOCK_MODE_R8G8B8A8N: ///< Normal 8 bit RGBA
- // filter2D_FIR<unsigned char,4>(NR_PIXBLOCK_PX(out), out->rs, 4, NR_PIXBLOCK_PX(out), out->rs, 4, height, width, kernel, scr_len_y, NTHREADS);
- // break;
- case NR_PIXBLOCK_MODE_R8G8B8A8P: ///< Premultiplied 8 bit RGBA
- filter2D_FIR<unsigned char,4>(NR_PIXBLOCK_PX(out), out->rs, 4, NR_PIXBLOCK_PX(out), out->rs, 4, height, width, kernel, scr_len_y, NTHREADS);
- break;
- default:
- assert(false);
- };
- }
-
- for(int i=0; i<NTHREADS; i++) {
- delete[] tmpdata[i]; // deleting a nullptr has no effect, so this is safe
- }
-
- // Upsampling, stores (the upsampled) out using slot.set(_output, ...)
- if ( !resampling ) {
- // No upsampling needed
- out->empty = FALSE;
- slot.set(_output, out);
- } else {
- // New buffer for the final output, same resolution as the in buffer
- NRPixBlock *finalout = new NRPixBlock;
- nr_pixblock_setup_fast(finalout, in->mode, in->area.x0, in->area.y0,
- in->area.x1, in->area.y1, true);
- if (finalout->size != NR_PIXBLOCK_SIZE_TINY && finalout->data.px == NULL) {
- // alas, we've accomplished a lot, but ran out of memory - so abort
- if (in != original_in) nr_pixblock_free(in);
- nr_pixblock_release(out);
- delete out;
- return 0;
- }
-
- // Upsample
- switch(in->mode) {
- case NR_PIXBLOCK_MODE_A8: ///< Grayscale
- upsample<unsigned char,1>(NR_PIXBLOCK_PX(finalout), 1, finalout->rs, width_org, height_org, NR_PIXBLOCK_PX(out), 1, out->rs, width, height, x_step_l2, y_step_l2);
- break;
- case NR_PIXBLOCK_MODE_R8G8B8: ///< 8 bit RGB
- upsample<unsigned char,3>(NR_PIXBLOCK_PX(finalout), 3, finalout->rs, width_org, height_org, NR_PIXBLOCK_PX(out), 3, out->rs, width, height, x_step_l2, y_step_l2);
- break;
- //case NR_PIXBLOCK_MODE_R8G8B8A8N: ///< Normal 8 bit RGBA
- // upsample<unsigned char,4>(NR_PIXBLOCK_PX(finalout), 4, finalout->rs, width_org, height_org, NR_PIXBLOCK_PX(out), 4, out->rs, width, height, x_step_l2, y_step_l2);
- // break;
- case NR_PIXBLOCK_MODE_R8G8B8A8P: ///< Premultiplied 8 bit RGBA
- upsample<unsigned char,4>(NR_PIXBLOCK_PX(finalout), 4, finalout->rs, width_org, height_org, NR_PIXBLOCK_PX(out), 4, out->rs, width, height, x_step_l2, y_step_l2);
- break;
- default:
- assert(false);
- };
-
- // We don't need the out buffer anymore
- nr_pixblock_release(out);
- delete out;
-
- // The final out buffer gets returned
- finalout->empty = FALSE;
- slot.set(_output, finalout);
- }
-
- // If we downsampled the input, clean up the downsampled data
- if (in != original_in) nr_pixblock_free(in);
-
- return 0;
-}
-
void FilterGaussian::area_enlarge(NRRectL &area, Geom::Matrix const &trans)
{
int area_x = _effect_area_scr(_deviation_x * trans.expansionX());
@@ -1057,8 +646,14 @@ void FilterGaussian::area_enlarge(NRRectL &area, Geom::Matrix const &trans)
area.y1 += area_max;
}
-FilterTraits FilterGaussian::get_input_traits() {
- return TRAIT_PARALLER;
+bool FilterGaussian::can_handle_affine(Geom::Matrix const &m)
+{
+ if (Geom::are_near(_deviation_x, _deviation_y)) {
+ // TODO after 2Geom sync, change this to m.preservesAngles()
+ return Geom::are_near(m[0], m[3]) && Geom::are_near(m[1], -m[2]);
+ } else {
+ return false;
+ }
}
void FilterGaussian::set_deviation(double deviation)
diff --git a/src/display/nr-filter-gaussian.h b/src/display/nr-filter-gaussian.h
index 7bcabdba9..01ce9efcb 100644
--- a/src/display/nr-filter-gaussian.h
+++ b/src/display/nr-filter-gaussian.h
@@ -39,9 +39,8 @@ public:
virtual ~FilterGaussian();
virtual void render_cairo(FilterSlot &slot);
- virtual int render(FilterSlot &slot, FilterUnits const &units);
virtual void area_enlarge(NRRectL &area, Geom::Matrix const &m);
- virtual FilterTraits get_input_traits();
+ virtual bool can_handle_affine(Geom::Matrix const &m);
/**
* Set the standard deviation value for gaussian blur. Deviation along
diff --git a/src/display/nr-filter-primitive.h b/src/display/nr-filter-primitive.h
index a7ae0125e..89927fdbd 100644
--- a/src/display/nr-filter-primitive.h
+++ b/src/display/nr-filter-primitive.h
@@ -44,7 +44,7 @@ public:
virtual ~FilterPrimitive();
virtual void render_cairo(FilterSlot &slot);
- virtual int render(FilterSlot &slot, FilterUnits const &units) = 0;
+ virtual int render(FilterSlot &slot, FilterUnits const &units) { return 0; }
virtual void area_enlarge(NRRectL &area, Geom::Matrix const &m);
/**
@@ -109,6 +109,20 @@ public:
*/
virtual FilterTraits get_input_traits();
+ /** @brief Indicate whether the filter primitive can handle the given affine.
+ *
+ * Results of some filter primitives depend on the coordinate system used when rendering.
+ * A gaussian blur will equal x and y deviation will remain unchanged by rotations.
+ * Per-pixel filters like color matrix and blend will not change regardless of
+ * the transformation.
+ *
+ * When any filter returns false, filter rendering is performed on an intermediate surface
+ * with edges parallel to the axes of the user coordinate system. This means
+ * the matrices from FilterUnits will contain at most a (possibly non-uniform) scale
+ * and a translation. When all primitives of the filter return false, the rendering is
+ * performed in display coordinate space and no intermediate surface is used. */
+ virtual bool can_handle_affine(Geom::Matrix const &) { return false; }
+
protected:
int _input;
int _output;
diff --git a/src/display/nr-filter-slot.cpp b/src/display/nr-filter-slot.cpp
index d700cd433..5371499e4 100644
--- a/src/display/nr-filter-slot.cpp
+++ b/src/display/nr-filter-slot.cpp
@@ -20,7 +20,6 @@
#include "display/nr-filter-types.h"
#include "display/nr-filter-gaussian.h"
#include "display/nr-filter-slot.h"
-#include "display/nr-filter-getalpha.h"
#include "display/nr-filter-units.h"
#include "display/pixblock-scaler.h"
#include "display/pixblock-transform.h"
@@ -131,10 +130,9 @@ cairo_surface_t *FilterSlot::getcairo(int slot_nr)
cairo_surface_destroy(tr);
} break;
case NR_FILTER_BACKGROUNDIMAGE: {
- // TODO
- //cairo_surface_t *bg = _get_transformed_background();
- //_set_internal(NR_FILTER_BACKGROUNDIMAGE, bg);
- //cairo_surface_destroy(bg);
+ cairo_surface_t *bg = _get_transformed_background();
+ _set_internal(NR_FILTER_BACKGROUNDIMAGE, bg);
+ cairo_surface_destroy(bg);
} break;
case NR_FILTER_SOURCEALPHA: {
cairo_surface_t *src = getcairo(NR_FILTER_SOURCEGRAPHIC);
@@ -158,8 +156,12 @@ cairo_surface_t *FilterSlot::getcairo(int slot_nr)
if (s == _slots.end()) {
// create empty surface
- // TODO
- return NULL;
+ cairo_surface_t *empty = cairo_surface_create_similar(
+ _source_graphic, cairo_surface_get_content(_source_graphic),
+ _slot_area.x1 - _slot_area.x0, _slot_area.y1 - _slot_area.y0);
+ _set_internal(slot_nr, empty);
+ cairo_surface_destroy(empty);
+ s = _slots.find(slot_nr);
}
return s->second;
@@ -189,7 +191,23 @@ cairo_surface_t *FilterSlot::_get_transformed_source_graphic()
cairo_surface_t *FilterSlot::_get_transformed_background()
{
- return NULL;
+ Geom::Matrix trans = _units.get_matrix_display2pb();
+
+ cairo_surface_t *bg = cairo_get_target(_background_ct);
+ cairo_surface_t *tbg = cairo_surface_create_similar(
+ bg, cairo_surface_get_content(bg),
+ _slot_area.x1 - _slot_area.x0, _slot_area.y1 - _slot_area.y0);
+ cairo_t *tbg_ct = cairo_create(tbg);
+
+ cairo_translate(tbg_ct, -_slot_area.x0, -_slot_area.y0);
+ ink_cairo_transform(tbg_ct, trans);
+ cairo_translate(tbg_ct, _background_area->x0, _background_area->y0);
+ cairo_set_source_surface(tbg_ct, bg, 0, 0);
+ cairo_set_operator(tbg_ct, CAIRO_OPERATOR_SOURCE);
+ cairo_paint(tbg_ct);
+ cairo_destroy(tbg_ct);
+
+ return tbg;
}
cairo_surface_t *FilterSlot::get_result(int res)
@@ -299,11 +317,6 @@ void FilterSlot::set(int slot_nr, cairo_surface_t *surface)
trans[1] * x1 + trans[3] * y0 + trans[5],
trans[1] * x1 + trans[3] * y1 + trans[5]);
- cairo_surface_t *trans_s = cairo_surface_create_similar(s,
- CAIRO_CONTENT_COLOR, max_x - min_x, max_y - min_y);
- cairo_t *ct = cairo_create(trans_s);
-
-
nr_pixblock_setup_fast(trans_pb, pb->mode,
min_x, min_y,
max_x, max_y, true);