Code

Added renderer support for feBlend filter effect
authorkiirala <kiirala@users.sourceforge.net>
Mon, 14 May 2007 12:54:58 +0000 (12:54 +0000)
committerkiirala <kiirala@users.sourceforge.net>
Mon, 14 May 2007 12:54:58 +0000 (12:54 +0000)
src/display/Makefile_insert
src/display/nr-arena-group.cpp
src/display/nr-arena-image.cpp
src/display/nr-arena-shape.cpp
src/display/nr-filter-blend.cpp [new file with mode: 0644]
src/display/nr-filter-blend.h [new file with mode: 0644]
src/display/nr-filter.cpp
src/sp-feblend.cpp
src/sp-feblend.h

index ad69c772b0b26a5bda243cbafecc8016720c0a7e..95502170a22118c7841612b492b4cdb43c55a9d8 100644 (file)
@@ -69,6 +69,8 @@ display_libspdisplay_a_SOURCES = \
        display/nr-filter-primitive.h   \
        display/nr-filter-gaussian.cpp  \
        display/nr-filter-gaussian.h    \
+       display/nr-filter-blend.cpp     \
+       display/nr-filter-blend.h       \
        display/nr-filter-slot.cpp      \
        display/nr-filter-slot.h        \
        display/nr-filter-types.h       \
index 0678eb37ecf3672668d353faae60e50ca56f1725..697ef6a056af17486335b46001763067593c099c 100644 (file)
@@ -19,6 +19,8 @@
 #include "style.h"
 #include "sp-filter.h"
 #include "sp-gaussian-blur.h"
+#include "sp-feblend.h"
+#include "display/nr-filter-blend.h"
 
 static void nr_arena_group_class_init (NRArenaGroupClass *klass);
 static void nr_arena_group_init (NRArenaGroup *group);
@@ -219,6 +221,12 @@ void nr_arena_group_set_style (NRArenaGroup *group, SPStyle *style)
                     else
                         gaussian->set_deviation((double) num);
                 }
+            } else if(SP_IS_FEBLEND(primitive)) {
+                // TODO: this is just a test. Besides this whole filter
+                // creation needs to be redone
+                NR::FilterBlend *nrblend = (NR::FilterBlend *) group->filter->add_primitive(NR::NR_FILTER_BLEND);
+                SPFeBlend *spblend = SP_FEBLEND(primitive);
+                nrblend->set_mode(spblend->blend_mode);
             }
         }
     }
index 1b4f3341c8b4b12e85da3e2655dc0afd644224ce..964f7e86f769661c9b282f1f33d7de0c1e0e6f8c 100644 (file)
@@ -24,6 +24,8 @@
 #include <livarot/Shape.h>
 #include "sp-filter.h"
 #include "sp-gaussian-blur.h"
+#include "sp-feblend.h"
+#include "display/nr-filter-blend.h"
 
 int nr_arena_image_x_sample = 1;
 int nr_arena_image_y_sample = 1;
@@ -392,6 +394,12 @@ void nr_arena_image_set_style (NRArenaImage *image, SPStyle *style)
                     else
                         gaussian->set_deviation((double) num);
                 }
+            } else if(SP_IS_FEBLEND(primitive)) {
+                // TODO: this is just a test. Besides this whole filter
+                // creation needs to be redone
+                NR::FilterBlend *nrblend = (NR::FilterBlend *) image->filter->add_primitive(NR::NR_FILTER_BLEND);
+                SPFeBlend *spblend = SP_FEBLEND(primitive);
+                nrblend->set_mode(spblend->blend_mode);
             }
         }
     }
index c5551695fc84514c788a005b19f49df9e0845f15..421627309d5f5e7648bd19cae0772b7d4f72437b 100644 (file)
@@ -17,9 +17,6 @@
 #include <display/canvas-arena.h>
 #include <display/nr-arena.h>
 #include <display/nr-arena-shape.h>
-#include "display/nr-filter.h"
-#include "display/nr-filter-gaussian.h"
-#include "display/nr-filter-types.h"
 #include <libnr/n-art-bpath.h>
 #include <libnr/nr-path.h>
 #include <libnr/nr-pixops.h>
 #include <style.h>
 #include "prefs-utils.h"
 #include "sp-filter.h"
-#include "sp-gaussian-blur.h"
 #include "inkscape-cairo.h"
 
+#include "display/nr-filter.h"
+#include "display/nr-filter-gaussian.h"
+#include "display/nr-filter-types.h"
+#include "sp-gaussian-blur.h"
+#include "sp-feblend.h"
+#include "display/nr-filter-blend.h"
+
 #include <cairo.h>
 
 //int  showRuns=0;
@@ -1386,6 +1389,12 @@ nr_arena_shape_set_style(NRArenaShape *shape, SPStyle *style)
                     else
                         gaussian->set_deviation((double) num);
                 }
+            } else if(SP_IS_FEBLEND(primitive)) {
+                // TODO: this is just a test. Besides this whole filter
+                // creation needs to be redone
+                NR::FilterBlend *nrblend = (NR::FilterBlend *) shape->filter->add_primitive(NR::NR_FILTER_BLEND);
+                SPFeBlend *spblend = SP_FEBLEND(primitive);
+                nrblend->set_mode(spblend->blend_mode);
             }
         }
     }
diff --git a/src/display/nr-filter-blend.cpp b/src/display/nr-filter-blend.cpp
new file mode 100644 (file)
index 0000000..e36574d
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ * SVG feBlend renderer
+ *
+ * "This filter composites two objects together using commonly used
+ * imaging software blending modes. It performs a pixel-wise combination
+ * of two input images." 
+ * http://www.w3.org/TR/SVG11/filters.html#feBlend
+ *
+ * Authors:
+ *   Niko Kiirala <niko@kiirala.com>
+ *
+ * Copyright (C) 2007 authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "display/nr-filter-blend.h"
+#include "display/nr-filter-primitive.h"
+#include "display/nr-filter-slot.h"
+#include "display/nr-filter-types.h"
+#include "libnr/nr-pixblock.h"
+#include "libnr/nr-matrix.h"
+#include "libnr/nr-blit.h"
+
+static inline int clamp(const int val, const int min, const int max) {
+    if (val < min) return min;
+    if (val > max) return max;
+    return val;
+}
+
+template <void(*blend)(unsigned char *cr, unsigned char const *ca, unsigned char const *cb)>
+static void _render(NRPixBlock &out, NRPixBlock &in1, NRPixBlock &in2) {
+    unsigned char *in1_data = NR_PIXBLOCK_PX(&in1);
+    unsigned char *in2_data = NR_PIXBLOCK_PX(&in2);
+    unsigned char *out_data = NR_PIXBLOCK_PX(&out);
+    unsigned char zero_rgba[4] = {0, 0, 0, 0};
+
+    if (in1.area.y0 < in2.area.y0) {
+        // in1 begins before in2 on y-axis
+        for (int y = in1.area.y0 ; y < in2.area.y0 ; y++) {
+            int out_line = (y - out.area.y0) * out.rs;
+            int in_line = (y - in1.area.y0) * in1.rs;
+            for (int x = in1.area.x0 ; x < in1.area.x1 ; x++) {
+                blend(out_data + out_line + 4 * (x - out.area.x0),
+                      in1_data + in_line + 4 * (x - in1.area.x0),
+                      zero_rgba);
+            }
+        }
+    } else if (in1.area.y0 > in2.area.y0) {
+        // in2 begins before in1 on y-axis
+        for (int y = in2.area.y0 ; y < in1.area.y0 ; y++) {
+            int out_line = (y - out.area.y0) * out.rs;
+            int in_line = (y - in2.area.y0) * in2.rs;
+            for (int x = in2.area.x0 ; x < in2.area.x1 ; x++) {
+                blend(out_data + out_line + 4 * (x - out.area.x0),
+                      zero_rgba,
+                      in2_data + in_line + 4 * (x - in2.area.x0));
+            }
+        }
+    }
+
+    for (int y = std::max(in1.area.y0, in2.area.y0) ;
+         y < std::min(in1.area.y1, in2.area.y1) ; ++y) {
+        int out_line = (y - out.area.y0) * out.rs;
+        int in1_line = (y - in1.area.y0) * in1.rs;
+        int in2_line = (y - in2.area.y0) * in2.rs;
+
+        if (in1.area.x0 < in2.area.x0) {
+            // in1 begins before in2 on x-axis
+            for (int x = in1.area.x0 ; x < in2.area.x0 ; ++x) {
+                blend(out_data + out_line + 4 * (x - out.area.x0),
+                      in1_data + in1_line + 4 * (x - in1.area.x0),
+                      zero_rgba);
+            }
+        } else if (in1.area.x0 > in2.area.x0) {
+            // in2 begins before in1 on x-axis
+            for (int x = in2.area.x0 ; x < in1.area.x0 ; ++x) {
+                blend(out_data + out_line + 4 * (x - out.area.x0),
+                      zero_rgba,
+                      in2_data + in2_line + 4 * (x - in2.area.x0));
+            }
+        }
+
+        for (int x = std::max(in1.area.x0, in2.area.x0) ;
+             x < std::min(in1.area.x1, in2.area.x1) ; ++x) {
+            blend(out_data + out_line + 4 * (x - out.area.x0),
+                  in1_data + in1_line + 4 * (x - in1.area.x0),
+                  in2_data + in2_line + 4 * (x - in2.area.x0));
+        }
+
+        if (in1.area.x1 > in2.area.x1) {
+            // in1 ends after in2 on x-axis
+            for (int x = in2.area.x1 ; x < in1.area.x1 ; ++x) {
+                blend(out_data + out_line + 4 * (x - out.area.x0),
+                      in1_data + in1_line + 4 * (x - in1.area.x0),
+                      zero_rgba);
+            }
+        } else if (in1.area.x1 < in2.area.x1) {
+            // in2 ends after in1 on x-axis
+            for (int x = in1.area.x1 ; x < in2.area.x1 ; ++x) {
+                blend(out_data + out_line + 4 * (x - out.area.x0),
+                      zero_rgba,
+                      in2_data + in2_line + 4 * (x - in2.area.x0));
+            }
+        }
+    }
+
+    if (in1.area.y1 > in2.area.y1) {
+        // in1 ends after in2 on y-axis
+        for (int y = in2.area.y1 ; y < in1.area.y1 ; y++) {
+            int out_line = (y - out.area.y0) * out.rs;
+            int in_line = (y - in1.area.y0) * in1.rs;
+            for (int x = in1.area.x0 ; x < in1.area.x1 ; x++) {
+                blend(out_data + out_line + 4 * (x - out.area.x0),
+                      in1_data + in_line + 4 * (x - in1.area.x0),
+                      zero_rgba);
+            }
+        }
+    } else if (in1.area.y1 < in2.area.y1) {
+        // in2 ends after in1 on y-axis
+        for (int y = in1.area.y1 ; y < in2.area.y1 ; y++) {
+            int out_line = (y - out.area.y0) * out.rs;
+            int in_line = (y - in2.area.y0) * in2.rs;
+            for (int x = in2.area.x0 ; x < in2.area.x1 ; x++) {
+                blend(out_data + out_line + 4 * (x - out.area.x0),
+                      zero_rgba,
+                      in2_data + in_line + 4 * (x - in2.area.x0));
+            }
+        }
+    }
+}
+
+/*
+ * From http://www.w3.org/TR/SVG11/filters.html#feBlend
+ *
+ * For all feBlend modes, the result opacity is computed as follows:
+ * qr = 1 - (1-qa)*(1-qb)
+ *
+ * For the compositing formulas below, the following definitions apply:
+ * cr = Result color (RGB) - premultiplied
+ * qa = Opacity value at a given pixel for image A
+ * qb = Opacity value at a given pixel for image B
+ * ca = Color (RGB) at a given pixel for image A - premultiplied
+ * cb = Color (RGB) at a given pixel for image B - premultiplied
+*/
+
+// cr = (1 - qa) * cb + ca
+inline void blend_normal(unsigned char *r, unsigned char const *a, unsigned char const *b) {
+    r[0] = (((255 - a[3]) * b[0]) >> 8) + a[0];
+    r[1] = (((255 - a[3]) * b[1]) >> 8) + a[1];
+    r[2] = (((255 - a[3]) * b[2]) >> 8) + a[2];
+    r[3] = 255 - (((255 - a[3]) * (255 - b[3])) >> 8);
+}
+
+// cr = (1-qa)*cb + (1-qb)*ca + ca*cb
+inline void blend_multiply(unsigned char *r, unsigned char const *a, unsigned char const *b) {
+    r[0] = ((255 - a[3]) * b[0] + (255 - b[3]) * a[0] + a[0] * b[0]) >> 8;
+    r[1] = ((255 - a[3]) * b[1] + (255 - b[3]) * a[1] + a[1] * b[1]) >> 8;
+    r[2] = ((255 - a[3]) * b[2] + (255 - b[3]) * a[2] + a[2] * b[2]) >> 8;
+    r[3] = 255 - (((255 - a[3]) * (255 - b[3])) >> 8);
+}
+
+// cr = cb + ca - ca * cb
+inline void blend_screen(unsigned char *r, unsigned char const *a, unsigned char const *b) {
+    r[0] = b[0] + a[0] - ((a[0] * b[0]) >> 8);
+    r[1] = b[1] + a[1] - ((a[1] * b[1]) >> 8);
+    r[2] = b[2] + a[2] - ((a[2] * b[2]) >> 8);
+    r[3] = 255 - (((255 - a[3]) * (255 - b[3])) >> 8);
+}
+
+// cr = Min ((1 - qa) * cb + ca, (1 - qb) * ca + cb)
+inline void blend_darken(unsigned char *r, unsigned char const *a, unsigned char const *b) {
+    r[0] = std::min((((255 - a[3]) * b[0]) >> 8) + a[0],
+                    (((255 - b[3]) * a[0]) >> 8) + b[0]);
+    r[1] = std::min((((255 - a[3]) * b[1]) >> 8) + a[1],
+                    (((255 - b[3]) * a[1]) >> 8) + b[1]);
+    r[2] = std::min((((255 - a[3]) * b[2]) >> 8) + a[2],
+                    (((255 - b[3]) * a[2]) >> 8) + b[2]);
+    r[3] = 255 - (((255 - a[3]) * (255 - b[3])) >> 8);
+}
+
+// cr = Max ((1 - qa) * cb + ca, (1 - qb) * ca + cb)
+inline void blend_lighten(unsigned char *r, unsigned char const *a, unsigned char const *b) {
+    r[0] = std::max((((255 - a[3]) * b[0]) >> 8) + a[0],
+                    (((255 - b[3]) * a[0]) >> 8) + b[0]);
+    r[1] = std::max((((255 - a[3]) * b[1]) >> 8) + a[1],
+                    (((255 - b[3]) * a[1]) >> 8) + b[1]);
+    r[2] = std::max((((255 - a[3]) * b[2]) >> 8) + a[2],
+                    (((255 - b[3]) * a[2]) >> 8) + b[2]);
+    r[3] = 255 - (((255 - a[3]) * (255 - b[3])) >> 8);
+}
+
+namespace NR {
+
+FilterBlend::FilterBlend() 
+    : _blend_mode(BLEND_NORMAL),
+      _input2(NR_FILTER_SLOT_NOT_SET)
+{}
+
+FilterPrimitive * FilterBlend::create() {
+    return new FilterBlend();
+}
+
+FilterBlend::~FilterBlend()
+{}
+
+int FilterBlend::render(FilterSlot &slot, Matrix const &trans) {
+    NRPixBlock *in1 = slot.get(_input);
+    NRPixBlock *in2 = slot.get(_input2);
+    NRPixBlock *original_in1 = in1;
+    NRPixBlock *original_in2 = in2;
+    NRPixBlock *out;
+
+    // Bail out if either one of source images is missing
+    if (!in1 || !in2) {
+        g_warning("Missing source image for feBlend (in=%d in2=%d)", _input, _input2);
+        return 1;
+    }
+
+    out = new NRPixBlock;
+    NRRectL out_area;
+    nr_rect_l_union(&out_area, &in1->area, &in2->area);
+    nr_pixblock_setup_fast(out, NR_PIXBLOCK_MODE_R8G8B8A8P,
+                           out_area.x0, out_area.y0, out_area.x1, out_area.y1,
+                           true);
+
+    // Blending modes are defined for premultiplied RGBA values,
+    // thus convert them to that format before blending
+    if (in1->mode != NR_PIXBLOCK_MODE_R8G8B8A8P) {
+        in1 = new NRPixBlock;
+        nr_pixblock_setup_fast(in1, NR_PIXBLOCK_MODE_R8G8B8A8P,
+                               original_in1->area.x0, original_in1->area.y0,
+                               original_in1->area.x1, original_in1->area.y1,
+                               false);
+        nr_blit_pixblock_pixblock(in1, original_in1);
+    }
+    if (in2->mode != NR_PIXBLOCK_MODE_R8G8B8A8P) {
+        in2 = new NRPixBlock;
+        nr_pixblock_setup_fast(in2, NR_PIXBLOCK_MODE_R8G8B8A8P,
+                               original_in2->area.x0, original_in2->area.y0,
+                               original_in2->area.x1, original_in2->area.y1,
+                               false);
+        nr_blit_pixblock_pixblock(in2, original_in2);
+    }
+
+    switch (_blend_mode) {
+        case BLEND_MULTIPLY:
+            _render<blend_multiply>(*out, *in1, *in2);
+            break;
+        case BLEND_SCREEN:
+            _render<blend_screen>(*out, *in1, *in2);
+            break;
+        case BLEND_DARKEN:
+            _render<blend_darken>(*out, *in1, *in2);
+            break;
+        case BLEND_LIGHTEN:
+            _render<blend_lighten>(*out, *in1, *in2);
+            break;
+        case BLEND_NORMAL:
+        default:
+            _render<blend_normal>(*out, *in1, *in2);
+            break;
+    }
+
+    if (in1 != original_in1) {
+        nr_pixblock_release(in1);
+        delete in1;
+    }
+    if (in2 != original_in2) {
+        nr_pixblock_release(in2);
+        delete in2;
+    }
+
+    out->empty = FALSE;
+    slot.set(_output, out);
+
+    return 0;
+}
+
+void FilterBlend::set_input(int slot) {
+    _input = slot;
+}
+
+void FilterBlend::set_input(int input, int slot) {
+    if (input == 0) _input = slot;
+    if (input == 1) _input2 = slot;
+}
+
+void FilterBlend::set_mode(FilterBlendMode mode) {
+    if (mode == BLEND_NORMAL || mode == BLEND_MULTIPLY ||
+        mode == BLEND_SCREEN || mode == BLEND_DARKEN ||
+        mode == BLEND_LIGHTEN)
+    {
+        _blend_mode = mode;
+    }
+}
+
+} /* 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-blend.h b/src/display/nr-filter-blend.h
new file mode 100644 (file)
index 0000000..4787e33
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef __NR_FILTER_BLEND_H__
+#define __NR_FILTER_BLEND_H__
+
+/*
+ * SVG feBlend renderer
+ *
+ * "This filter composites two objects together using commonly used
+ * imaging software blending modes. It performs a pixel-wise combination
+ * of two input images." 
+ * http://www.w3.org/TR/SVG11/filters.html#feBlend
+ *
+ * Authors:
+ *   Niko Kiirala <niko@kiirala.com>
+ *
+ * Copyright (C) 2007 authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "display/nr-filter-primitive.h"
+#include "display/nr-filter-slot.h"
+#include "libnr/nr-matrix.h"
+
+namespace NR {
+
+enum FilterBlendMode {
+    BLEND_NORMAL,
+    BLEND_MULTIPLY,
+    BLEND_SCREEN,
+    BLEND_DARKEN,
+    BLEND_LIGHTEN
+};
+
+class FilterBlend : public FilterPrimitive {
+public:
+    FilterBlend();
+    static FilterPrimitive *create();
+    virtual ~FilterBlend();
+
+    virtual int render(FilterSlot &slot, Matrix const &trans);
+
+    virtual void set_input(int slot);
+    virtual void set_input(int input, int slot);
+    void set_mode(FilterBlendMode mode);
+
+private:
+    FilterBlendMode _blend_mode;
+    int _input2;
+};
+
+
+} /* namespace NR */
+
+
+
+
+#endif /* __NR_FILTER_BLEND_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 :
index 07c2649289b128fa9b9657ab3cd171ce4b390251..fe33afff0b56cb2f3eac244cd663a78231587f0b 100644 (file)
 
 #include "display/nr-filter.h"
 #include "display/nr-filter-primitive.h"
-#include "display/nr-filter-gaussian.h"
 #include "display/nr-filter-slot.h"
 #include "display/nr-filter-types.h"
 #include "display/pixblock-scaler.h"
 #include "display/pixblock-transform.h"
+#include "display/nr-filter-gaussian.h"
+#include "display/nr-filter-blend.h"
 
 #include "display/nr-arena-item.h"
 #include "libnr/nr-pixblock.h"
@@ -63,7 +64,7 @@ Filter::Filter()
     _primitive_count = 0;
     _primitive_table_size = 1;
     _primitive = new FilterPrimitive*[1];
-       _primitive[0] = NULL;
+    _primitive[0] = NULL;
     //_primitive_count = 1;
     //_primitive[0] = new FilterGaussian;
     _common_init();
@@ -213,8 +214,9 @@ int Filter::render(NRArenaItem const *item, NRPixBlock *pb)
     slot.set(NR_FILTER_SOURCEGRAPHIC, in);
     in = NULL; // in is now handled by FilterSlot, we should not touch it
 
-    // TODO: loop through ALL the primitives and render them one at a time
-    _primitive[0]->render(slot, paraller_trans);
+    for (int i = 0 ; i < _primitive_count ; i++) {
+        _primitive[i]->render(slot, paraller_trans);
+    }
     NRPixBlock *out = slot.get(_output_slot);
 
     // Clear the pixblock, where the output will be put
@@ -310,7 +312,7 @@ void Filter::_create_constructor_table()
     if(created) return;
 
     /* Filter effects not yet implemented are set to NULL */
-    _constructor[NR_FILTER_BLEND] = NULL;
+    _constructor[NR_FILTER_BLEND] = &FilterBlend::create;
     _constructor[NR_FILTER_COLORMATRIX] = NULL;
     _constructor[NR_FILTER_COMPONENTTRANSFER] = NULL;
     _constructor[NR_FILTER_COMPOSITE] = NULL;
index 7448dd4ab66ad1aa2b557ac6da5d873ecfcc46a9..55c387e0036570e92ee7a7ffdd3a8c7ac3ec72e0 100644 (file)
@@ -6,9 +6,10 @@
  */
 /*
  * Authors:
- *   hugo Rodrigues <haa.rodrigues@gmail.com>
+ *   Hugo Rodrigues <haa.rodrigues@gmail.com>
+ *   Niko Kiirala <niko@kiirala.com>
  *
- * Copyright (C) 2006 Hugo Rodrigues
+ * Copyright (C) 2006,2007 authors
  *
  * Released under GNU GPL, read the file 'COPYING' for more information
  */
 # include "config.h"
 #endif
 
+#include <string.h>
+
 #include "attributes.h"
 #include "svg/svg.h"
 #include "sp-feblend.h"
 #include "xml/repr.h"
 
+#include "display/nr-filter-blend.h"
 
 /* FeBlend base class */
 
@@ -89,6 +93,7 @@ sp_feBlend_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *re
     }
 
     /*LOAD ATTRIBUTES FROM REPR HERE*/
+    sp_object_read_attr(object, "mode");
 }
 
 /**
@@ -101,6 +106,37 @@ sp_feBlend_release(SPObject *object)
         ((SPObjectClass *) feBlend_parent_class)->release(object);
 }
 
+static NR::FilterBlendMode sp_feBlend_readmode(gchar const *value)
+{
+    if (!value) return NR::BLEND_NORMAL;
+    switch (value[0]) {
+        case 'n':
+            if (strncmp(value, "normal", 6) == 0)
+                return NR::BLEND_NORMAL;
+            break;
+        case 'm':
+            if (strncmp(value, "multiply", 8) == 0)
+                return NR::BLEND_MULTIPLY;
+            break;
+        case 's':
+            if (strncmp(value, "screen", 6) == 0)
+                return NR::BLEND_SCREEN;
+            break;
+        case 'd':
+            if (strncmp(value, "darken", 6) == 0)
+                return NR::BLEND_DARKEN;
+            break;
+        case 'l':
+            if (strncmp(value, "lighten", 7) == 0)
+                return NR::BLEND_LIGHTEN;
+            break;
+        default:
+            // do nothing by default
+            break;
+    }
+    return NR::BLEND_NORMAL;
+}
+
 /**
  * Sets a specific value in the SPFeBlend.
  */
@@ -112,6 +148,9 @@ sp_feBlend_set(SPObject *object, unsigned int key, gchar const *value)
 
     switch(key) {
        /*DEAL WITH SETTING ATTRIBUTES HERE*/
+        case SP_ATTR_MODE:
+            feBlend->blend_mode = sp_feBlend_readmode(value);
+            break;
         default:
             if (((SPObjectClass *) feBlend_parent_class)->set)
                 ((SPObjectClass *) feBlend_parent_class)->set(object, key, value);
@@ -148,7 +187,7 @@ sp_feBlend_write(SPObject *object, Inkscape::XML::Node *repr, guint flags)
     if (flags & SP_OBJECT_WRITE_EXT) {
         if (repr) {
             // is this sane?
-            repr->mergeFrom(SP_OBJECT_REPR(object), "id");
+            // repr->mergeFrom(SP_OBJECT_REPR(object), "id");
         } else {
             repr = SP_OBJECT_REPR(object)->duplicate(NULL); // FIXME
         }
index dea1100a3b86d54c04acff9640a4c61505ef80b2..90ab8967f589dd05a7eeacd92db593464cffc70c 100644 (file)
@@ -7,8 +7,9 @@
 /*
  * Authors:
  *   Hugo Rodrigues <haa.rodrigues@gmail.com>
+ *   Niko Kiirala <niko@kiirala.com>
  *
- * Copyright (C) 2006 Hugo Rodrigues
+ * Copyright (C) 2006,2007 authors
  *
  * Released under GNU GPL, read the file 'COPYING' for more information
  */
 #include "sp-filter.h"
 #include "sp-feblend-fns.h"
 
+#include "display/nr-filter-blend.h"
+
 /* FeBlend base class */
 class SPFeBlendClass;
 
 struct SPFeBlend : public SPFilterPrimitive {
     /** BLEND ATTRIBUTES HERE */
-    
+    NR::FilterBlendMode blend_mode;
 };
 
 struct SPFeBlendClass {