[lasem] feDisplacementMap: algorithm from librsvg



commit 52a96feef97ee76f12241a452269626ebdb61362
Author: Emmanuel Pacaud <emmanuel gnome org>
Date:   Sun Aug 16 23:44:00 2015 +0200

    feDisplacementMap: algorithm from librsvg

 docs/reference/lasem/Makefile.am                 |    1 +
 src/Makefile.am                                  |    2 +
 src/lsmsvgattributes.h                           |    5 +
 src/lsmsvgdocument.c                             |    3 +
 src/lsmsvgenums.c                                |   23 +++
 src/lsmsvgenums.h                                |   11 ++
 src/lsmsvgfilterdisplacementmap.c                |  124 ++++++++++++++++
 src/lsmsvgfilterdisplacementmap.h                |   60 ++++++++
 src/lsmsvgfiltersurface.c                        |  163 ++++++++++++++++++++++
 src/lsmsvgfiltersurface.h                        |    6 +
 src/lsmsvgtraits.c                               |   24 +++
 src/lsmsvgtraits.h                               |    1 +
 src/lsmsvgtypes.h                                |    1 +
 src/lsmsvgview.c                                 |   34 +++++
 src/lsmsvgview.h                                 |    4 +
 tests/data/svg/svg1.1/images/DisplaceChecker.png |  Bin 0 -> 2470 bytes
 tests/data/svg/svg1.1/images/rotate20.png        |  Bin 0 -> 1434 bytes
 tests/data/svg/svg1.1/images/sphere.png          |  Bin 0 -> 5923 bytes
 tests/filter.c                                   |   20 ++-
 19 files changed, 475 insertions(+), 7 deletions(-)
---
diff --git a/docs/reference/lasem/Makefile.am b/docs/reference/lasem/Makefile.am
index 5b3c4fe..8db4934 100644
--- a/docs/reference/lasem/Makefile.am
+++ b/docs/reference/lasem/Makefile.am
@@ -155,6 +155,7 @@ IGNORE_HFILES=\
        lsmsvgfiltercolormatrix.h               \
        lsmsvgfiltercomposite.h                 \
        lsmsvgfilterconvolvematrix.h            \
+       lsmsvgfilterdisplacementmap.h           \
        lsmsvgfilterflood.h                     \
        lsmsvgfiltergaussianblur.h              \
        lsmsvgfilterimage.h                     \
diff --git a/src/Makefile.am b/src/Makefile.am
index e7053a2..dbc5c87 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -137,6 +137,7 @@ LASEM_SVG_SRCS =                            \
        lsmsvgfiltercolormatrix.c               \
        lsmsvgfiltercomposite.c                 \
        lsmsvgfilterconvolvematrix.c            \
+       lsmsvgfilterdisplacementmap.c           \
        lsmsvgfilterflood.c                     \
        lsmsvgfiltergaussianblur.c              \
        lsmsvgfilterimage.c                     \
@@ -259,6 +260,7 @@ LASEM_SVG_HDRS =                            \
        lsmsvgfilterblend.h                     \
        lsmsvgfiltercolormatrix.h               \
        lsmsvgfiltercomposite.h                 \
+       lsmsvgfilterdisplacementmap.h           \
        lsmsvgfilterconvolvematrix.h            \
        lsmsvgfilterflood.h                     \
        lsmsvgfiltergaussianblur.h              \
diff --git a/src/lsmsvgattributes.h b/src/lsmsvgattributes.h
index 2f90678..1f9ee59 100644
--- a/src/lsmsvgattributes.h
+++ b/src/lsmsvgattributes.h
@@ -158,6 +158,11 @@ typedef struct {
        LsmSvgTurbulenceType value;
 } LsmSvgTurbulenceTypeAttribute;
 
+typedef struct {
+       LsmAttribute base;
+       LsmSvgChannelSelector value;
+} LsmSvgChannelSelectorAttribute;
+
 G_END_DECLS
 
 #endif
diff --git a/src/lsmsvgdocument.c b/src/lsmsvgdocument.c
index f341360..2c56808 100644
--- a/src/lsmsvgdocument.c
+++ b/src/lsmsvgdocument.c
@@ -33,6 +33,7 @@
 #include <lsmsvgfiltercolormatrix.h>
 #include <lsmsvgfiltercomposite.h>
 #include <lsmsvgfilterconvolvematrix.h>
+#include <lsmsvgfilterdisplacementmap.h>
 #include <lsmsvgfilterflood.h>
 #include <lsmsvgfiltergaussianblur.h>
 #include <lsmsvgfilterimage.h>
@@ -163,6 +164,8 @@ _create_element (LsmDomDocument *document, const char *tag_name)
                node = lsm_svg_filter_color_matrix_new ();
        else if (strcmp (tag_name, "feConvolveMatrix") == 0)
                node = lsm_svg_filter_convolve_matrix_new ();
+       else if (strcmp (tag_name, "feDisplacementMap") == 0)
+               node = lsm_svg_filter_displacement_map_new ();
        else if (strcmp (tag_name, "feFlood") == 0)
                node = lsm_svg_filter_flood_new ();
        else if (strcmp (tag_name, "feGaussianBlur") == 0)
diff --git a/src/lsmsvgenums.c b/src/lsmsvgenums.c
index 502687f..168b4ad 100644
--- a/src/lsmsvgenums.c
+++ b/src/lsmsvgenums.c
@@ -649,3 +649,26 @@ lsm_svg_turbulence_type_from_string (const char *string)
        return lsm_enum_value_from_string (string, lsm_svg_turbulence_type_strings,
                                           G_N_ELEMENTS (lsm_svg_turbulence_type_strings));
 }
+
+static const char *lsm_svg_channel_selector_strings[] = {
+       "R",
+       "G",
+       "B",
+       "A"
+};
+
+const char *
+lsm_svg_channel_selector_to_string (LsmSvgChannelSelector channel_selector)
+{
+       if (channel_selector < 0 || channel_selector > LSM_SVG_CHANNEL_SELECTOR_ALPHA)
+               return NULL;
+
+       return lsm_svg_channel_selector_strings[channel_selector];
+}
+
+LsmSvgChannelSelector
+lsm_svg_channel_selector_from_string (const char *string)
+{
+       return lsm_enum_value_from_string (string, lsm_svg_channel_selector_strings,
+                                          G_N_ELEMENTS (lsm_svg_channel_selector_strings));
+}
diff --git a/src/lsmsvgenums.h b/src/lsmsvgenums.h
index f96a7c9..3ec506f 100644
--- a/src/lsmsvgenums.h
+++ b/src/lsmsvgenums.h
@@ -400,6 +400,17 @@ typedef enum {
 const char *           lsm_svg_turbulence_type_to_string       (LsmSvgTurbulenceType turbulence_type);
 LsmSvgTurbulenceType   lsm_svg_turbulence_type_from_string     (const char *string);
 
+typedef enum {
+       LSM_SVG_CHANNEL_SELECTOR_ERROR = -1,
+       LSM_SVG_CHANNEL_SELECTOR_RED,
+       LSM_SVG_CHANNEL_SELECTOR_GREEN,
+       LSM_SVG_CHANNEL_SELECTOR_BLUE,
+       LSM_SVG_CHANNEL_SELECTOR_ALPHA
+} LsmSvgChannelSelector;
+
+const char *           lsm_svg_channel_selector_to_string      (LsmSvgChannelSelector channel_selector);
+LsmSvgChannelSelector  lsm_svg_channel_selector_from_string    (const char *string);
+
 G_END_DECLS
 
 #endif
diff --git a/src/lsmsvgfilterdisplacementmap.c b/src/lsmsvgfilterdisplacementmap.c
new file mode 100644
index 0000000..4d37234
--- /dev/null
+++ b/src/lsmsvgfilterdisplacementmap.c
@@ -0,0 +1,124 @@
+/* Lasem
+ * 
+ * Copyright © 2015 Emmanuel Pacaud
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author:
+ *     Emmanuel Pacaud <emmanuel gnome org>
+ */
+
+#include <lsmsvgfilterdisplacementmap.h>
+#include <lsmsvgview.h>
+
+static GObjectClass *parent_class;
+
+/* GdomNode implementation */
+
+static const char *
+lsm_svg_filter_displacement_map_get_node_name (LsmDomNode *node)
+{
+       return "feDisplacementMap";
+}
+
+/* LsmSvgElement implementation */
+
+static void
+lsm_svg_filter_displacement_map_apply  (LsmSvgFilterPrimitive *self, LsmSvgView *view,
+                            const char *input, const char *output, const LsmBox *subregion)
+{
+       LsmSvgFilterDisplacementMap *displacement_map = LSM_SVG_FILTER_DISPLACEMENT_MAP (self);
+
+       lsm_svg_view_apply_displacement_map (view, input, displacement_map->in2.value, output, subregion,
+                                            displacement_map->scale.value,
+                                            displacement_map->x_channel_selector.value,
+                                            displacement_map->y_channel_selector.value);
+}
+
+/* LsmSvgFilterDisplacementMap implementation */
+
+LsmDomNode *
+lsm_svg_filter_displacement_map_new (void)
+{
+       return g_object_new (LSM_TYPE_SVG_FILTER_DISPLACEMENT_MAP, NULL);
+}
+
+static double scale_default = 0.0; 
+static LsmSvgChannelSelector channel_selector_default = LSM_SVG_CHANNEL_SELECTOR_ALPHA;
+
+static void
+lsm_svg_filter_displacement_map_init (LsmSvgFilterDisplacementMap *self)
+{
+}
+
+static void
+lsm_svg_filter_displacement_map_finalize (GObject *object)
+{
+       parent_class->finalize (object);
+}
+
+/* LsmSvgFilterDisplacementMap class */
+
+static const LsmAttributeInfos lsm_svg_filter_displacement_map_attribute_infos[] = {
+       {
+               .name = "in2",
+               .attribute_offset = offsetof (LsmSvgFilterDisplacementMap, in2),
+               .trait_class = &lsm_null_trait_class
+       },
+       {
+               .name = "scale",
+               .attribute_offset = offsetof (LsmSvgFilterDisplacementMap, scale),
+               .trait_class = &lsm_double_trait_class,
+               .trait_default = &scale_default
+       },
+       {
+               .name = "xChannelSelector",
+               .attribute_offset = offsetof (LsmSvgFilterDisplacementMap, x_channel_selector),
+               .trait_class = &lsm_svg_channel_selector_trait_class,
+               .trait_default = &channel_selector_default
+       },
+       {
+               .name = "yChannelSelector",
+               .attribute_offset = offsetof (LsmSvgFilterDisplacementMap, y_channel_selector),
+               .trait_class = &lsm_svg_channel_selector_trait_class,
+               .trait_default = &channel_selector_default
+       }
+};
+
+static void
+lsm_svg_filter_displacement_map_class_init (LsmSvgFilterDisplacementMapClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+       LsmDomNodeClass *d_node_class = LSM_DOM_NODE_CLASS (klass);
+       LsmSvgElementClass *s_element_class = LSM_SVG_ELEMENT_CLASS (klass);
+       LsmSvgFilterPrimitiveClass *f_primitive_class = LSM_SVG_FILTER_PRIMITIVE_CLASS (klass);
+
+       parent_class = g_type_class_peek_parent (klass);
+
+       object_class->finalize = lsm_svg_filter_displacement_map_finalize;
+
+       d_node_class->get_node_name = lsm_svg_filter_displacement_map_get_node_name;
+
+       s_element_class->attribute_manager = lsm_attribute_manager_duplicate 
(s_element_class->attribute_manager);
+
+       lsm_attribute_manager_add_attributes (s_element_class->attribute_manager,
+                                             G_N_ELEMENTS (lsm_svg_filter_displacement_map_attribute_infos),
+                                             lsm_svg_filter_displacement_map_attribute_infos);
+
+       f_primitive_class->apply = lsm_svg_filter_displacement_map_apply;
+}
+
+G_DEFINE_TYPE (LsmSvgFilterDisplacementMap, lsm_svg_filter_displacement_map, LSM_TYPE_SVG_FILTER_PRIMITIVE)
diff --git a/src/lsmsvgfilterdisplacementmap.h b/src/lsmsvgfilterdisplacementmap.h
new file mode 100644
index 0000000..6be7c84
--- /dev/null
+++ b/src/lsmsvgfilterdisplacementmap.h
@@ -0,0 +1,60 @@
+/* Lasem
+ *
+ * Copyright © 2015 Emmanuel Pacaud
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author:
+ *     Emmanuel Pacaud <emmanuel gnome org>
+ */
+
+#ifndef LSM_SVG_FILTER_DISPLACEMENT_MAP_H
+#define LSM_SVG_FILTER_DISPLACEMENT_MAP_H
+
+#include <lsmsvgtypes.h>
+#include <lsmsvgfilterprimitive.h>
+
+G_BEGIN_DECLS
+
+#define LSM_TYPE_SVG_FILTER_DISPLACEMENT_MAP             (lsm_svg_filter_displacement_map_get_type ())
+#define LSM_SVG_FILTER_DISPLACEMENT_MAP(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
LSM_TYPE_SVG_FILTER_DISPLACEMENT_MAP, LsmSvgFilterDisplacementMap))
+#define LSM_SVG_FILTER_DISPLACEMENT_MAP_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), 
LSM_TYPE_SVG_FILTER_DISPLACEMENT_MAP, LsmSvgFilterDisplacementMapClass))
+#define LSM_IS_SVG_FILTER_DISPLACEMENT_MAP(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), 
LSM_TYPE_SVG_FILTER_DISPLACEMENT_MAP))
+#define LSM_IS_SVG_FILTER_DISPLACEMENT_MAP_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), 
LSM_TYPE_SVG_FILTER_DISPLACEMENT_MAP))
+#define LSM_SVG_FILTER_DISPLACEMENT_MAP_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS((obj), 
LSM_TYPE_SVG_FILTER_DISPLACEMENT_MAP, LsmSvgFilterDisplacementMapClass))
+
+typedef struct _LsmSvgFilterDisplacementMapClass LsmSvgFilterDisplacementMapClass;
+
+struct _LsmSvgFilterDisplacementMap {
+       LsmSvgFilterPrimitive base;
+
+       LsmAttribute in2;
+       LsmSvgDoubleAttribute scale;
+       LsmSvgChannelSelectorAttribute x_channel_selector;
+       LsmSvgChannelSelectorAttribute y_channel_selector;
+};
+
+struct _LsmSvgFilterDisplacementMapClass {
+       LsmSvgFilterPrimitiveClass  element_class;
+};
+
+GType lsm_svg_filter_displacement_map_get_type (void);
+
+LsmDomNode *   lsm_svg_filter_displacement_map_new             (void);
+
+G_END_DECLS
+
+#endif
diff --git a/src/lsmsvgfiltersurface.c b/src/lsmsvgfiltersurface.c
index 78fd4fe..1ada833 100644
--- a/src/lsmsvgfiltersurface.c
+++ b/src/lsmsvgfiltersurface.c
@@ -906,6 +906,169 @@ lsm_svg_filter_surface_convolve_matrix (LsmSvgFilterSurface *input, LsmSvgFilter
        cairo_destroy (cairo);
 }
 
+static guchar
+_get_interp_pixel (guchar * src, gdouble ox, gdouble oy, guchar ch,
+                  gint x1, gint x2, gint y1, gint y2,
+                  guint rowstride)
+{
+       double xmod, ymod;
+       double dist1, dist2, dist3, dist4;
+       double c, c1, c2, c3, c4;
+       double fox, foy, cox, coy;
+
+       xmod = fmod (ox, 1.0);
+       ymod = fmod (oy, 1.0);
+
+       dist1 = (1 - xmod) * (1 - ymod);
+       dist2 = (xmod) * (1 - ymod);
+       dist3 = (xmod) * (ymod);
+       dist4 = (1 - xmod) * (ymod);
+
+       fox = floor (ox);
+       foy = floor (oy);
+       cox = ceil (ox);
+       coy = ceil (oy);
+
+       if (fox <= x1 || fox >= x2 ||
+           foy <= y1 || foy >= y2)
+               c1 = 0;
+       else
+               c1 = src[(guint) foy * rowstride + (guint) fox * 4 + ch];
+
+       if (cox <= x1 || cox >= x2 ||
+           foy <= y1 || foy >= y2)
+               c2 = 0;
+       else
+               c2 = src[(guint) foy * rowstride + (guint) cox * 4 + ch];
+
+       if (cox <= x1 || cox >= x2 ||
+           coy <= y1 || coy >= y2)
+               c3 = 0;
+       else
+               c3 = src[(guint) coy * rowstride + (guint) cox * 4 + ch];
+
+       if (fox <= x1 || fox >= x2 ||
+           coy <= y1 || coy >= y2)
+               c4 = 0;
+       else
+               c4 = src[(guint) coy * rowstride + (guint) fox * 4 + ch];
+
+       c = (c1 * dist1 + c2 * dist2 + c3 * dist3 + c4 * dist4) / (dist1 + dist2 + dist3 + dist4);
+
+       return (guchar) c;
+}
+
+void
+lsm_svg_filter_surface_displacement_map (LsmSvgFilterSurface *input_1,
+                                        LsmSvgFilterSurface *input_2,
+                                        LsmSvgFilterSurface *output,
+                                        double x_scale,
+                                        double y_scale,
+                                        LsmSvgChannelSelector x_channel_selector,
+                                        LsmSvgChannelSelector y_channel_selector)
+{
+       guchar ch, xch, ych;
+       gint x, y, x1, x2, y1, y2;
+       double ox, oy;
+       gint rowstride, height, width;
+       guchar *in_pixels;
+       guchar *in2_pixels;
+       guchar *output_pixels;
+       cairo_t *cairo;
+
+       g_return_if_fail (input_1 != NULL);
+       g_return_if_fail (input_2 != NULL);
+       g_return_if_fail (output != NULL);
+
+       height = cairo_image_surface_get_height (input_1->surface);
+       width = cairo_image_surface_get_width (input_1->surface);
+
+       if (width != cairo_image_surface_get_width (input_2->surface) ||
+           height != cairo_image_surface_get_height (input_2->surface))
+               return;
+
+       if (width != cairo_image_surface_get_width (output->surface) ||
+           height != cairo_image_surface_get_height (output->surface))
+               return;
+
+       cairo_surface_flush (input_1->surface);
+       cairo_surface_flush (input_2->surface);
+
+       cairo = cairo_create (output->surface);
+
+       in_pixels = cairo_image_surface_get_data (input_1->surface);
+       in2_pixels = cairo_image_surface_get_data (input_2->surface);
+
+       rowstride = cairo_image_surface_get_stride (input_1->surface);
+
+       output_pixels = cairo_image_surface_get_data (output->surface);
+
+       switch (x_channel_selector) {
+               case LSM_SVG_CHANNEL_SELECTOR_RED:
+                       xch = 0;
+                       break;
+               case LSM_SVG_CHANNEL_SELECTOR_GREEN:
+                       xch = 1;
+                       break;
+               case LSM_SVG_CHANNEL_SELECTOR_BLUE:
+                       xch = 2;
+                       break;
+               case LSM_SVG_CHANNEL_SELECTOR_ALPHA:
+                       xch = 3;
+                       break;
+               default:
+                       xch = 4;
+       };
+
+       switch (y_channel_selector) {
+               case LSM_SVG_CHANNEL_SELECTOR_RED:
+                       ych = 0;
+                       break;
+               case LSM_SVG_CHANNEL_SELECTOR_GREEN:
+                       ych = 1;
+                       break;
+               case LSM_SVG_CHANNEL_SELECTOR_BLUE:
+                       ych = 2;
+                       break;
+               case LSM_SVG_CHANNEL_SELECTOR_ALPHA:
+                       ych = 3;
+                       break;
+               default:
+                       ych = 4;
+       };
+
+       x1 = CLAMP (input_1->subregion.x, 0, width);
+       x2 = CLAMP (input_1->subregion.x + input_1->subregion.width, 0, width);
+       y1 = CLAMP (input_1->subregion.y, 0, height);
+       y2 = CLAMP (input_1->subregion.y + input_1->subregion.height, 0, height);
+
+       xch = channelmap[xch];
+       ych = channelmap[ych];
+       for (y = y1; y < y2; y++)
+               for (x = x1; x < x2; x++) {
+                       if (xch != 4)
+                               ox = x + x_scale *
+                                       ((double) in2_pixels[y * rowstride + x * 4 + xch] / 255.0 - 0.5);
+                       else
+                               ox = x;
+
+                       if (ych != 4)
+                               oy = y + y_scale *
+                                       ((double) in2_pixels[y * rowstride + x * 4 + ych] / 255.0 - 0.5);
+                       else
+                               oy = y;
+
+                       for (ch = 0; ch < 4; ch++) {
+                               output_pixels[y * rowstride + x * 4 + ch] =
+                                       _get_interp_pixel (in_pixels, ox, oy, ch, x1, x2, y1, y2, rowstride);
+                       }
+               }
+
+       cairo_surface_mark_dirty (output->surface);
+
+       cairo_destroy (cairo);
+}
+
 void
 lsm_svg_filter_surface_specular_lighting (LsmSvgFilterSurface *output,
                                          double surface_scale, double specular_constant, double 
specular_exponent,
diff --git a/src/lsmsvgfiltersurface.h b/src/lsmsvgfiltersurface.h
index 7bdc05c..ad0aeff 100644
--- a/src/lsmsvgfiltersurface.h
+++ b/src/lsmsvgfiltersurface.h
@@ -68,6 +68,12 @@ void                         lsm_svg_filter_surface_convolve_matrix  (LsmSvgFilterSurface 
*input, Lsm
                                                                 unsigned n_values, const double *values,
                                                                 double divisor, double bias, unsigned 
target_x, unsigned target_y,
                                                                 LsmSvgEdgeMode edge_mode, gboolean 
preserve_alpha);
+void                   lsm_svg_filter_surface_displacement_map (LsmSvgFilterSurface *input_1,
+                                                                LsmSvgFilterSurface *input_2,
+                                                                LsmSvgFilterSurface *output,
+                                                                double x_scale, double y_scale,
+                                                                LsmSvgChannelSelector x_channel_selector,
+                                                                LsmSvgChannelSelector y_channel_selector);
 void                   lsm_svg_filter_surface_image            (LsmSvgFilterSurface *output, GdkPixbuf 
*pixbuf,
                                                                 LsmSvgPreserveAspectRatio 
preserve_aspect_ratio);
 void                   lsm_svg_filter_surface_morphology       (LsmSvgFilterSurface *input_surface, 
LsmSvgFilterSurface *output_surface,
diff --git a/src/lsmsvgtraits.c b/src/lsmsvgtraits.c
index 25df16a..fe89682 100644
--- a/src/lsmsvgtraits.c
+++ b/src/lsmsvgtraits.c
@@ -1455,3 +1455,27 @@ const LsmTraitClass lsm_svg_turbulence_type_trait_class = {
        .from_string = lsm_svg_turbulence_type_trait_from_string,
        .to_string = lsm_svg_turbulence_type_trait_to_string
 };
+
+static gboolean
+lsm_svg_channel_selector_trait_from_string (LsmTrait *abstract_trait, char *string)
+{
+       LsmSvgChannelSelector *trait = (LsmSvgChannelSelector *) abstract_trait;
+
+       *trait = lsm_svg_channel_selector_from_string (string);
+
+       return *trait >= 0;
+}
+
+static char *
+lsm_svg_channel_selector_trait_to_string (LsmTrait *abstract_trait)
+{
+       LsmSvgChannelSelector *trait = (LsmSvgChannelSelector *) abstract_trait;
+
+       return g_strdup (lsm_svg_channel_selector_to_string (*trait));
+}
+
+const LsmTraitClass lsm_svg_channel_selector_trait_class = {
+       .size = sizeof (LsmSvgChannelSelector),
+       .from_string = lsm_svg_channel_selector_trait_from_string,
+       .to_string = lsm_svg_channel_selector_trait_to_string
+};
diff --git a/src/lsmsvgtraits.h b/src/lsmsvgtraits.h
index 22dd9ce..b1136b1 100644
--- a/src/lsmsvgtraits.h
+++ b/src/lsmsvgtraits.h
@@ -85,6 +85,7 @@ typedef struct {
 extern const LsmTraitClass lsm_svg_angle_trait_class;
 extern const LsmTraitClass lsm_svg_blending_mode_trait_class;
 extern const LsmTraitClass lsm_svg_enable_background_trait_class;
+extern const LsmTraitClass lsm_svg_channel_selector_trait_class;
 extern const LsmTraitClass lsm_svg_color_trait_class;
 extern const LsmTraitClass lsm_svg_color_filter_type_trait_class;
 extern const LsmTraitClass lsm_svg_comp_op_trait_class;
diff --git a/src/lsmsvgtypes.h b/src/lsmsvgtypes.h
index cf14d62..3dc1956 100644
--- a/src/lsmsvgtypes.h
+++ b/src/lsmsvgtypes.h
@@ -50,6 +50,7 @@ typedef struct _LsmSvgFilterBlend LsmSvgFilterBlend;
 typedef struct _LsmSvgFilterColorMatrix LsmSvgFilterColorMatrix;
 typedef struct _LsmSvgFilterComposite LsmSvgFilterComposite;
 typedef struct _LsmSvgFilterConvolveMatrix LsmSvgFilterConvolveMatrix;
+typedef struct _LsmSvgFilterDisplacementMap LsmSvgFilterDisplacementMap;
 typedef struct _LsmSvgFilterFlood LsmSvgFilterFlood;
 typedef struct _LsmSvgFilterGaussianBlur LsmSvgFilterGaussianBlur;
 typedef struct _LsmSvgFilterImage LsmSvgFilterImage;
diff --git a/src/lsmsvgview.c b/src/lsmsvgview.c
index 34dc4dc..607a84d 100644
--- a/src/lsmsvgview.c
+++ b/src/lsmsvgview.c
@@ -2222,6 +2222,40 @@ lsm_svg_view_apply_color_matrix (LsmSvgView *view, const char *input, const char
        lsm_svg_filter_surface_color_matrix (input_surface, output_surface, type, n_values, values);
 }
 
+void
+lsm_svg_view_apply_displacement_map (LsmSvgView *view, const char *input_1, const char *input_2, const char 
*output,
+                                    const LsmBox *subregion,
+                                    double scale, LsmSvgChannelSelector x_channel_selector, 
LsmSvgChannelSelector y_channel_selector)
+{
+       LsmSvgFilterSurface *output_surface;
+       LsmSvgFilterSurface *input_1_surface;
+       LsmSvgFilterSurface *input_2_surface;
+       LsmBox subregion_px;
+       cairo_matrix_t transform;
+       double x_scale, y_scale;
+
+       g_return_if_fail (LSM_IS_SVG_VIEW (view));
+
+       input_1_surface = _get_filter_surface (view, input_1);
+       input_2_surface = _get_filter_surface (view, input_2);
+
+       if (input_1_surface == NULL || input_2_surface == NULL) {
+               lsm_warning_render ("[SvgView::apply_displacement_map] Inputs '%s' or '%s' not found", 
input_1, input_2);
+               return;
+       }
+
+       lsm_cairo_box_user_to_device (view->dom_view.cairo, &subregion_px, subregion);
+       output_surface = _create_filter_surface (view, output, input_1_surface, &subregion_px);
+
+       cairo_get_matrix (view->dom_view.cairo, &transform);
+
+       x_scale = transform.xx * scale;
+       y_scale = transform.yy * scale;
+
+       lsm_svg_filter_surface_displacement_map (input_1_surface, input_2_surface, output_surface, x_scale, 
y_scale,
+                                                x_channel_selector, y_channel_selector);
+}
+
 void 
 lsm_svg_view_apply_morphology (LsmSvgView *view, const char *input, const char *output, const LsmBox 
*subregion,
                               LsmSvgMorphologyOperator op, double radius)
diff --git a/src/lsmsvgview.h b/src/lsmsvgview.h
index a505f5f..92ed6c6 100644
--- a/src/lsmsvgview.h
+++ b/src/lsmsvgview.h
@@ -175,6 +175,10 @@ void               lsm_svg_view_apply_offset               (LsmSvgView *view, const char 
*input, const c
 void           lsm_svg_view_apply_color_matrix         (LsmSvgView *view, const char *input, const char 
*output,
                                                         const LsmBox *subregion, LsmSvgColorFilterType type,
                                                         unsigned int n_values, const double *values);
+void           lsm_svg_view_apply_displacement_map     (LsmSvgView *view, const char *input_1, const char 
*input_2, const char *output,
+                                                        const LsmBox *subregion, double scale,
+                                                        LsmSvgChannelSelector x_channel_selector,
+                                                        LsmSvgChannelSelector y_channel_selector);
 void           lsm_svg_view_apply_merge                (LsmSvgView *view, const char *input, const char 
*output, const LsmBox *subregion);
 void           lsm_svg_view_apply_tile                 (LsmSvgView *view, const char *input, const char 
*output, const LsmBox *subregion);
 void           lsm_svg_view_apply_image                (LsmSvgView *view, const char *output, const LsmBox 
*subregion,
diff --git a/tests/data/svg/svg1.1/images/DisplaceChecker.png 
b/tests/data/svg/svg1.1/images/DisplaceChecker.png
new file mode 100644
index 0000000..25c77d0
Binary files /dev/null and b/tests/data/svg/svg1.1/images/DisplaceChecker.png differ
diff --git a/tests/data/svg/svg1.1/images/rotate20.png b/tests/data/svg/svg1.1/images/rotate20.png
new file mode 100644
index 0000000..e566bfa
Binary files /dev/null and b/tests/data/svg/svg1.1/images/rotate20.png differ
diff --git a/tests/data/svg/svg1.1/images/sphere.png b/tests/data/svg/svg1.1/images/sphere.png
new file mode 100644
index 0000000..9e22388
Binary files /dev/null and b/tests/data/svg/svg1.1/images/sphere.png differ
diff --git a/tests/filter.c b/tests/filter.c
index ee25073..29bb4c6 100644
--- a/tests/filter.c
+++ b/tests/filter.c
@@ -57,16 +57,22 @@ operations (LsmSvgFilterSurface *input_1, LsmSvgFilterSurface *input_2, LsmSvgFi
        lsm_svg_filter_surface_blur (input_1, output, 1.0, 1.0);
        lsm_svg_filter_surface_blur (input_1, output, 10.0, 10.0);
        lsm_svg_filter_surface_blur (input_1, output, 1000.0, 1000.0);
+       lsm_svg_filter_surface_color_matrix (input_1, output, LSM_SVG_COLOR_FILTER_TYPE_HUE_ROTATE, 0, NULL);
+       lsm_svg_filter_surface_convolve_matrix (input_1, output, 0, 0, 0, NULL, 1.0, 0.0, 0, 0, 
LSM_SVG_EDGE_MODE_NONE, TRUE);
+       lsm_svg_filter_surface_displacement_map (input_1, input_2, output, 2.0, 2.0,
+                                                LSM_SVG_CHANNEL_SELECTOR_RED, 
LSM_SVG_CHANNEL_SELECTOR_GREEN);
+       lsm_svg_filter_surface_displacement_map (input_1, input_2, output, 2.0, 3.0,
+                                                LSM_SVG_CHANNEL_SELECTOR_BLUE, 
LSM_SVG_CHANNEL_SELECTOR_ALPHA);
+       lsm_svg_filter_surface_displacement_map (input_1, input_2, output, 0.0, 0.0,
+                                                LSM_SVG_CHANNEL_SELECTOR_ALPHA, 
LSM_SVG_CHANNEL_SELECTOR_ALPHA);
        lsm_svg_filter_surface_flood (output, 1.0, 0.0, 0.5, 0.25);
+       lsm_svg_filter_surface_merge (input_1, output);
+       lsm_svg_filter_surface_morphology (input_1, output, LSM_SVG_MORPHOLOGY_OPERATOR_ERODE, 1, 1);
+       lsm_svg_filter_surface_morphology (input_1, output, LSM_SVG_MORPHOLOGY_OPERATOR_DILATE, 1, 1);
        lsm_svg_filter_surface_offset (input_1, output, 10, 10);
        lsm_svg_filter_surface_offset (input_1, output, -10, -10);
        lsm_svg_filter_surface_offset (input_1, output, -1000, -1000);
-       lsm_svg_filter_surface_merge (input_1, output);
        lsm_svg_filter_surface_tile (input_1, output);
-       lsm_svg_filter_surface_color_matrix (input_1, output, LSM_SVG_COLOR_FILTER_TYPE_HUE_ROTATE, 0, NULL);
-       lsm_svg_filter_surface_convolve_matrix (input_1, output, 0, 0, 0, NULL, 1.0, 0.0, 0, 0, 
LSM_SVG_EDGE_MODE_NONE, TRUE);
-       lsm_svg_filter_surface_morphology (input_1, output, LSM_SVG_MORPHOLOGY_OPERATOR_ERODE, 1, 1);
-       lsm_svg_filter_surface_morphology (input_1, output, LSM_SVG_MORPHOLOGY_OPERATOR_DILATE, 1, 1);
        lsm_svg_filter_surface_turbulence (output, 10.0, 10.0, 2, 1.0, LSM_SVG_STITCH_TILES_STITCH, 
LSM_SVG_TURBULENCE_TYPE_FRACTAL_NOISE,
                                           &transform);
 }
@@ -112,12 +118,12 @@ processing_null (void)
 {
        unsigned int i;
 
-       for (i = 0; i < 17; i++)
+       for (i = 0; i < 20; i++)
                g_test_expect_message ("Lasem", G_LOG_LEVEL_CRITICAL, "*assertion*NULL*failed");
 
        operations (NULL, NULL, NULL);
 
-       for (i = 0; i < 17; i++)
+       for (i = 0; i < 20; i++)
                g_test_assert_expected_messages ();
 }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]