summaryrefslogtreecommitdiffstats
path: root/src/object/filters
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/object/filters/CMakeLists.txt54
-rw-r--r--src/object/filters/blend.cpp290
-rw-r--r--src/object/filters/blend.h55
-rw-r--r--src/object/filters/colormatrix.cpp159
-rw-r--r--src/object/filters/colormatrix.h55
-rw-r--r--src/object/filters/componenttransfer-funcnode.cpp213
-rw-r--r--src/object/filters/componenttransfer-funcnode.h64
-rw-r--r--src/object/filters/componenttransfer.cpp189
-rw-r--r--src/object/filters/componenttransfer.h59
-rw-r--r--src/object/filters/composite.cpp333
-rw-r--r--src/object/filters/composite.h77
-rw-r--r--src/object/filters/convolvematrix.cpp318
-rw-r--r--src/object/filters/convolvematrix.h67
-rw-r--r--src/object/filters/diffuselighting.cpp326
-rw-r--r--src/object/filters/diffuselighting.h73
-rw-r--r--src/object/filters/displacementmap.cpp256
-rw-r--r--src/object/filters/displacementmap.h63
-rw-r--r--src/object/filters/distantlight.cpp164
-rw-r--r--src/object/filters/distantlight.h59
-rw-r--r--src/object/filters/flood.cpp180
-rw-r--r--src/object/filters/flood.h55
-rw-r--r--src/object/filters/gaussian-blur.cpp132
-rw-r--r--src/object/filters/gaussian-blur.h57
-rw-r--r--src/object/filters/image.cpp261
-rw-r--r--src/object/filters/image.h69
-rw-r--r--src/object/filters/merge.cpp115
-rw-r--r--src/object/filters/merge.h48
-rw-r--r--src/object/filters/mergenode.cpp106
-rw-r--r--src/object/filters/mergenode.h53
-rw-r--r--src/object/filters/morphology.cpp161
-rw-r--r--src/object/filters/morphology.h55
-rw-r--r--src/object/filters/offset.cpp137
-rw-r--r--src/object/filters/offset.h52
-rw-r--r--src/object/filters/pointlight.cpp190
-rw-r--r--src/object/filters/pointlight.h61
-rw-r--r--src/object/filters/sp-filter-primitive.cpp273
-rw-r--r--src/object/filters/sp-filter-primitive.h68
-rw-r--r--src/object/filters/specularlighting.cpp340
-rw-r--r--src/object/filters/specularlighting.h79
-rw-r--r--src/object/filters/spotlight.cpp320
-rw-r--r--src/object/filters/spotlight.h77
-rw-r--r--src/object/filters/tile.cpp108
-rw-r--r--src/object/filters/tile.h51
-rw-r--r--src/object/filters/turbulence.cpp229
-rw-r--r--src/object/filters/turbulence.h64
45 files changed, 6215 insertions, 0 deletions
diff --git a/src/object/filters/CMakeLists.txt b/src/object/filters/CMakeLists.txt
new file mode 100644
index 0000000..14ea76b
--- /dev/null
+++ b/src/object/filters/CMakeLists.txt
@@ -0,0 +1,54 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+set(filters_SRC
+ sp-filter-primitive.cpp
+ blend.cpp
+ colormatrix.cpp
+ componenttransfer-funcnode.cpp
+ componenttransfer.cpp
+ composite.cpp
+ convolvematrix.cpp
+ diffuselighting.cpp
+ displacementmap.cpp
+ distantlight.cpp
+ flood.cpp
+ gaussian-blur.cpp
+ image.cpp
+ merge.cpp
+ mergenode.cpp
+ morphology.cpp
+ offset.cpp
+ pointlight.cpp
+ specularlighting.cpp
+ spotlight.cpp
+ tile.cpp
+ turbulence.cpp
+
+
+ # -------
+ # Headers
+ sp-filter-primitive.h
+ blend.h
+ colormatrix.h
+ componenttransfer-funcnode.h
+ componenttransfer.h
+ composite.h
+ convolvematrix.h
+ diffuselighting.h
+ displacementmap.h
+ distantlight.h
+ flood.h
+ gaussian-blur.h
+ image.h
+ merge.h
+ mergenode.h
+ morphology.h
+ offset.h
+ pointlight.h
+ specularlighting.h
+ spotlight.h
+ tile.h
+ turbulence.h
+)
+
+add_inkscape_source("${filters_SRC}")
diff --git a/src/object/filters/blend.cpp b/src/object/filters/blend.cpp
new file mode 100644
index 0000000..2d0c053
--- /dev/null
+++ b/src/object/filters/blend.cpp
@@ -0,0 +1,290 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** \file
+ * SVG <feBlend> implementation.
+ *
+ */
+/*
+ * Authors:
+ * Hugo Rodrigues <haa.rodrigues@gmail.com>
+ * Niko Kiirala <niko@kiirala.com>
+ * Abhishek Sharma
+ *
+ * Copyright (C) 2006,2007 authors
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include <cstring>
+
+#include "blend.h"
+
+#include "attributes.h"
+
+#include "display/nr-filter.h"
+
+#include "object/sp-filter.h"
+
+#include "xml/repr.h"
+
+
+SPFeBlend::SPFeBlend()
+ : SPFilterPrimitive(), blend_mode(SP_CSS_BLEND_NORMAL),
+ in2(Inkscape::Filters::NR_FILTER_SLOT_NOT_SET)
+{
+}
+
+SPFeBlend::~SPFeBlend() = default;
+
+/**
+ * Reads the Inkscape::XML::Node, and initializes SPFeBlend variables. For this to get called,
+ * our name must be associated with a repr via "sp_object_type_register". Best done through
+ * sp-object-repr.cpp's repr_name_entries array.
+ */
+void SPFeBlend::build(SPDocument *document, Inkscape::XML::Node *repr) {
+ SPFilterPrimitive::build(document, repr);
+
+ /*LOAD ATTRIBUTES FROM REPR HERE*/
+ this->readAttr( "mode" );
+ this->readAttr( "in2" );
+
+ /* Unlike normal in, in2 is required attribute. Make sure, we can call
+ * it by some name. */
+ if (this->in2 == Inkscape::Filters::NR_FILTER_SLOT_NOT_SET ||
+ this->in2 == Inkscape::Filters::NR_FILTER_UNNAMED_SLOT)
+ {
+ SPFilter *parent = SP_FILTER(this->parent);
+ this->in2 = this->name_previous_out();
+ repr->setAttribute("in2", parent->name_for_image(this->in2));
+ }
+}
+
+/**
+ * Drops any allocated memory.
+ */
+void SPFeBlend::release() {
+ SPFilterPrimitive::release();
+}
+
+static SPBlendMode sp_feBlend_readmode(gchar const *value) {
+ if (!value) {
+ return SP_CSS_BLEND_NORMAL;
+ }
+
+ switch (value[0]) {
+ case 'n':
+ if (strncmp(value, "normal", 6) == 0)
+ return SP_CSS_BLEND_NORMAL;
+ break;
+ case 'm':
+ if (strncmp(value, "multiply", 8) == 0)
+ return SP_CSS_BLEND_MULTIPLY;
+ break;
+ case 's':
+ if (strncmp(value, "screen", 6) == 0)
+ return SP_CSS_BLEND_SCREEN;
+ if (strncmp(value, "saturation", 10) == 0)
+ return SP_CSS_BLEND_SATURATION;
+ break;
+ case 'd':
+ if (strncmp(value, "darken", 6) == 0)
+ return SP_CSS_BLEND_DARKEN;
+ if (strncmp(value, "difference", 10) == 0)
+ return SP_CSS_BLEND_DIFFERENCE;
+ break;
+ case 'l':
+ if (strncmp(value, "lighten", 7) == 0)
+ return SP_CSS_BLEND_LIGHTEN;
+ if (strncmp(value, "luminosity", 10) == 0)
+ return SP_CSS_BLEND_LUMINOSITY;
+ break;
+ case 'o':
+ if (strncmp(value, "overlay", 7) == 0)
+ return SP_CSS_BLEND_OVERLAY;
+ break;
+ case 'c':
+ if (strncmp(value, "color-dodge", 11) == 0)
+ return SP_CSS_BLEND_COLORDODGE;
+ if (strncmp(value, "color-burn", 10) == 0)
+ return SP_CSS_BLEND_COLORBURN;
+ if (strncmp(value, "color", 5) == 0)
+ return SP_CSS_BLEND_COLOR;
+ break;
+ case 'h':
+ if (strncmp(value, "hard-light", 10) == 0)
+ return SP_CSS_BLEND_HARDLIGHT;
+ if (strncmp(value, "hue", 3) == 0)
+ return SP_CSS_BLEND_HUE;
+ break;
+ case 'e':
+ if (strncmp(value, "exclusion", 10) == 0)
+ return SP_CSS_BLEND_EXCLUSION;
+ default:
+ std::cout << "SPBlendMode: Unimplemented mode: " << value << std::endl;
+ // do nothing by default
+ break;
+ }
+
+ return SP_CSS_BLEND_NORMAL;
+}
+
+/**
+ * Sets a specific value in the SPFeBlend.
+ */
+void SPFeBlend::set(SPAttributeEnum key, gchar const *value) {
+ SPBlendMode mode;
+ int input;
+
+ switch(key) {
+ /*DEAL WITH SETTING ATTRIBUTES HERE*/
+ case SP_ATTR_MODE:
+ mode = sp_feBlend_readmode(value);
+
+ if (mode != this->blend_mode) {
+ this->blend_mode = mode;
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ case SP_ATTR_IN2:
+ input = this->read_in(value);
+
+ if (input != this->in2) {
+ this->in2 = input;
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ default:
+ SPFilterPrimitive::set(key, value);
+ break;
+ }
+}
+
+/**
+ * Receives update notifications.
+ */
+void SPFeBlend::update(SPCtx *ctx, guint flags) {
+ if (flags & SP_OBJECT_MODIFIED_FLAG) {
+ this->readAttr( "mode" );
+ this->readAttr( "in2" );
+ }
+
+ /* Unlike normal in, in2 is required attribute. Make sure, we can call
+ * it by some name. */
+ /* This may not be true.... see issue at
+ * http://www.w3.org/TR/filter-effects/#feBlendElement (but it doesn't hurt). */
+ if (this->in2 == Inkscape::Filters::NR_FILTER_SLOT_NOT_SET ||
+ this->in2 == Inkscape::Filters::NR_FILTER_UNNAMED_SLOT)
+ {
+ SPFilter *parent = SP_FILTER(this->parent);
+ this->in2 = this->name_previous_out();
+
+ // TODO: XML Tree being used directly here while it shouldn't be.
+ this->setAttribute("in2", parent->name_for_image(this->in2));
+ }
+
+ SPFilterPrimitive::update(ctx, flags);
+}
+
+/**
+ * Writes its settings to an incoming repr object, if any.
+ */
+Inkscape::XML::Node* SPFeBlend::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) {
+ SPFilter *parent = SP_FILTER(this->parent);
+
+ if (!repr) {
+ repr = doc->createElement("svg:feBlend");
+ }
+
+ gchar const *in2_name = parent->name_for_image(this->in2);
+
+ if( !in2_name ) {
+
+ // This code is very similar to name_previous_out()
+ SPObject *i = parent->firstChild();
+
+ // Find previous filter primitive
+ while (i && i->getNext() != this) {
+ i = i->getNext();
+ }
+
+ if( i ) {
+ SPFilterPrimitive *i_prim = SP_FILTER_PRIMITIVE(i);
+ in2_name = parent->name_for_image(i_prim->image_out);
+ }
+ }
+
+ if (in2_name) {
+ repr->setAttribute("in2", in2_name);
+ } else {
+ g_warning("Unable to set in2 for feBlend");
+ }
+
+ char const *mode;
+ switch(this->blend_mode) {
+ case SP_CSS_BLEND_NORMAL:
+ mode = "normal"; break;
+ case SP_CSS_BLEND_MULTIPLY:
+ mode = "multiply"; break;
+ case SP_CSS_BLEND_SCREEN:
+ mode = "screen"; break;
+ case SP_CSS_BLEND_DARKEN:
+ mode = "darken"; break;
+ case SP_CSS_BLEND_LIGHTEN:
+ mode = "lighten"; break;
+ // New
+ case SP_CSS_BLEND_OVERLAY:
+ mode = "overlay"; break;
+ case SP_CSS_BLEND_COLORDODGE:
+ mode = "color-dodge"; break;
+ case SP_CSS_BLEND_COLORBURN:
+ mode = "color-burn"; break;
+ case SP_CSS_BLEND_HARDLIGHT:
+ mode = "hard-light"; break;
+ case SP_CSS_BLEND_SOFTLIGHT:
+ mode = "soft-light"; break;
+ case SP_CSS_BLEND_DIFFERENCE:
+ mode = "difference"; break;
+ case SP_CSS_BLEND_EXCLUSION:
+ mode = "exclusion"; break;
+ case SP_CSS_BLEND_HUE:
+ mode = "hue"; break;
+ case SP_CSS_BLEND_SATURATION:
+ mode = "saturation"; break;
+ case SP_CSS_BLEND_COLOR:
+ mode = "color"; break;
+ case SP_CSS_BLEND_LUMINOSITY:
+ mode = "luminosity"; break;
+ default:
+ mode = nullptr;
+ }
+
+ repr->setAttribute("mode", mode);
+
+ SPFilterPrimitive::write(doc, repr, flags);
+
+ return repr;
+}
+
+void SPFeBlend::build_renderer(Inkscape::Filters::Filter* filter) {
+ g_assert(filter != nullptr);
+
+ int primitive_n = filter->add_primitive(Inkscape::Filters::NR_FILTER_BLEND);
+ Inkscape::Filters::FilterPrimitive *nr_primitive = filter->get_primitive(primitive_n);
+ Inkscape::Filters::FilterBlend *nr_blend = dynamic_cast<Inkscape::Filters::FilterBlend*>(nr_primitive);
+ g_assert(nr_blend != nullptr);
+
+ this->renderer_common(nr_primitive);
+
+ nr_blend->set_mode(this->blend_mode);
+ nr_blend->set_input(1, this->in2);
+}
+
+/*
+ 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:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/blend.h b/src/object/filters/blend.h
new file mode 100644
index 0000000..094d0cf
--- /dev/null
+++ b/src/object/filters/blend.h
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** @file
+ * @brief SVG blend filter effect
+ *//*
+ * Authors:
+ * Hugo Rodrigues <haa.rodrigues@gmail.com>
+ * Niko Kiirala <niko@kiirala.com>
+ *
+ * Copyright (C) 2006,2007 authors
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#ifndef SP_FEBLEND_H_SEEN
+#define SP_FEBLEND_H_SEEN
+
+#include "sp-filter-primitive.h"
+#include "display/nr-filter-blend.h"
+
+#define SP_FEBLEND(obj) (dynamic_cast<SPFeBlend*>((SPObject*)obj))
+#define SP_IS_FEBLEND(obj) (dynamic_cast<const SPFeBlend*>((SPObject*)obj) != NULL)
+
+class SPFeBlend : public SPFilterPrimitive {
+public:
+ SPFeBlend();
+ ~SPFeBlend() override;
+
+ SPBlendMode blend_mode;
+ int in2;
+
+protected:
+ void build(SPDocument* doc, Inkscape::XML::Node* repr) override;
+ void release() override;
+
+ void set(SPAttributeEnum key, const gchar* value) override;
+
+ void update(SPCtx* ctx, unsigned int flags) override;
+
+ Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags) override;
+
+ void build_renderer(Inkscape::Filters::Filter* filter) override;
+};
+
+#endif /* !SP_FEBLEND_H_SEEN */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/colormatrix.cpp b/src/object/filters/colormatrix.cpp
new file mode 100644
index 0000000..e35bcb2
--- /dev/null
+++ b/src/object/filters/colormatrix.cpp
@@ -0,0 +1,159 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** \file
+ * SVG <feColorMatrix> implementation.
+ *
+ */
+/*
+ * Authors:
+ * Felipe Sanches <juca@members.fsf.org>
+ * hugo Rodrigues <haa.rodrigues@gmail.com>
+ * Abhishek Sharma
+ *
+ * Copyright (C) 2007 Felipe C. da S. Sanches
+ * Copyright (C) 2006 Hugo Rodrigues
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include <cstring>
+
+#include "attributes.h"
+#include "svg/svg.h"
+#include "colormatrix.h"
+#include "xml/repr.h"
+#include "helper-fns.h"
+
+#include "display/nr-filter.h"
+
+SPFeColorMatrix::SPFeColorMatrix()
+ : SPFilterPrimitive(), type(Inkscape::Filters::COLORMATRIX_MATRIX), value(0)
+{
+}
+
+SPFeColorMatrix::~SPFeColorMatrix() = default;
+
+/**
+ * Reads the Inkscape::XML::Node, and initializes SPFeColorMatrix variables. For this to get called,
+ * our name must be associated with a repr via "sp_object_type_register". Best done through
+ * sp-object-repr.cpp's repr_name_entries array.
+ */
+void SPFeColorMatrix::build(SPDocument *document, Inkscape::XML::Node *repr) {
+ SPFilterPrimitive::build(document, repr);
+
+ /*LOAD ATTRIBUTES FROM REPR HERE*/
+ this->readAttr( "type" );
+ this->readAttr( "values" );
+}
+
+/**
+ * Drops any allocated memory.
+ */
+void SPFeColorMatrix::release() {
+ SPFilterPrimitive::release();
+}
+
+static Inkscape::Filters::FilterColorMatrixType sp_feColorMatrix_read_type(gchar const *value){
+ if (!value) {
+ return Inkscape::Filters::COLORMATRIX_MATRIX; //matrix is default
+ }
+
+ switch(value[0]){
+ case 'm':
+ if (strcmp(value, "matrix") == 0) return Inkscape::Filters::COLORMATRIX_MATRIX;
+ break;
+ case 's':
+ if (strcmp(value, "saturate") == 0) return Inkscape::Filters::COLORMATRIX_SATURATE;
+ break;
+ case 'h':
+ if (strcmp(value, "hueRotate") == 0) return Inkscape::Filters::COLORMATRIX_HUEROTATE;
+ break;
+ case 'l':
+ if (strcmp(value, "luminanceToAlpha") == 0) return Inkscape::Filters::COLORMATRIX_LUMINANCETOALPHA;
+ break;
+ }
+
+ return Inkscape::Filters::COLORMATRIX_MATRIX; //matrix is default
+}
+
+/**
+ * Sets a specific value in the SPFeColorMatrix.
+ */
+void SPFeColorMatrix::set(SPAttributeEnum key, gchar const *str) {
+ Inkscape::Filters::FilterColorMatrixType read_type;
+
+ /*DEAL WITH SETTING ATTRIBUTES HERE*/
+ switch(key) {
+ case SP_ATTR_TYPE:
+ read_type = sp_feColorMatrix_read_type(str);
+
+ if (this->type != read_type){
+ this->type = read_type;
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ case SP_ATTR_VALUES:
+ if (str){
+ this->values = helperfns_read_vector(str);
+ this->value = helperfns_read_number(str, HELPERFNS_NO_WARNING);
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ default:
+ SPFilterPrimitive::set(key, str);
+ break;
+ }
+}
+
+/**
+ * Receives update notifications.
+ */
+void SPFeColorMatrix::update(SPCtx *ctx, guint flags) {
+ if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG |
+ SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
+
+ /* do something to trigger redisplay, updates? */
+
+ }
+
+ SPFilterPrimitive::update(ctx, flags);
+}
+
+/**
+ * Writes its settings to an incoming repr object, if any.
+ */
+Inkscape::XML::Node* SPFeColorMatrix::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) {
+ /* TODO: Don't just clone, but create a new repr node and write all
+ * relevant values into it */
+ if (!repr) {
+ repr = this->getRepr()->duplicate(doc);
+ }
+
+ SPFilterPrimitive::write(doc, repr, flags);
+
+ return repr;
+}
+
+void SPFeColorMatrix::build_renderer(Inkscape::Filters::Filter* filter) {
+ g_assert(filter != nullptr);
+
+ int primitive_n = filter->add_primitive(Inkscape::Filters::NR_FILTER_COLORMATRIX);
+ Inkscape::Filters::FilterPrimitive *nr_primitive = filter->get_primitive(primitive_n);
+ Inkscape::Filters::FilterColorMatrix *nr_colormatrix = dynamic_cast<Inkscape::Filters::FilterColorMatrix*>(nr_primitive);
+ g_assert(nr_colormatrix != nullptr);
+
+ this->renderer_common(nr_primitive);
+ nr_colormatrix->set_type(this->type);
+ nr_colormatrix->set_value(this->value);
+ nr_colormatrix->set_values(this->values);
+}
+
+/*
+ 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:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/colormatrix.h b/src/object/filters/colormatrix.h
new file mode 100644
index 0000000..a44ea8a
--- /dev/null
+++ b/src/object/filters/colormatrix.h
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** @file
+ * @brief SVG color matrix filter effect
+ *//*
+ * Authors:
+ * Hugo Rodrigues <haa.rodrigues@gmail.com>
+ *
+ * Copyright (C) 2006 Hugo Rodrigues
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+#ifndef SP_FECOLORMATRIX_H_SEEN
+#define SP_FECOLORMATRIX_H_SEEN
+
+#include <vector>
+#include "sp-filter-primitive.h"
+#include "display/nr-filter-colormatrix.h"
+
+#define SP_FECOLORMATRIX(obj) (dynamic_cast<SPFeColorMatrix*>((SPObject*)obj))
+#define SP_IS_FECOLORMATRIX(obj) (dynamic_cast<const SPFeColorMatrix*>((SPObject*)obj) != NULL)
+
+class SPFeColorMatrix : public SPFilterPrimitive {
+public:
+ SPFeColorMatrix();
+ ~SPFeColorMatrix() override;
+
+ Inkscape::Filters::FilterColorMatrixType type;
+ gdouble value;
+ std::vector<gdouble> values;
+
+protected:
+ void build(SPDocument* doc, Inkscape::XML::Node* repr) override;
+ void release() override;
+
+ void set(SPAttributeEnum key, const gchar* value) override;
+
+ void update(SPCtx* ctx, unsigned int flags) override;
+
+ Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags) override;
+
+ void build_renderer(Inkscape::Filters::Filter* filter) override;
+};
+
+#endif /* !SP_FECOLORMATRIX_H_SEEN */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/componenttransfer-funcnode.cpp b/src/object/filters/componenttransfer-funcnode.cpp
new file mode 100644
index 0000000..ed6ff88
--- /dev/null
+++ b/src/object/filters/componenttransfer-funcnode.cpp
@@ -0,0 +1,213 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** \file
+ * SVG <funcR>, <funcG>, <funcB> and <funcA> implementations.
+ */
+/*
+ * Authors:
+ * Hugo Rodrigues <haa.rodrigues@gmail.com>
+ * Niko Kiirala <niko@kiirala.com>
+ * Felipe Corrêa da Silva Sanches <juca@members.fsf.org>
+ * Abhishek Sharma
+ *
+ * Copyright (C) 2006, 2007, 2008 Authors
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include <glib.h>
+
+#include "attributes.h"
+#include "document.h"
+#include "componenttransfer.h"
+#include "componenttransfer-funcnode.h"
+#include "xml/repr.h"
+#include "helper-fns.h"
+
+/* FeFuncNode class */
+SPFeFuncNode::SPFeFuncNode(SPFeFuncNode::Channel channel)
+ : SPObject(), type(Inkscape::Filters::COMPONENTTRANSFER_TYPE_IDENTITY),
+ slope(1), intercept(0), amplitude(1), exponent(1), offset(0), channel(channel) {
+}
+
+SPFeFuncNode::~SPFeFuncNode() = default;
+
+/**
+ * Reads the Inkscape::XML::Node, and initializes SPDistantLight variables. For this to get called,
+ * our name must be associated with a repr via "sp_object_type_register". Best done through
+ * sp-object-repr.cpp's repr_name_entries array.
+ */
+void SPFeFuncNode::build(SPDocument *document, Inkscape::XML::Node *repr) {
+ SPObject::build(document, repr);
+
+ //Read values of key attributes from XML nodes into object.
+ this->readAttr( "type" );
+ this->readAttr( "tableValues" );
+ this->readAttr( "slope" );
+ this->readAttr( "intercept" );
+ this->readAttr( "amplitude" );
+ this->readAttr( "exponent" );
+ this->readAttr( "offset" );
+
+
+//is this necessary?
+ document->addResource("fefuncnode", this); //maybe feFuncR, fefuncG, feFuncB and fefuncA ?
+}
+
+/**
+ * Drops any allocated memory.
+ */
+void SPFeFuncNode::release() {
+ if ( this->document ) {
+ // Unregister ourselves
+ this->document->removeResource("fefuncnode", this);
+ }
+
+//TODO: release resources here
+}
+
+static Inkscape::Filters::FilterComponentTransferType sp_feComponenttransfer_read_type(gchar const *value){
+ if (!value) {
+ return Inkscape::Filters::COMPONENTTRANSFER_TYPE_ERROR; //type attribute is REQUIRED.
+ }
+
+ switch(value[0]){
+ case 'i':
+ if (strncmp(value, "identity", 8) == 0) {
+ return Inkscape::Filters::COMPONENTTRANSFER_TYPE_IDENTITY;
+ }
+ break;
+ case 't':
+ if (strncmp(value, "table", 5) == 0) {
+ return Inkscape::Filters::COMPONENTTRANSFER_TYPE_TABLE;
+ }
+ break;
+ case 'd':
+ if (strncmp(value, "discrete", 8) == 0) {
+ return Inkscape::Filters::COMPONENTTRANSFER_TYPE_DISCRETE;
+ }
+ break;
+ case 'l':
+ if (strncmp(value, "linear", 6) == 0) {
+ return Inkscape::Filters::COMPONENTTRANSFER_TYPE_LINEAR;
+ }
+ break;
+ case 'g':
+ if (strncmp(value, "gamma", 5) == 0) {
+ return Inkscape::Filters::COMPONENTTRANSFER_TYPE_GAMMA;
+ }
+ break;
+ }
+
+ return Inkscape::Filters::COMPONENTTRANSFER_TYPE_ERROR; //type attribute is REQUIRED.
+}
+
+/**
+ * Sets a specific value in the SPFeFuncNode.
+ */
+void SPFeFuncNode::set(SPAttributeEnum key, gchar const *value) {
+ Inkscape::Filters::FilterComponentTransferType type;
+ double read_num;
+
+ switch(key) {
+ case SP_ATTR_TYPE:
+ type = sp_feComponenttransfer_read_type(value);
+
+ if(type != this->type) {
+ this->type = type;
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ case SP_ATTR_TABLEVALUES:
+ if (value){
+ this->tableValues = helperfns_read_vector(value);
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ case SP_ATTR_SLOPE:
+ read_num = value ? helperfns_read_number(value) : 1;
+
+ if (read_num != this->slope) {
+ this->slope = read_num;
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ case SP_ATTR_INTERCEPT:
+ read_num = value ? helperfns_read_number(value) : 0;
+
+ if (read_num != this->intercept) {
+ this->intercept = read_num;
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ case SP_ATTR_AMPLITUDE:
+ read_num = value ? helperfns_read_number(value) : 1;
+
+ if (read_num != this->amplitude) {
+ this->amplitude = read_num;
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ case SP_ATTR_EXPONENT:
+ read_num = value ? helperfns_read_number(value) : 1;
+
+ if (read_num != this->exponent) {
+ this->exponent = read_num;
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ case SP_ATTR_OFFSET:
+ read_num = value ? helperfns_read_number(value) : 0;
+
+ if (read_num != this->offset) {
+ this->offset = read_num;
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ default:
+ SPObject::set(key, value);
+ break;
+ }
+}
+
+/**
+ * Receives update notifications.
+ */
+void SPFeFuncNode::update(SPCtx *ctx, guint flags) {
+ std::cout << "SPFeFuncNode::update" << std::endl;
+ if (flags & SP_OBJECT_MODIFIED_FLAG) {
+ this->readAttr( "type" );
+ this->readAttr( "tableValues" );
+ this->readAttr( "slope" );
+ this->readAttr( "intercept" );
+ this->readAttr( "amplitude" );
+ this->readAttr( "exponent" );
+ this->readAttr( "offset" );
+ }
+
+ SPObject::update(ctx, flags);
+}
+
+/**
+ * Writes its settings to an incoming repr object, if any.
+ */
+Inkscape::XML::Node* SPFeFuncNode::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) {
+ std::cout << "SPFeFuncNode::write" << std::endl;
+ if (!repr) {
+ repr = this->getRepr()->duplicate(doc);
+ }
+
+ SPObject::write(doc, repr, flags);
+
+ return repr;
+}
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/componenttransfer-funcnode.h b/src/object/filters/componenttransfer-funcnode.h
new file mode 100644
index 0000000..8022035
--- /dev/null
+++ b/src/object/filters/componenttransfer-funcnode.h
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#ifndef SP_FECOMPONENTTRANSFER_FUNCNODE_H_SEEN
+#define SP_FECOMPONENTTRANSFER_FUNCNODE_H_SEEN
+
+/** \file
+ * SVG <filter> implementation, see sp-filter.cpp.
+ */
+/*
+ * Authors:
+ * Hugo Rodrigues <haa.rodrigues@gmail.com>
+ * Niko Kiirala <niko@kiirala.com>
+ * Felipe Corrêa da Silva Sanches <juca@members.fsf.org>
+ *
+ * Copyright (C) 2006,2007 Authors
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include "../sp-object.h"
+#include "display/nr-filter-component-transfer.h"
+
+#define SP_FEFUNCNODE(obj) (dynamic_cast<SPFeFuncNode*>((SPObject*)obj))
+
+class SPFeFuncNode : public SPObject {
+public:
+ enum Channel {
+ R, G, B, A
+ };
+
+ SPFeFuncNode(Channel channel);
+ ~SPFeFuncNode() override;
+
+ Inkscape::Filters::FilterComponentTransferType type;
+ std::vector<double> tableValues;
+ double slope;
+ double intercept;
+ double amplitude;
+ double exponent;
+ double offset;
+ Channel channel;
+
+protected:
+ void build(SPDocument* doc, Inkscape::XML::Node* repr) override;
+ void release() override;
+
+ void set(SPAttributeEnum key, const gchar* value) override;
+
+ void update(SPCtx* ctx, unsigned int flags) override;
+
+ Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags) override;
+};
+
+#endif /* !SP_FECOMPONENTTRANSFER_FUNCNODE_H_SEEN */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/componenttransfer.cpp b/src/object/filters/componenttransfer.cpp
new file mode 100644
index 0000000..3a921c2
--- /dev/null
+++ b/src/object/filters/componenttransfer.cpp
@@ -0,0 +1,189 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** \file
+ * SVG <feComponentTransfer> implementation.
+ *
+ */
+/*
+ * Authors:
+ * hugo Rodrigues <haa.rodrigues@gmail.com>
+ * Abhishek Sharma
+ *
+ * Copyright (C) 2006 Hugo Rodrigues
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include "attributes.h"
+#include "document.h"
+
+// In same directory
+#include "componenttransfer.h"
+#include "componenttransfer-funcnode.h"
+
+#include "display/nr-filter.h"
+
+#include "xml/repr.h"
+
+SPFeComponentTransfer::SPFeComponentTransfer()
+ : SPFilterPrimitive(), renderer(nullptr)
+{
+}
+
+SPFeComponentTransfer::~SPFeComponentTransfer() = default;
+
+/**
+ * Reads the Inkscape::XML::Node, and initializes SPFeComponentTransfer variables. For this to get called,
+ * our name must be associated with a repr via "sp_object_type_register". Best done through
+ * sp-object-repr.cpp's repr_name_entries array.
+ */
+void SPFeComponentTransfer::build(SPDocument *document, Inkscape::XML::Node *repr) {
+ SPFilterPrimitive::build(document, repr);
+
+ /*LOAD ATTRIBUTES FROM REPR HERE*/
+
+ //do we need this?
+ //document->addResource("feComponentTransfer", object);
+}
+
+static void sp_feComponentTransfer_children_modified(SPFeComponentTransfer *sp_componenttransfer)
+{
+ if (sp_componenttransfer->renderer) {
+ bool set[4] = {false, false, false, false};
+ for(auto& node: sp_componenttransfer->children) {
+ int i = 4;
+
+ SPFeFuncNode *funcNode = SP_FEFUNCNODE(&node);
+ if(!funcNode) {
+ continue;
+ }
+
+ switch (funcNode->channel) {
+ case SPFeFuncNode::R:
+ i = 0;
+ break;
+ case SPFeFuncNode::G:
+ i = 1;
+ break;
+ case SPFeFuncNode::B:
+ i = 2;
+ break;
+ case SPFeFuncNode::A:
+ i = 3;
+ break;
+ }
+
+ if (i == 4) {
+ g_warning("Unrecognized channel for component transfer.");
+ break;
+ }
+ sp_componenttransfer->renderer->type[i] = ((SPFeFuncNode *) &node)->type;
+ sp_componenttransfer->renderer->tableValues[i] = ((SPFeFuncNode *) &node)->tableValues;
+ sp_componenttransfer->renderer->slope[i] = ((SPFeFuncNode *) &node)->slope;
+ sp_componenttransfer->renderer->intercept[i] = ((SPFeFuncNode *) &node)->intercept;
+ sp_componenttransfer->renderer->amplitude[i] = ((SPFeFuncNode *) &node)->amplitude;
+ sp_componenttransfer->renderer->exponent[i] = ((SPFeFuncNode *) &node)->exponent;
+ sp_componenttransfer->renderer->offset[i] = ((SPFeFuncNode *) &node)->offset;
+ set[i] = true;
+ }
+ // Set any types not explicitly set to the identity transform
+ for(int i=0;i<4;i++) {
+ if (!set[i]) {
+ sp_componenttransfer->renderer->type[i] = Inkscape::Filters::COMPONENTTRANSFER_TYPE_IDENTITY;
+ }
+ }
+ }
+}
+
+/**
+ * Callback for child_added event.
+ */
+void SPFeComponentTransfer::child_added(Inkscape::XML::Node *child, Inkscape::XML::Node *ref) {
+ SPFilterPrimitive::child_added(child, ref);
+
+ sp_feComponentTransfer_children_modified(this);
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+}
+
+/**
+ * Callback for remove_child event.
+ */
+void SPFeComponentTransfer::remove_child(Inkscape::XML::Node *child) {
+ SPFilterPrimitive::remove_child(child);
+
+ sp_feComponentTransfer_children_modified(this);
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+}
+
+/**
+ * Drops any allocated memory.
+ */
+void SPFeComponentTransfer::release() {
+ SPFilterPrimitive::release();
+}
+
+/**
+ * Sets a specific value in the SPFeComponentTransfer.
+ */
+void SPFeComponentTransfer::set(SPAttributeEnum key, gchar const *value) {
+ switch(key) {
+ /*DEAL WITH SETTING ATTRIBUTES HERE*/
+ default:
+ SPFilterPrimitive::set(key, value);
+ break;
+ }
+}
+
+/**
+ * Receives update notifications.
+ */
+void SPFeComponentTransfer::update(SPCtx *ctx, guint flags) {
+ if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG |
+ SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
+
+ /* do something to trigger redisplay, updates? */
+
+ }
+
+ SPFilterPrimitive::update(ctx, flags);
+}
+
+/**
+ * Writes its settings to an incoming repr object, if any.
+ */
+Inkscape::XML::Node* SPFeComponentTransfer::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) {
+ /* TODO: Don't just clone, but create a new repr node and write all
+ * relevant values into it */
+ if (!repr) {
+ repr = this->getRepr()->duplicate(doc);
+ }
+
+ SPFilterPrimitive::write(doc, repr, flags);
+
+ return repr;
+}
+
+void SPFeComponentTransfer::build_renderer(Inkscape::Filters::Filter* filter) {
+ g_assert(filter != nullptr);
+
+ int primitive_n = filter->add_primitive(Inkscape::Filters::NR_FILTER_COMPONENTTRANSFER);
+ Inkscape::Filters::FilterPrimitive *nr_primitive = filter->get_primitive(primitive_n);
+ Inkscape::Filters::FilterComponentTransfer *nr_componenttransfer = dynamic_cast<Inkscape::Filters::FilterComponentTransfer*>(nr_primitive);
+ g_assert(nr_componenttransfer != nullptr);
+
+ this->renderer = nr_componenttransfer;
+ this->renderer_common(nr_primitive);
+
+
+ sp_feComponentTransfer_children_modified(this); //do we need it?!
+}
+
+/*
+ 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:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/componenttransfer.h b/src/object/filters/componenttransfer.h
new file mode 100644
index 0000000..b1ca47c
--- /dev/null
+++ b/src/object/filters/componenttransfer.h
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** @file
+ * @brief SVG component transferfilter effect
+ *//*
+ * Authors:
+ * Hugo Rodrigues <haa.rodrigues@gmail.com>
+ *
+ * Copyright (C) 2006 Hugo Rodrigues
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+#ifndef SP_FECOMPONENTTRANSFER_H_SEEN
+#define SP_FECOMPONENTTRANSFER_H_SEEN
+
+#include "sp-filter-primitive.h"
+
+#define SP_FECOMPONENTTRANSFER(obj) (dynamic_cast<SPFeComponentTransfer*>((SPObject*)obj))
+#define SP_IS_FECOMPONENTTRANSFER(obj) (dynamic_cast<const SPFeComponentTransfer*>((SPObject*)obj) != NULL)
+
+namespace Inkscape {
+namespace Filters {
+class FilterComponentTransfer;
+} }
+
+class SPFeComponentTransfer : public SPFilterPrimitive {
+public:
+ SPFeComponentTransfer();
+ ~SPFeComponentTransfer() override;
+
+ Inkscape::Filters::FilterComponentTransfer *renderer;
+
+protected:
+ void build(SPDocument* doc, Inkscape::XML::Node* repr) override;
+ void release() override;
+
+ void child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref) override;
+ void remove_child(Inkscape::XML::Node* child) override;
+
+ void set(SPAttributeEnum key, const gchar* value) override;
+
+ void update(SPCtx* ctx, unsigned int flags) override;
+
+ Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags) override;
+
+ void build_renderer(Inkscape::Filters::Filter* filter) override;
+};
+
+#endif /* !SP_FECOMPONENTTRANSFER_H_SEEN */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/composite.cpp b/src/object/filters/composite.cpp
new file mode 100644
index 0000000..716aeaa
--- /dev/null
+++ b/src/object/filters/composite.cpp
@@ -0,0 +1,333 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** \file
+ * SVG <feComposite> implementation.
+ *
+ */
+/*
+ * Authors:
+ * hugo Rodrigues <haa.rodrigues@gmail.com>
+ * Abhishek Sharma
+ *
+ * Copyright (C) 2006 Hugo Rodrigues
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include "composite.h"
+
+#include "attributes.h"
+#include "helper-fns.h"
+
+#include "display/nr-filter.h"
+#include "display/nr-filter-composite.h"
+
+#include "object/sp-filter.h"
+
+#include "svg/svg.h"
+
+#include "xml/repr.h"
+
+SPFeComposite::SPFeComposite()
+ : SPFilterPrimitive(), composite_operator(COMPOSITE_DEFAULT),
+ k1(0), k2(0), k3(0), k4(0), in2(Inkscape::Filters::NR_FILTER_SLOT_NOT_SET)
+{
+}
+
+SPFeComposite::~SPFeComposite() = default;
+
+/**
+ * Reads the Inkscape::XML::Node, and initializes SPFeComposite variables. For this to get called,
+ * our name must be associated with a repr via "sp_object_type_register". Best done through
+ * sp-object-repr.cpp's repr_name_entries array.
+ */
+void SPFeComposite::build(SPDocument *document, Inkscape::XML::Node *repr) {
+ SPFilterPrimitive::build(document, repr);
+
+ this->readAttr( "operator" );
+
+ if (this->composite_operator == COMPOSITE_ARITHMETIC) {
+ this->readAttr( "k1" );
+ this->readAttr( "k2" );
+ this->readAttr( "k3" );
+ this->readAttr( "k4" );
+ }
+
+ this->readAttr( "in2" );
+
+ /* Unlike normal in, in2 is required attribute. Make sure, we can call
+ * it by some name. */
+ if (this->in2 == Inkscape::Filters::NR_FILTER_SLOT_NOT_SET ||
+ this->in2 == Inkscape::Filters::NR_FILTER_UNNAMED_SLOT)
+ {
+ SPFilter *parent = SP_FILTER(this->parent);
+ this->in2 = this->name_previous_out();
+ repr->setAttribute("in2", parent->name_for_image(this->in2));
+ }
+}
+
+/**
+ * Drops any allocated memory.
+ */
+void SPFeComposite::release() {
+ SPFilterPrimitive::release();
+}
+
+static FeCompositeOperator
+sp_feComposite_read_operator(gchar const *value) {
+ if (!value) {
+ return COMPOSITE_DEFAULT;
+ }
+
+ if (strcmp(value, "over") == 0) {
+ return COMPOSITE_OVER;
+ } else if (strcmp(value, "in") == 0) {
+ return COMPOSITE_IN;
+ } else if (strcmp(value, "out") == 0) {
+ return COMPOSITE_OUT;
+ } else if (strcmp(value, "atop") == 0) {
+ return COMPOSITE_ATOP;
+ } else if (strcmp(value, "xor") == 0) {
+ return COMPOSITE_XOR;
+ } else if (strcmp(value, "arithmetic") == 0) {
+ return COMPOSITE_ARITHMETIC;
+ }
+#ifdef WITH_CSSCOMPOSITE
+ else if (strcmp(value, "clear") == 0) {
+ return COMPOSITE_CLEAR;
+ } else if (strcmp(value, "copy") == 0) {
+ return COMPOSITE_COPY;
+ } else if (strcmp(value, "destination") == 0) {
+ return COMPOSITE_DESTINATION;
+ } else if (strcmp(value, "destination-over") == 0) {
+ return COMPOSITE_DESTINATION_OVER;
+ } else if (strcmp(value, "destination-in") == 0) {
+ return COMPOSITE_DESTINATION_IN;
+ } else if (strcmp(value, "destination-out") == 0) {
+ return COMPOSITE_DESTINATION_OUT;
+ } else if (strcmp(value, "destination-atop") == 0) {
+ return COMPOSITE_DESTINATION_ATOP;
+ } else if (strcmp(value, "lighter") == 0) {
+ return COMPOSITE_LIGHTER;
+ }
+#endif
+ std::cout << "Inkscape::Filters::FilterCompositeOperator: Unimplemented operator: " << value << std::endl;
+
+ return COMPOSITE_DEFAULT;
+}
+
+/**
+ * Sets a specific value in the SPFeComposite.
+ */
+void SPFeComposite::set(SPAttributeEnum key, gchar const *value) {
+ int input;
+ FeCompositeOperator op;
+ double k_n;
+
+ switch(key) {
+ /*DEAL WITH SETTING ATTRIBUTES HERE*/
+ case SP_ATTR_OPERATOR:
+ op = sp_feComposite_read_operator(value);
+ if (op != this->composite_operator) {
+ this->composite_operator = op;
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+
+ case SP_ATTR_K1:
+ k_n = value ? helperfns_read_number(value) : 0;
+ if (k_n != this->k1) {
+ this->k1 = k_n;
+ if (this->composite_operator == COMPOSITE_ARITHMETIC)
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+
+ case SP_ATTR_K2:
+ k_n = value ? helperfns_read_number(value) : 0;
+ if (k_n != this->k2) {
+ this->k2 = k_n;
+ if (this->composite_operator == COMPOSITE_ARITHMETIC)
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+
+ case SP_ATTR_K3:
+ k_n = value ? helperfns_read_number(value) : 0;
+ if (k_n != this->k3) {
+ this->k3 = k_n;
+ if (this->composite_operator == COMPOSITE_ARITHMETIC)
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+
+ case SP_ATTR_K4:
+ k_n = value ? helperfns_read_number(value) : 0;
+ if (k_n != this->k4) {
+ this->k4 = k_n;
+ if (this->composite_operator == COMPOSITE_ARITHMETIC)
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+
+ case SP_ATTR_IN2:
+ input = this->read_in(value);
+ if (input != this->in2) {
+ this->in2 = input;
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+
+ default:
+ SPFilterPrimitive::set(key, value);
+ break;
+ }
+}
+
+/**
+ * Receives update notifications.
+ */
+void SPFeComposite::update(SPCtx *ctx, guint flags) {
+ if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG |
+ SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
+
+ /* do something to trigger redisplay, updates? */
+
+ }
+
+ /* Unlike normal in, in2 is required attribute. Make sure, we can call
+ * it by some name. */
+ /* This may not be true.... see issue at
+ * http://www.w3.org/TR/filter-effects/#feBlendElement (but it doesn't hurt). */
+ if (this->in2 == Inkscape::Filters::NR_FILTER_SLOT_NOT_SET ||
+ this->in2 == Inkscape::Filters::NR_FILTER_UNNAMED_SLOT)
+ {
+ SPFilter *parent = SP_FILTER(this->parent);
+ this->in2 = this->name_previous_out();
+
+ //XML Tree being used directly here while it shouldn't be.
+ this->setAttribute("in2", parent->name_for_image(this->in2));
+ }
+
+ SPFilterPrimitive::update(ctx, flags);
+}
+
+/**
+ * Writes its settings to an incoming repr object, if any.
+ */
+Inkscape::XML::Node* SPFeComposite::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) {
+ SPFilter *parent = SP_FILTER(this->parent);
+
+ if (!repr) {
+ repr = doc->createElement("svg:feComposite");
+ }
+
+ gchar const *in2_name = parent->name_for_image(this->in2);
+
+ if( !in2_name ) {
+
+ // This code is very similar to name_previous_out()
+ SPObject *i = parent->firstChild();
+
+ // Find previous filter primitive
+ while (i && i->getNext() != this) {
+ i = i->getNext();
+ }
+
+ if( i ) {
+ SPFilterPrimitive *i_prim = SP_FILTER_PRIMITIVE(i);
+ in2_name = parent->name_for_image(i_prim->image_out);
+ }
+ }
+
+ if (in2_name) {
+ repr->setAttribute("in2", in2_name);
+ } else {
+ g_warning("Unable to set in2 for feComposite");
+ }
+
+ char const *comp_op;
+
+ switch (this->composite_operator) {
+ case COMPOSITE_OVER:
+ comp_op = "over"; break;
+ case COMPOSITE_IN:
+ comp_op = "in"; break;
+ case COMPOSITE_OUT:
+ comp_op = "out"; break;
+ case COMPOSITE_ATOP:
+ comp_op = "atop"; break;
+ case COMPOSITE_XOR:
+ comp_op = "xor"; break;
+ case COMPOSITE_ARITHMETIC:
+ comp_op = "arithmetic"; break;
+#ifdef WITH_CSSCOMPOSITE
+ // New CSS operators
+ case COMPOSITE_CLEAR:
+ comp_op = "clear"; break;
+ case COMPOSITE_COPY:
+ comp_op = "copy"; break;
+ case COMPOSITE_DESTINATION:
+ comp_op = "destination"; break;
+ case COMPOSITE_DESTINATION_OVER:
+ comp_op = "destination-over"; break;
+ case COMPOSITE_DESTINATION_IN:
+ comp_op = "destination-in"; break;
+ case COMPOSITE_DESTINATION_OUT:
+ comp_op = "destination-out"; break;
+ case COMPOSITE_DESTINATION_ATOP:
+ comp_op = "destination-atop"; break;
+ case COMPOSITE_LIGHTER:
+ comp_op = "lighter"; break;
+#endif
+ default:
+ comp_op = nullptr;
+ }
+
+ repr->setAttribute("operator", comp_op);
+
+ if (this->composite_operator == COMPOSITE_ARITHMETIC) {
+ sp_repr_set_svg_double(repr, "k1", this->k1);
+ sp_repr_set_svg_double(repr, "k2", this->k2);
+ sp_repr_set_svg_double(repr, "k3", this->k3);
+ sp_repr_set_svg_double(repr, "k4", this->k4);
+ } else {
+ repr->removeAttribute("k1");
+ repr->removeAttribute("k2");
+ repr->removeAttribute("k3");
+ repr->removeAttribute("k4");
+ }
+
+ SPFilterPrimitive::write(doc, repr, flags);
+
+ return repr;
+}
+
+void SPFeComposite::build_renderer(Inkscape::Filters::Filter* filter) {
+ g_assert(filter != nullptr);
+
+ int primitive_n = filter->add_primitive(Inkscape::Filters::NR_FILTER_COMPOSITE);
+ Inkscape::Filters::FilterPrimitive *nr_primitive = filter->get_primitive(primitive_n);
+ Inkscape::Filters::FilterComposite *nr_composite = dynamic_cast<Inkscape::Filters::FilterComposite*>(nr_primitive);
+ g_assert(nr_composite != nullptr);
+
+ this->renderer_common(nr_primitive);
+
+ nr_composite->set_operator(this->composite_operator);
+ nr_composite->set_input(1, this->in2);
+
+ if (this->composite_operator == COMPOSITE_ARITHMETIC) {
+ nr_composite->set_arithmetic(this->k1, this->k2,
+ this->k3, this->k4);
+ }
+}
+
+/*
+ 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:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/composite.h b/src/object/filters/composite.h
new file mode 100644
index 0000000..1205b31
--- /dev/null
+++ b/src/object/filters/composite.h
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** @file
+ * @brief SVG composite filter effect
+ *//*
+ * Authors:
+ * Hugo Rodrigues <haa.rodrigues@gmail.com>
+ *
+ * Copyright (C) 2006 Hugo Rodrigues
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+#ifndef SP_FECOMPOSITE_H_SEEN
+#define SP_FECOMPOSITE_H_SEEN
+
+#include "sp-filter-primitive.h"
+
+#define SP_FECOMPOSITE(obj) (dynamic_cast<SPFeComposite*>((SPObject*)obj))
+#define SP_IS_FECOMPOSITE(obj) (dynamic_cast<const SPFeComposite*>((SPObject*)obj) != NULL)
+
+enum FeCompositeOperator {
+ // Default value is 'over', but let's distinquish specifying the
+ // default and implicitly using the default
+ COMPOSITE_DEFAULT,
+ COMPOSITE_OVER, /* Source Over */
+ COMPOSITE_IN, /* Source In */
+ COMPOSITE_OUT, /* Source Out */
+ COMPOSITE_ATOP, /* Source Atop */
+ COMPOSITE_XOR,
+ COMPOSITE_ARITHMETIC, /* Not a fundamental PorterDuff operator, nor Cairo */
+#ifdef WITH_CSSCOMPOSITE
+ // New in CSS
+ COMPOSITE_CLEAR,
+ COMPOSITE_COPY, /* Source */
+ COMPOSITE_DESTINATION,
+ COMPOSITE_DESTINATION_OVER,
+ COMPOSITE_DESTINATION_IN,
+ COMPOSITE_DESTINATION_OUT,
+ COMPOSITE_DESTINATION_ATOP,
+ COMPOSITE_LIGHTER, /* Plus, Add (Not a fundamental PorterDuff operator */
+#endif
+ COMPOSITE_ENDOPERATOR /* Cairo Saturate is not included in CSS */
+};
+
+class SPFeComposite : public SPFilterPrimitive {
+public:
+ SPFeComposite();
+ ~SPFeComposite() override;
+
+ FeCompositeOperator composite_operator;
+ double k1, k2, k3, k4;
+ int in2;
+
+protected:
+ void build(SPDocument* doc, Inkscape::XML::Node* repr) override;
+ void release() override;
+
+ void set(SPAttributeEnum key, const gchar* value) override;
+
+ void update(SPCtx* ctx, unsigned int flags) override;
+
+ Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags) override;
+
+ void build_renderer(Inkscape::Filters::Filter* filter) override;
+};
+
+#endif /* !SP_FECOMPOSITE_H_SEEN */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/convolvematrix.cpp b/src/object/filters/convolvematrix.cpp
new file mode 100644
index 0000000..658a383
--- /dev/null
+++ b/src/object/filters/convolvematrix.cpp
@@ -0,0 +1,318 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** \file
+ * SVG <feConvolveMatrix> implementation.
+ *
+ */
+/*
+ * Authors:
+ * Felipe Corrêa da Silva Sanches <juca@members.fsf.org>
+ * hugo Rodrigues <haa.rodrigues@gmail.com>
+ * Abhishek Sharma
+ *
+ * Copyright (C) 2006 Hugo Rodrigues
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include <cstring>
+#include <cmath>
+#include <vector>
+
+#include "convolvematrix.h"
+
+#include "attributes.h"
+#include "helper-fns.h"
+
+#include "display/nr-filter.h"
+
+#include "xml/repr.h"
+
+SPFeConvolveMatrix::SPFeConvolveMatrix() : SPFilterPrimitive() {
+ this->bias = 0;
+ this->divisorIsSet = false;
+ this->divisor = 0;
+
+ //Setting default values:
+ this->order.set("3 3");
+ this->targetX = 1;
+ this->targetY = 1;
+ this->edgeMode = Inkscape::Filters::CONVOLVEMATRIX_EDGEMODE_DUPLICATE;
+ this->preserveAlpha = false;
+
+ //some helper variables:
+ this->targetXIsSet = false;
+ this->targetYIsSet = false;
+ this->kernelMatrixIsSet = false;
+}
+
+SPFeConvolveMatrix::~SPFeConvolveMatrix() = default;
+
+/**
+ * Reads the Inkscape::XML::Node, and initializes SPFeConvolveMatrix variables. For this to get called,
+ * our name must be associated with a repr via "sp_object_type_register". Best done through
+ * sp-object-repr.cpp's repr_name_entries array.
+ */
+void SPFeConvolveMatrix::build(SPDocument *document, Inkscape::XML::Node *repr) {
+ SPFilterPrimitive::build(document, repr);
+
+ /*LOAD ATTRIBUTES FROM REPR HERE*/
+ this->readAttr( "order" );
+ this->readAttr( "kernelMatrix" );
+ this->readAttr( "divisor" );
+ this->readAttr( "bias" );
+ this->readAttr( "targetX" );
+ this->readAttr( "targetY" );
+ this->readAttr( "edgeMode" );
+ this->readAttr( "kernelUnitLength" );
+ this->readAttr( "preserveAlpha" );
+}
+
+/**
+ * Drops any allocated memory.
+ */
+void SPFeConvolveMatrix::release() {
+ SPFilterPrimitive::release();
+}
+
+static Inkscape::Filters::FilterConvolveMatrixEdgeMode sp_feConvolveMatrix_read_edgeMode(gchar const *value){
+ if (!value) {
+ return Inkscape::Filters::CONVOLVEMATRIX_EDGEMODE_DUPLICATE; //duplicate is default
+ }
+
+ switch (value[0]) {
+ case 'd':
+ if (strncmp(value, "duplicate", 9) == 0) {
+ return Inkscape::Filters::CONVOLVEMATRIX_EDGEMODE_DUPLICATE;
+ }
+ break;
+ case 'w':
+ if (strncmp(value, "wrap", 4) == 0) {
+ return Inkscape::Filters::CONVOLVEMATRIX_EDGEMODE_WRAP;
+ }
+ break;
+ case 'n':
+ if (strncmp(value, "none", 4) == 0) {
+ return Inkscape::Filters::CONVOLVEMATRIX_EDGEMODE_NONE;
+ }
+ break;
+ }
+
+ return Inkscape::Filters::CONVOLVEMATRIX_EDGEMODE_DUPLICATE; //duplicate is default
+}
+
+/**
+ * Sets a specific value in the SPFeConvolveMatrix.
+ */
+void SPFeConvolveMatrix::set(SPAttributeEnum key, gchar const *value) {
+ double read_num;
+ int read_int;
+ bool read_bool;
+ Inkscape::Filters::FilterConvolveMatrixEdgeMode read_mode;
+
+ switch(key) {
+ /*DEAL WITH SETTING ATTRIBUTES HERE*/
+ case SP_ATTR_ORDER:
+ this->order.set(value);
+
+ //From SVG spec: If <orderY> is not provided, it defaults to <orderX>.
+ if (this->order.optNumIsSet() == false) {
+ this->order.setOptNumber(this->order.getNumber());
+ }
+
+ if (this->targetXIsSet == false) {
+ this->targetX = (int) floor(this->order.getNumber()/2);
+ }
+
+ if (this->targetYIsSet == false) {
+ this->targetY = (int) floor(this->order.getOptNumber()/2);
+ }
+
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ break;
+ case SP_ATTR_KERNELMATRIX:
+ if (value){
+ this->kernelMatrixIsSet = true;
+ this->kernelMatrix = helperfns_read_vector(value);
+
+ if (! this->divisorIsSet) {
+ this->divisor = 0;
+
+ for (double i : this->kernelMatrix) {
+ this->divisor += i;
+ }
+
+ if (this->divisor == 0) {
+ this->divisor = 1;
+ }
+ }
+
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ } else {
+ g_warning("For feConvolveMatrix you MUST pass a kernelMatrix parameter!");
+ }
+ break;
+ case SP_ATTR_DIVISOR:
+ if (value) {
+ read_num = helperfns_read_number(value);
+
+ if (read_num == 0) {
+ // This should actually be an error, but given our UI it is more useful to simply set divisor to the default.
+ if (this->kernelMatrixIsSet) {
+ for (double i : this->kernelMatrix) {
+ read_num += i;
+ }
+ }
+
+ if (read_num == 0) {
+ read_num = 1;
+ }
+
+ if (this->divisorIsSet || this->divisor!=read_num) {
+ this->divisorIsSet = false;
+ this->divisor = read_num;
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ } else if (!this->divisorIsSet || this->divisor!=read_num) {
+ this->divisorIsSet = true;
+ this->divisor = read_num;
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ }
+ break;
+ case SP_ATTR_BIAS:
+ read_num = 0;
+ if (value) {
+ read_num = helperfns_read_number(value);
+ }
+
+ if (read_num != this->bias){
+ this->bias = read_num;
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ case SP_ATTR_TARGETX:
+ if (value) {
+ read_int = (int) helperfns_read_number(value);
+
+ if (read_int < 0 || read_int > this->order.getNumber()){
+ g_warning("targetX must be a value between 0 and orderX! Assuming floor(orderX/2) as default value.");
+ read_int = (int) floor(this->order.getNumber()/2.0);
+ }
+
+ this->targetXIsSet = true;
+
+ if (read_int != this->targetX){
+ this->targetX = read_int;
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ }
+ break;
+ case SP_ATTR_TARGETY:
+ if (value) {
+ read_int = (int) helperfns_read_number(value);
+
+ if (read_int < 0 || read_int > this->order.getOptNumber()){
+ g_warning("targetY must be a value between 0 and orderY! Assuming floor(orderY/2) as default value.");
+ read_int = (int) floor(this->order.getOptNumber()/2.0);
+ }
+
+ this->targetYIsSet = true;
+
+ if (read_int != this->targetY){
+ this->targetY = read_int;
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ }
+ break;
+ case SP_ATTR_EDGEMODE:
+ read_mode = sp_feConvolveMatrix_read_edgeMode(value);
+
+ if (read_mode != this->edgeMode){
+ this->edgeMode = read_mode;
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ case SP_ATTR_KERNELUNITLENGTH:
+ this->kernelUnitLength.set(value);
+
+ //From SVG spec: If the <dy> value is not specified, it defaults to the same value as <dx>.
+ if (this->kernelUnitLength.optNumIsSet() == false) {
+ this->kernelUnitLength.setOptNumber(this->kernelUnitLength.getNumber());
+ }
+
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ break;
+ case SP_ATTR_PRESERVEALPHA:
+ read_bool = helperfns_read_bool(value, false);
+
+ if (read_bool != this->preserveAlpha){
+ this->preserveAlpha = read_bool;
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ default:
+ SPFilterPrimitive::set(key, value);
+ break;
+ }
+
+}
+
+/**
+ * Receives update notifications.
+ */
+void SPFeConvolveMatrix::update(SPCtx *ctx, guint flags) {
+ if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG |
+ SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
+
+ /* do something to trigger redisplay, updates? */
+
+ }
+
+ SPFilterPrimitive::update(ctx, flags);
+}
+
+/**
+ * Writes its settings to an incoming repr object, if any.
+ */
+Inkscape::XML::Node* SPFeConvolveMatrix::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) {
+ /* TODO: Don't just clone, but create a new repr node and write all
+ * relevant values into it */
+ if (!repr) {
+ repr = this->getRepr()->duplicate(doc);
+ }
+
+
+ SPFilterPrimitive::write(doc, repr, flags);
+
+ return repr;
+}
+
+void SPFeConvolveMatrix::build_renderer(Inkscape::Filters::Filter* filter) {
+ g_assert(filter != nullptr);
+
+ int primitive_n = filter->add_primitive(Inkscape::Filters::NR_FILTER_CONVOLVEMATRIX);
+ Inkscape::Filters::FilterPrimitive *nr_primitive = filter->get_primitive(primitive_n);
+ Inkscape::Filters::FilterConvolveMatrix *nr_convolve = dynamic_cast<Inkscape::Filters::FilterConvolveMatrix*>(nr_primitive);
+ g_assert(nr_convolve != nullptr);
+
+ this->renderer_common(nr_primitive);
+
+ nr_convolve->set_targetX(this->targetX);
+ nr_convolve->set_targetY(this->targetY);
+ nr_convolve->set_orderX( (int)this->order.getNumber() );
+ nr_convolve->set_orderY( (int)this->order.getOptNumber() );
+ nr_convolve->set_kernelMatrix(this->kernelMatrix);
+ nr_convolve->set_divisor(this->divisor);
+ nr_convolve->set_bias(this->bias);
+ nr_convolve->set_preserveAlpha(this->preserveAlpha);
+}
+/*
+ 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:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/convolvematrix.h b/src/object/filters/convolvematrix.h
new file mode 100644
index 0000000..e19608a
--- /dev/null
+++ b/src/object/filters/convolvematrix.h
@@ -0,0 +1,67 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** @file
+ * @brief SVG matrix convolution filter effect
+ */
+/*
+ * Authors:
+ * Felipe Corrêa da Silva Sanches <juca@members.fsf.org>
+ * Hugo Rodrigues <haa.rodrigues@gmail.com>
+ *
+ * Copyright (C) 2006 Hugo Rodrigues
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+#ifndef SP_FECONVOLVEMATRIX_H_SEEN
+#define SP_FECONVOLVEMATRIX_H_SEEN
+
+#include <vector>
+#include "sp-filter-primitive.h"
+#include "number-opt-number.h"
+#include "display/nr-filter-convolve-matrix.h"
+
+#define SP_FECONVOLVEMATRIX(obj) (dynamic_cast<SPFeConvolveMatrix*>((SPObject*)obj))
+#define SP_IS_FECONVOLVEMATRIX(obj) (dynamic_cast<const SPFeConvolveMatrix*>((SPObject*)obj) != NULL)
+
+class SPFeConvolveMatrix : public SPFilterPrimitive {
+public:
+ SPFeConvolveMatrix();
+ ~SPFeConvolveMatrix() override;
+
+ NumberOptNumber order;
+ std::vector<gdouble> kernelMatrix;
+ double divisor, bias;
+ int targetX, targetY;
+ Inkscape::Filters::FilterConvolveMatrixEdgeMode edgeMode;
+ NumberOptNumber kernelUnitLength;
+ bool preserveAlpha;
+
+ bool targetXIsSet;
+ bool targetYIsSet;
+ bool divisorIsSet;
+ bool kernelMatrixIsSet;
+
+protected:
+ void build(SPDocument* doc, Inkscape::XML::Node* repr) override;
+ void release() override;
+
+ void set(SPAttributeEnum key, const gchar* value) override;
+
+ void update(SPCtx* ctx, unsigned int flags) override;
+
+ Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags) override;
+
+ void build_renderer(Inkscape::Filters::Filter* filter) override;
+};
+
+#endif /* !SP_FECONVOLVEMATRIX_H_SEEN */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/diffuselighting.cpp b/src/object/filters/diffuselighting.cpp
new file mode 100644
index 0000000..a9ee1cf
--- /dev/null
+++ b/src/object/filters/diffuselighting.cpp
@@ -0,0 +1,326 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** \file
+ * SVG <feDiffuseLighting> implementation.
+ *
+ */
+/*
+ * Authors:
+ * hugo Rodrigues <haa.rodrigues@gmail.com>
+ * Jean-Rene Reinhard <jr@komite.net>
+ * Abhishek Sharma
+ *
+ * Copyright (C) 2006 Hugo Rodrigues
+ * 2007 authors
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+// Same directory
+#include "diffuselighting.h"
+#include "distantlight.h"
+#include "pointlight.h"
+#include "spotlight.h"
+
+#include "strneq.h"
+#include "attributes.h"
+
+#include "display/nr-filter.h"
+#include "display/nr-filter-diffuselighting.h"
+
+#include "svg/svg.h"
+#include "svg/svg-color.h"
+#include "svg/svg-icc-color.h"
+
+#include "xml/repr.h"
+
+/* FeDiffuseLighting base class */
+static void sp_feDiffuseLighting_children_modified(SPFeDiffuseLighting *sp_diffuselighting);
+
+SPFeDiffuseLighting::SPFeDiffuseLighting() : SPFilterPrimitive() {
+ this->surfaceScale = 1;
+ this->diffuseConstant = 1;
+ this->lighting_color = 0xffffffff;
+ this->icc = nullptr;
+
+ //TODO kernelUnit
+ this->renderer = nullptr;
+
+ this->surfaceScale_set = FALSE;
+ this->diffuseConstant_set = FALSE;
+ this->lighting_color_set = FALSE;
+}
+
+SPFeDiffuseLighting::~SPFeDiffuseLighting() = default;
+
+/**
+ * Reads the Inkscape::XML::Node, and initializes SPFeDiffuseLighting variables. For this to get called,
+ * our name must be associated with a repr via "sp_object_type_register". Best done through
+ * sp-object-repr.cpp's repr_name_entries array.
+ */
+void SPFeDiffuseLighting::build(SPDocument *document, Inkscape::XML::Node *repr) {
+ SPFilterPrimitive::build(document, repr);
+
+ /*LOAD ATTRIBUTES FROM REPR HERE*/
+ this->readAttr( "surfaceScale" );
+ this->readAttr( "diffuseConstant" );
+ this->readAttr( "kernelUnitLength" );
+ this->readAttr( "lighting-color" );
+}
+
+/**
+ * Drops any allocated memory.
+ */
+void SPFeDiffuseLighting::release() {
+ SPFilterPrimitive::release();
+}
+
+/**
+ * Sets a specific value in the SPFeDiffuseLighting.
+ */
+void SPFeDiffuseLighting::set(SPAttributeEnum key, gchar const *value) {
+ gchar const *cend_ptr = nullptr;
+ gchar *end_ptr = nullptr;
+
+ switch(key) {
+ /*DEAL WITH SETTING ATTRIBUTES HERE*/
+ //TODO test forbidden values
+ case SP_ATTR_SURFACESCALE:
+ end_ptr = nullptr;
+
+ if (value) {
+ this->surfaceScale = g_ascii_strtod(value, &end_ptr);
+
+ if (end_ptr) {
+ this->surfaceScale_set = TRUE;
+ }
+ }
+
+ if (!value || !end_ptr) {
+ this->surfaceScale = 1;
+ this->surfaceScale_set = FALSE;
+ }
+
+ if (this->renderer) {
+ this->renderer->surfaceScale = this->surfaceScale;
+ }
+
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ break;
+ case SP_ATTR_DIFFUSECONSTANT:
+ end_ptr = nullptr;
+
+ if (value) {
+ this->diffuseConstant = g_ascii_strtod(value, &end_ptr);
+
+ if (end_ptr && this->diffuseConstant >= 0) {
+ this->diffuseConstant_set = TRUE;
+ } else {
+ end_ptr = nullptr;
+ g_warning("this: diffuseConstant should be a positive number ... defaulting to 1");
+ }
+ }
+
+ if (!value || !end_ptr) {
+ this->diffuseConstant = 1;
+ this->diffuseConstant_set = FALSE;
+ }
+
+ if (this->renderer) {
+ this->renderer->diffuseConstant = this->diffuseConstant;
+ }
+
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ break;
+ case SP_ATTR_KERNELUNITLENGTH:
+ //TODO kernelUnit
+ //this->kernelUnitLength.set(value);
+ /*TODOif (feDiffuseLighting->renderer) {
+ feDiffuseLighting->renderer->surfaceScale = feDiffuseLighting->renderer;
+ }
+ */
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ break;
+ case SP_PROP_LIGHTING_COLOR:
+ cend_ptr = nullptr;
+ this->lighting_color = sp_svg_read_color(value, &cend_ptr, 0xffffffff);
+
+ //if a value was read
+ if (cend_ptr) {
+ while (g_ascii_isspace(*cend_ptr)) {
+ ++cend_ptr;
+ }
+
+ if (strneq(cend_ptr, "icc-color(", 10)) {
+ if (!this->icc) {
+ this->icc = new SVGICCColor();
+ }
+
+ if ( ! sp_svg_read_icc_color( cend_ptr, this->icc ) ) {
+ delete this->icc;
+ this->icc = nullptr;
+ }
+ }
+
+ this->lighting_color_set = TRUE;
+ } else {
+ //lighting_color already contains the default value
+ this->lighting_color_set = FALSE;
+ }
+
+ if (this->renderer) {
+ this->renderer->lighting_color = this->lighting_color;
+ }
+
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ break;
+ default:
+ SPFilterPrimitive::set(key, value);
+ break;
+ }
+}
+
+/**
+ * Receives update notifications.
+ */
+void SPFeDiffuseLighting::update(SPCtx *ctx, guint flags) {
+ if (flags & (SP_OBJECT_MODIFIED_FLAG)) {
+ this->readAttr( "surfaceScale" );
+ this->readAttr( "diffuseConstant" );
+ this->readAttr( "kernelUnit" );
+ this->readAttr( "lighting-color" );
+ }
+
+ SPFilterPrimitive::update(ctx, flags);
+}
+
+/**
+ * Writes its settings to an incoming repr object, if any.
+ */
+Inkscape::XML::Node* SPFeDiffuseLighting::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) {
+ /* TODO: Don't just clone, but create a new repr node and write all
+ * relevant values _and children_ into it */
+ if (!repr) {
+ repr = this->getRepr()->duplicate(doc);
+ //repr = doc->createElement("svg:feDiffuseLighting");
+ }
+
+ if (this->surfaceScale_set) {
+ sp_repr_set_css_double(repr, "surfaceScale", this->surfaceScale);
+ } else {
+ repr->removeAttribute("surfaceScale");
+ }
+
+ if (this->diffuseConstant_set) {
+ sp_repr_set_css_double(repr, "diffuseConstant", this->diffuseConstant);
+ } else {
+ repr->removeAttribute("diffuseConstant");
+ }
+
+ /*TODO kernelUnits */
+ if (this->lighting_color_set) {
+ gchar c[64];
+ sp_svg_write_color(c, sizeof(c), this->lighting_color);
+ repr->setAttribute("lighting-color", c);
+ } else {
+ repr->removeAttribute("lighting-color");
+ }
+
+ SPFilterPrimitive::write(doc, repr, flags);
+
+ return repr;
+}
+
+/**
+ * Callback for child_added event.
+ */
+void SPFeDiffuseLighting::child_added(Inkscape::XML::Node *child, Inkscape::XML::Node *ref) {
+ SPFilterPrimitive::child_added(child, ref);
+
+ sp_feDiffuseLighting_children_modified(this);
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+}
+
+/**
+ * Callback for remove_child event.
+ */
+void SPFeDiffuseLighting::remove_child(Inkscape::XML::Node *child) {
+ SPFilterPrimitive::remove_child(child);
+
+ sp_feDiffuseLighting_children_modified(this);
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+}
+
+void SPFeDiffuseLighting::order_changed(Inkscape::XML::Node *child, Inkscape::XML::Node *old_ref, Inkscape::XML::Node *new_ref) {
+ SPFilterPrimitive::order_changed(child, old_ref, new_ref);
+
+ sp_feDiffuseLighting_children_modified(this);
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+}
+
+static void sp_feDiffuseLighting_children_modified(SPFeDiffuseLighting *sp_diffuselighting)
+{
+ if (sp_diffuselighting->renderer) {
+ sp_diffuselighting->renderer->light_type = Inkscape::Filters::NO_LIGHT;
+ if (SP_IS_FEDISTANTLIGHT(sp_diffuselighting->firstChild())) {
+ sp_diffuselighting->renderer->light_type = Inkscape::Filters::DISTANT_LIGHT;
+ sp_diffuselighting->renderer->light.distant = SP_FEDISTANTLIGHT(sp_diffuselighting->firstChild());
+ }
+ if (SP_IS_FEPOINTLIGHT(sp_diffuselighting->firstChild())) {
+ sp_diffuselighting->renderer->light_type = Inkscape::Filters::POINT_LIGHT;
+ sp_diffuselighting->renderer->light.point = SP_FEPOINTLIGHT(sp_diffuselighting->firstChild());
+ }
+ if (SP_IS_FESPOTLIGHT(sp_diffuselighting->firstChild())) {
+ sp_diffuselighting->renderer->light_type = Inkscape::Filters::SPOT_LIGHT;
+ sp_diffuselighting->renderer->light.spot = SP_FESPOTLIGHT(sp_diffuselighting->firstChild());
+ }
+ }
+}
+
+void SPFeDiffuseLighting::build_renderer(Inkscape::Filters::Filter* filter) {
+ g_assert(filter != nullptr);
+
+ int primitive_n = filter->add_primitive(Inkscape::Filters::NR_FILTER_DIFFUSELIGHTING);
+ Inkscape::Filters::FilterPrimitive *nr_primitive = filter->get_primitive(primitive_n);
+ Inkscape::Filters::FilterDiffuseLighting *nr_diffuselighting = dynamic_cast<Inkscape::Filters::FilterDiffuseLighting*>(nr_primitive);
+ g_assert(nr_diffuselighting != nullptr);
+
+ this->renderer = nr_diffuselighting;
+ this->renderer_common(nr_primitive);
+
+ nr_diffuselighting->diffuseConstant = this->diffuseConstant;
+ nr_diffuselighting->surfaceScale = this->surfaceScale;
+ nr_diffuselighting->lighting_color = this->lighting_color;
+ nr_diffuselighting->set_icc(this->icc);
+
+ //We assume there is at most one child
+ nr_diffuselighting->light_type = Inkscape::Filters::NO_LIGHT;
+
+ if (SP_IS_FEDISTANTLIGHT(this->firstChild())) {
+ nr_diffuselighting->light_type = Inkscape::Filters::DISTANT_LIGHT;
+ nr_diffuselighting->light.distant = SP_FEDISTANTLIGHT(this->firstChild());
+ }
+
+ if (SP_IS_FEPOINTLIGHT(this->firstChild())) {
+ nr_diffuselighting->light_type = Inkscape::Filters::POINT_LIGHT;
+ nr_diffuselighting->light.point = SP_FEPOINTLIGHT(this->firstChild());
+ }
+
+ if (SP_IS_FESPOTLIGHT(this->firstChild())) {
+ nr_diffuselighting->light_type = Inkscape::Filters::SPOT_LIGHT;
+ nr_diffuselighting->light.spot = SP_FESPOTLIGHT(this->firstChild());
+ }
+
+ //nr_offset->set_dx(sp_offset->dx);
+ //nr_offset->set_dy(sp_offset->dy);
+}
+
+/*
+ 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:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/diffuselighting.h b/src/object/filters/diffuselighting.h
new file mode 100644
index 0000000..7905f64
--- /dev/null
+++ b/src/object/filters/diffuselighting.h
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** @file
+ * @brief SVG diffuse lighting filter effect
+ *//*
+ * Authors:
+ * Hugo Rodrigues <haa.rodrigues@gmail.com>
+ * Jean-Rene Reinhard <jr@komite.net>
+ *
+ * Copyright (C) 2006-2007 Authors
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#ifndef SP_FEDIFFUSELIGHTING_H_SEEN
+#define SP_FEDIFFUSELIGHTING_H_SEEN
+
+#include "sp-filter-primitive.h"
+#include "number-opt-number.h"
+
+#define SP_FEDIFFUSELIGHTING(obj) (dynamic_cast<SPFeDiffuseLighting*>((SPObject*)obj))
+#define SP_IS_FEDIFFUSELIGHTING(obj) (dynamic_cast<const SPFeDiffuseLighting*>((SPObject*)obj) != NULL)
+
+struct SVGICCColor;
+
+namespace Inkscape {
+namespace Filters {
+class FilterDiffuseLighting;
+} }
+
+class SPFeDiffuseLighting : public SPFilterPrimitive {
+public:
+ SPFeDiffuseLighting();
+ ~SPFeDiffuseLighting() override;
+
+ gfloat surfaceScale;
+ guint surfaceScale_set : 1;
+ gfloat diffuseConstant;
+ guint diffuseConstant_set : 1;
+ NumberOptNumber kernelUnitLength;
+ guint32 lighting_color;
+ guint lighting_color_set : 1;
+ Inkscape::Filters::FilterDiffuseLighting *renderer;
+ SVGICCColor *icc;
+
+protected:
+ void build(SPDocument* doc, Inkscape::XML::Node* repr) override;
+ void release() override;
+
+ void child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref) override;
+ void remove_child(Inkscape::XML::Node* child) override;
+
+ void order_changed(Inkscape::XML::Node* child, Inkscape::XML::Node* old_repr, Inkscape::XML::Node* new_repr) override;
+
+ void set(SPAttributeEnum key, const gchar* value) override;
+
+ void update(SPCtx* ctx, unsigned int flags) override;
+
+ Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags) override;
+
+ void build_renderer(Inkscape::Filters::Filter* filter) override;
+};
+
+#endif /* !SP_FEDIFFUSELIGHTING_H_SEEN */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/displacementmap.cpp b/src/object/filters/displacementmap.cpp
new file mode 100644
index 0000000..80b9638
--- /dev/null
+++ b/src/object/filters/displacementmap.cpp
@@ -0,0 +1,256 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** \file
+ * SVG <feDisplacementMap> implementation.
+ *
+ */
+/*
+ * Authors:
+ * hugo Rodrigues <haa.rodrigues@gmail.com>
+ * Abhishek Sharma
+ *
+ * Copyright (C) 2006 Hugo Rodrigues
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include "displacementmap.h"
+
+#include "attributes.h"
+#include "helper-fns.h"
+
+#include "display/nr-filter-displacement-map.h"
+#include "display/nr-filter.h"
+
+#include "object/sp-filter.h"
+
+#include "svg/svg.h"
+
+#include "xml/repr.h"
+
+SPFeDisplacementMap::SPFeDisplacementMap() : SPFilterPrimitive() {
+ this->scale=0;
+ this->xChannelSelector = DISPLACEMENTMAP_CHANNEL_ALPHA;
+ this->yChannelSelector = DISPLACEMENTMAP_CHANNEL_ALPHA;
+ this->in2 = Inkscape::Filters::NR_FILTER_SLOT_NOT_SET;
+}
+
+SPFeDisplacementMap::~SPFeDisplacementMap() = default;
+
+/**
+ * Reads the Inkscape::XML::Node, and initializes SPFeDisplacementMap variables. For this to get called,
+ * our name must be associated with a repr via "sp_object_type_register". Best done through
+ * sp-object-repr.cpp's repr_name_entries array.
+ */
+void SPFeDisplacementMap::build(SPDocument *document, Inkscape::XML::Node *repr) {
+ SPFilterPrimitive::build(document, repr);
+
+ /*LOAD ATTRIBUTES FROM REPR HERE*/
+ this->readAttr( "scale" );
+ this->readAttr( "in2" );
+ this->readAttr( "xChannelSelector" );
+ this->readAttr( "yChannelSelector" );
+
+ /* Unlike normal in, in2 is required attribute. Make sure, we can call
+ * it by some name. */
+ if (this->in2 == Inkscape::Filters::NR_FILTER_SLOT_NOT_SET ||
+ this->in2 == Inkscape::Filters::NR_FILTER_UNNAMED_SLOT)
+ {
+ SPFilter *parent = SP_FILTER(this->parent);
+ this->in2 = this->name_previous_out();
+ repr->setAttribute("in2", parent->name_for_image(this->in2));
+ }
+}
+
+/**
+ * Drops any allocated memory.
+ */
+void SPFeDisplacementMap::release() {
+ SPFilterPrimitive::release();
+}
+
+static FilterDisplacementMapChannelSelector sp_feDisplacementMap_readChannelSelector(gchar const *value)
+{
+ if (!value) return DISPLACEMENTMAP_CHANNEL_ALPHA;
+
+ switch (value[0]) {
+ case 'R':
+ return DISPLACEMENTMAP_CHANNEL_RED;
+ break;
+ case 'G':
+ return DISPLACEMENTMAP_CHANNEL_GREEN;
+ break;
+ case 'B':
+ return DISPLACEMENTMAP_CHANNEL_BLUE;
+ break;
+ case 'A':
+ return DISPLACEMENTMAP_CHANNEL_ALPHA;
+ break;
+ default:
+ // error
+ g_warning("Invalid attribute for Channel Selector. Valid modes are 'R', 'G', 'B' or 'A'");
+ break;
+ }
+
+ return DISPLACEMENTMAP_CHANNEL_ALPHA; //default is Alpha Channel
+}
+
+/**
+ * Sets a specific value in the SPFeDisplacementMap.
+ */
+void SPFeDisplacementMap::set(SPAttributeEnum key, gchar const *value) {
+ int input;
+ double read_num;
+ FilterDisplacementMapChannelSelector read_selector;
+
+ switch(key) {
+ /*DEAL WITH SETTING ATTRIBUTES HERE*/
+ case SP_ATTR_XCHANNELSELECTOR:
+ read_selector = sp_feDisplacementMap_readChannelSelector(value);
+
+ if (read_selector != this->xChannelSelector){
+ this->xChannelSelector = read_selector;
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ case SP_ATTR_YCHANNELSELECTOR:
+ read_selector = sp_feDisplacementMap_readChannelSelector(value);
+
+ if (read_selector != this->yChannelSelector){
+ this->yChannelSelector = read_selector;
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ case SP_ATTR_SCALE:
+ read_num = value ? helperfns_read_number(value) : 0;
+
+ if (read_num != this->scale) {
+ this->scale = read_num;
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ case SP_ATTR_IN2:
+ input = this->read_in(value);
+
+ if (input != this->in2) {
+ this->in2 = input;
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ default:
+ SPFilterPrimitive::set(key, value);
+ break;
+ }
+}
+
+/**
+ * Receives update notifications.
+ */
+void SPFeDisplacementMap::update(SPCtx *ctx, guint flags) {
+ if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG |
+ SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
+
+ /* do something to trigger redisplay, updates? */
+
+ }
+
+ /* Unlike normal in, in2 is required attribute. Make sure, we can call
+ * it by some name. */
+ if (this->in2 == Inkscape::Filters::NR_FILTER_SLOT_NOT_SET ||
+ this->in2 == Inkscape::Filters::NR_FILTER_UNNAMED_SLOT)
+ {
+ SPFilter *parent = SP_FILTER(this->parent);
+ this->in2 = this->name_previous_out();
+
+ //XML Tree being used directly here while it shouldn't be.
+ this->setAttribute("in2", parent->name_for_image(this->in2));
+ }
+
+ SPFilterPrimitive::update(ctx, flags);
+}
+
+static char const * get_channelselector_name(FilterDisplacementMapChannelSelector selector) {
+ switch(selector) {
+ case DISPLACEMENTMAP_CHANNEL_RED:
+ return "R";
+ case DISPLACEMENTMAP_CHANNEL_GREEN:
+ return "G";
+ case DISPLACEMENTMAP_CHANNEL_BLUE:
+ return "B";
+ case DISPLACEMENTMAP_CHANNEL_ALPHA:
+ return "A";
+ default:
+ return nullptr;
+ }
+}
+
+/**
+ * Writes its settings to an incoming repr object, if any.
+ */
+Inkscape::XML::Node* SPFeDisplacementMap::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) {
+ SPFilter *parent = SP_FILTER(this->parent);
+
+ if (!repr) {
+ repr = doc->createElement("svg:feDisplacementMap");
+ }
+
+ gchar const *in2_name = parent->name_for_image(this->in2);
+
+ if( !in2_name ) {
+
+ // This code is very similar to name_previous_out()
+ SPObject *i = parent->firstChild();
+
+ // Find previous filter primitive
+ while (i && i->getNext() != this) {
+ i = i->getNext();
+ }
+
+ if( i ) {
+ SPFilterPrimitive *i_prim = SP_FILTER_PRIMITIVE(i);
+ in2_name = parent->name_for_image(i_prim->image_out);
+ }
+ }
+
+ if (in2_name) {
+ repr->setAttribute("in2", in2_name);
+ } else {
+ g_warning("Unable to set in2 for feDisplacementMap");
+ }
+
+ sp_repr_set_svg_double(repr, "scale", this->scale);
+ repr->setAttribute("xChannelSelector",
+ get_channelselector_name(this->xChannelSelector));
+ repr->setAttribute("yChannelSelector",
+ get_channelselector_name(this->yChannelSelector));
+
+ SPFilterPrimitive::write(doc, repr, flags);
+
+ return repr;
+}
+
+void SPFeDisplacementMap::build_renderer(Inkscape::Filters::Filter* filter) {
+ g_assert(filter != nullptr);
+
+ int primitive_n = filter->add_primitive(Inkscape::Filters::NR_FILTER_DISPLACEMENTMAP);
+ Inkscape::Filters::FilterPrimitive *nr_primitive = filter->get_primitive(primitive_n);
+ Inkscape::Filters::FilterDisplacementMap *nr_displacement_map = dynamic_cast<Inkscape::Filters::FilterDisplacementMap*>(nr_primitive);
+ g_assert(nr_displacement_map != nullptr);
+
+ this->renderer_common(nr_primitive);
+
+ nr_displacement_map->set_input(1, this->in2);
+ nr_displacement_map->set_scale(this->scale);
+ nr_displacement_map->set_channel_selector(0, this->xChannelSelector);
+ nr_displacement_map->set_channel_selector(1, this->yChannelSelector);
+}
+
+/*
+ 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:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/displacementmap.h b/src/object/filters/displacementmap.h
new file mode 100644
index 0000000..e9e0731
--- /dev/null
+++ b/src/object/filters/displacementmap.h
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** \file
+ * SVG displacement map filter effect
+ *//*
+ * Authors:
+ * Hugo Rodrigues <haa.rodrigues@gmail.com>
+ *
+ * Copyright (C) 2006 Hugo Rodrigues
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#ifndef SP_FEDISPLACEMENTMAP_H_SEEN
+#define SP_FEDISPLACEMENTMAP_H_SEEN
+
+#include "sp-filter-primitive.h"
+
+#define SP_FEDISPLACEMENTMAP(obj) (dynamic_cast<SPFeDisplacementMap*>((SPObject*)obj))
+#define SP_IS_FEDISPLACEMENTMAP(obj) (dynamic_cast<const SPFeDisplacementMap*>((SPObject*)obj) != NULL)
+
+enum FilterDisplacementMapChannelSelector {
+ DISPLACEMENTMAP_CHANNEL_RED,
+ DISPLACEMENTMAP_CHANNEL_GREEN,
+ DISPLACEMENTMAP_CHANNEL_BLUE,
+ DISPLACEMENTMAP_CHANNEL_ALPHA,
+ DISPLACEMENTMAP_CHANNEL_ENDTYPE
+};
+
+class SPFeDisplacementMap : public SPFilterPrimitive {
+public:
+ SPFeDisplacementMap();
+ ~SPFeDisplacementMap() override;
+
+ int in2;
+ double scale;
+ FilterDisplacementMapChannelSelector xChannelSelector;
+ FilterDisplacementMapChannelSelector yChannelSelector;
+
+protected:
+ void build(SPDocument* doc, Inkscape::XML::Node* repr) override;
+ void release() override;
+
+ void set(SPAttributeEnum key, const gchar* value) override;
+
+ void update(SPCtx* ctx, unsigned int flags) override;
+
+ Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags) override;
+
+ void build_renderer(Inkscape::Filters::Filter* filter) override;
+};
+
+#endif /* !SP_FEDISPLACEMENTMAP_H_SEEN */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/distantlight.cpp b/src/object/filters/distantlight.cpp
new file mode 100644
index 0000000..7862906
--- /dev/null
+++ b/src/object/filters/distantlight.cpp
@@ -0,0 +1,164 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** \file
+ * SVG <fedistantlight> implementation.
+ */
+/*
+ * Authors:
+ * Hugo Rodrigues <haa.rodrigues@gmail.com>
+ * Niko Kiirala <niko@kiirala.com>
+ * Jean-Rene Reinhard <jr@komite.net>
+ * Abhishek Sharma
+ *
+ * Copyright (C) 2006,2007 Authors
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include <glib.h>
+
+// In same directory
+#include "distantlight.h"
+#include "diffuselighting.h"
+#include "specularlighting.h"
+
+#include "attributes.h"
+#include "document.h"
+
+#include "xml/repr.h"
+
+SPFeDistantLight::SPFeDistantLight()
+ : SPObject(), azimuth(0), azimuth_set(FALSE), elevation(0), elevation_set(FALSE) {
+}
+
+SPFeDistantLight::~SPFeDistantLight() = default;
+
+/**
+ * Reads the Inkscape::XML::Node, and initializes SPDistantLight variables. For this to get called,
+ * our name must be associated with a repr via "sp_object_type_register". Best done through
+ * sp-object-repr.cpp's repr_name_entries array.
+ */
+void SPFeDistantLight::build(SPDocument *document, Inkscape::XML::Node *repr) {
+ SPObject::build(document, repr);
+
+ //Read values of key attributes from XML nodes into object.
+ this->readAttr( "azimuth" );
+ this->readAttr( "elevation" );
+
+//is this necessary?
+ document->addResource("fedistantlight", this);
+}
+
+/**
+ * Drops any allocated memory.
+ */
+void SPFeDistantLight::release() {
+ if ( this->document ) {
+ // Unregister ourselves
+ this->document->removeResource("fedistantlight", this);
+ }
+
+//TODO: release resources here
+}
+
+/**
+ * Sets a specific value in the SPFeDistantLight.
+ */
+void SPFeDistantLight::set(SPAttributeEnum key, gchar const *value) {
+ gchar *end_ptr;
+
+ switch (key) {
+ case SP_ATTR_AZIMUTH:
+ end_ptr =nullptr;
+
+ if (value) {
+ this->azimuth = g_ascii_strtod(value, &end_ptr);
+
+ if (end_ptr) {
+ this->azimuth_set = TRUE;
+ }
+ }
+
+ if (!value || !end_ptr) {
+ this->azimuth_set = FALSE;
+ this->azimuth = 0;
+ }
+
+ if (this->parent &&
+ (SP_IS_FEDIFFUSELIGHTING(this->parent) ||
+ SP_IS_FESPECULARLIGHTING(this->parent))) {
+ this->parent->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ case SP_ATTR_ELEVATION:
+ end_ptr =nullptr;
+
+ if (value) {
+ this->elevation = g_ascii_strtod(value, &end_ptr);
+
+ if (end_ptr) {
+ this->elevation_set = TRUE;
+ }
+ }
+
+ if (!value || !end_ptr) {
+ this->elevation_set = FALSE;
+ this->elevation = 0;
+ }
+
+ if (this->parent &&
+ (SP_IS_FEDIFFUSELIGHTING(this->parent) ||
+ SP_IS_FESPECULARLIGHTING(this->parent))) {
+ this->parent->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ default:
+ // See if any parents need this value.
+ SPObject::set(key, value);
+ break;
+ }
+}
+
+/**
+ * * Receives update notifications.
+ * */
+void SPFeDistantLight::update(SPCtx *ctx, guint flags) {
+ if (flags & SP_OBJECT_MODIFIED_FLAG) {
+ /* do something to trigger redisplay, updates? */
+ this->readAttr( "azimuth" );
+ this->readAttr( "elevation" );
+ }
+
+ SPObject::update(ctx, flags);
+}
+
+/**
+ * Writes its settings to an incoming repr object, if any.
+ */
+Inkscape::XML::Node* SPFeDistantLight::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) {
+ if (!repr) {
+ repr = this->getRepr()->duplicate(doc);
+ }
+
+ if (this->azimuth_set) {
+ sp_repr_set_css_double(repr, "azimuth", this->azimuth);
+ }
+
+ if (this->elevation_set) {
+ sp_repr_set_css_double(repr, "elevation", this->elevation);
+ }
+
+ SPObject::write(doc, repr, flags);
+
+ return repr;
+}
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/distantlight.h b/src/object/filters/distantlight.h
new file mode 100644
index 0000000..dfc193d
--- /dev/null
+++ b/src/object/filters/distantlight.h
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#ifndef SP_FEDISTANTLIGHT_H_SEEN
+#define SP_FEDISTANTLIGHT_H_SEEN
+
+/** \file
+ * SVG <filter> implementation, see sp-filter.cpp.
+ */
+/*
+ * Authors:
+ * Hugo Rodrigues <haa.rodrigues@gmail.com>
+ * Niko Kiirala <niko@kiirala.com>
+ * Jean-Rene Reinhard <jr@komite.net>
+ *
+ * Copyright (C) 2006,2007 Authors
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include "../sp-object.h"
+
+#define SP_FEDISTANTLIGHT(obj) (dynamic_cast<SPFeDistantLight*>((SPObject*)obj))
+#define SP_IS_FEDISTANTLIGHT(obj) (dynamic_cast<const SPFeDistantLight*>((SPObject*)obj) != NULL)
+
+/* Distant light class */
+class SPFeDistantLight : public SPObject {
+public:
+ SPFeDistantLight();
+ ~SPFeDistantLight() override;
+
+ /** azimuth attribute */
+ float azimuth;
+ unsigned int azimuth_set : 1;
+ /** elevation attribute */
+ float elevation;
+ unsigned int elevation_set : 1;
+
+protected:
+ void build(SPDocument* doc, Inkscape::XML::Node* repr) override;
+ void release() override;
+
+ void set(SPAttributeEnum key, char const* value) override;
+
+ void update(SPCtx* ctx, unsigned int flags) override;
+
+ Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, unsigned int flags) override;
+};
+
+#endif /* !SP_FEDISTANTLIGHT_H_SEEN */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/flood.cpp b/src/object/filters/flood.cpp
new file mode 100644
index 0000000..ed3b94a
--- /dev/null
+++ b/src/object/filters/flood.cpp
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** \file
+ * SVG <feFlood> implementation.
+ *
+ */
+/*
+ * Authors:
+ * hugo Rodrigues <haa.rodrigues@gmail.com>
+ * Abhishek Sharma
+ *
+ * Copyright (C) 2006 Hugo Rodrigues
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include "flood.h"
+
+#include "strneq.h"
+#include "attributes.h"
+
+#include "svg/svg.h"
+#include "svg/svg-color.h"
+
+#include "display/nr-filter.h"
+#include "display/nr-filter-flood.h"
+
+#include "xml/repr.h"
+
+SPFeFlood::SPFeFlood() : SPFilterPrimitive() {
+ this->color = 0;
+
+ this->opacity = 1;
+ this->icc = nullptr;
+}
+
+SPFeFlood::~SPFeFlood() = default;
+
+/**
+ * Reads the Inkscape::XML::Node, and initializes SPFeFlood variables. For this to get called,
+ * our name must be associated with a repr via "sp_object_type_register". Best done through
+ * sp-object-repr.cpp's repr_name_entries array.
+ */
+void SPFeFlood::build(SPDocument *document, Inkscape::XML::Node *repr) {
+ SPFilterPrimitive::build(document, repr);
+
+ /*LOAD ATTRIBUTES FROM REPR HERE*/
+ this->readAttr( "flood-opacity" );
+ this->readAttr( "flood-color" );
+}
+
+/**
+ * Drops any allocated memory.
+ */
+void SPFeFlood::release() {
+ SPFilterPrimitive::release();
+}
+
+/**
+ * Sets a specific value in the SPFeFlood.
+ */
+void SPFeFlood::set(SPAttributeEnum key, gchar const *value) {
+ gchar const *cend_ptr = nullptr;
+ gchar *end_ptr = nullptr;
+ guint32 read_color;
+ double read_num;
+ bool dirty = false;
+
+ switch(key) {
+ /*DEAL WITH SETTING ATTRIBUTES HERE*/
+ case SP_PROP_FLOOD_COLOR:
+ cend_ptr = nullptr;
+ read_color = sp_svg_read_color(value, &cend_ptr, 0xffffffff);
+
+ if (cend_ptr && read_color != this->color){
+ this->color = read_color;
+ dirty=true;
+ }
+
+ if (cend_ptr){
+ while (g_ascii_isspace(*cend_ptr)) {
+ ++cend_ptr;
+ }
+
+ if (strneq(cend_ptr, "icc-color(", 10)) {
+ if (!this->icc) {
+ this->icc = new SVGICCColor();
+ }
+
+ if ( ! sp_svg_read_icc_color( cend_ptr, this->icc ) ) {
+ delete this->icc;
+ this->icc = nullptr;
+ }
+
+ dirty = true;
+ }
+ }
+
+ if (dirty) {
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ case SP_PROP_FLOOD_OPACITY:
+ if (value) {
+ read_num = g_ascii_strtod(value, &end_ptr);
+
+ if (end_ptr != nullptr) {
+ if (*end_ptr) {
+ g_warning("Unable to convert \"%s\" to number", value);
+ read_num = 1;
+ }
+ }
+ } else {
+ read_num = 1;
+ }
+
+ if (read_num != this->opacity) {
+ this->opacity = read_num;
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ default:
+ SPFilterPrimitive::set(key, value);
+ break;
+ }
+}
+
+/**
+ * Receives update notifications.
+ */
+void SPFeFlood::update(SPCtx *ctx, guint flags) {
+ if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG |
+ SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
+
+ /* do something to trigger redisplay, updates? */
+
+ }
+
+ SPFilterPrimitive::update(ctx, flags);
+}
+
+/**
+ * Writes its settings to an incoming repr object, if any.
+ */
+Inkscape::XML::Node* SPFeFlood::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) {
+ /* TODO: Don't just clone, but create a new repr node and write all
+ * relevant values into it */
+ if (!repr) {
+ repr = this->getRepr()->duplicate(doc);
+ }
+
+ SPFilterPrimitive::write(doc, repr, flags);
+
+ return repr;
+}
+
+void SPFeFlood::build_renderer(Inkscape::Filters::Filter* filter) {
+ g_assert(filter != nullptr);
+
+ int primitive_n = filter->add_primitive(Inkscape::Filters::NR_FILTER_FLOOD);
+ Inkscape::Filters::FilterPrimitive *nr_primitive = filter->get_primitive(primitive_n);
+ Inkscape::Filters::FilterFlood *nr_flood = dynamic_cast<Inkscape::Filters::FilterFlood*>(nr_primitive);
+ g_assert(nr_flood != nullptr);
+
+ this->renderer_common(nr_primitive);
+
+ nr_flood->set_opacity(this->opacity);
+ nr_flood->set_color(this->color);
+ nr_flood->set_icc(this->icc);
+}
+
+/*
+ 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:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/flood.h b/src/object/filters/flood.h
new file mode 100644
index 0000000..f36e6db
--- /dev/null
+++ b/src/object/filters/flood.h
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** @file
+ * @brief SVG flood filter effect
+ *//*
+ * Authors:
+ * Hugo Rodrigues <haa.rodrigues@gmail.com>
+ *
+ * Copyright (C) 2006 Hugo Rodrigues
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#ifndef SP_FEFLOOD_H_SEEN
+#define SP_FEFLOOD_H_SEEN
+
+#include "sp-filter-primitive.h"
+#include "svg/svg-icc-color.h"
+
+#define SP_FEFLOOD(obj) (dynamic_cast<SPFeFlood*>((SPObject*)obj))
+#define SP_IS_FEFLOOD(obj) (dynamic_cast<const SPFeFlood*>((SPObject*)obj) != NULL)
+
+class SPFeFlood : public SPFilterPrimitive {
+public:
+ SPFeFlood();
+ ~SPFeFlood() override;
+
+ guint32 color;
+ SVGICCColor *icc;
+ double opacity;
+
+protected:
+ void build(SPDocument* doc, Inkscape::XML::Node* repr) override;
+ void release() override;
+
+ void set(SPAttributeEnum key, const gchar* value) override;
+
+ void update(SPCtx* ctx, unsigned int flags) override;
+
+ Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags) override;
+
+ void build_renderer(Inkscape::Filters::Filter* filter) override;
+};
+
+#endif /* !SP_FEFLOOD_H_SEEN */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/gaussian-blur.cpp b/src/object/filters/gaussian-blur.cpp
new file mode 100644
index 0000000..2cbbaa7
--- /dev/null
+++ b/src/object/filters/gaussian-blur.cpp
@@ -0,0 +1,132 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** \file
+ * SVG <gaussianBlur> implementation.
+ *
+ */
+/*
+ * Authors:
+ * Hugo Rodrigues <haa.rodrigues@gmail.com>
+ * Niko Kiirala <niko@kiirala.com>
+ * Abhishek Sharma
+ *
+ * Copyright (C) 2006,2007 Authors
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include "gaussian-blur.h"
+
+#include "attributes.h"
+
+#include "display/nr-filter.h"
+#include "display/nr-filter-gaussian.h"
+
+#include "svg/svg.h"
+
+#include "xml/repr.h"
+
+SPGaussianBlur::SPGaussianBlur() : SPFilterPrimitive() {
+}
+
+SPGaussianBlur::~SPGaussianBlur() = default;
+
+/**
+ * Reads the Inkscape::XML::Node, and initializes SPGaussianBlur variables. For this to get called,
+ * our name must be associated with a repr via "sp_object_type_register". Best done through
+ * sp-object-repr.cpp's repr_name_entries array.
+ */
+void SPGaussianBlur::build(SPDocument *document, Inkscape::XML::Node *repr) {
+ SPFilterPrimitive::build(document, repr);
+
+ this->readAttr( "stdDeviation" );
+}
+
+/**
+ * Drops any allocated memory.
+ */
+void SPGaussianBlur::release() {
+ SPFilterPrimitive::release();
+}
+
+/**
+ * Sets a specific value in the SPGaussianBlur.
+ */
+void SPGaussianBlur::set(SPAttributeEnum key, gchar const *value) {
+ switch(key) {
+ case SP_ATTR_STDDEVIATION:
+ this->stdDeviation.set(value);
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ break;
+ default:
+ SPFilterPrimitive::set(key, value);
+ break;
+ }
+}
+
+/**
+ * Receives update notifications.
+ */
+void SPGaussianBlur::update(SPCtx *ctx, guint flags) {
+ if (flags & SP_OBJECT_MODIFIED_FLAG) {
+ this->readAttr( "stdDeviation" );
+ }
+
+ SPFilterPrimitive::update(ctx, flags);
+}
+
+/**
+ * Writes its settings to an incoming repr object, if any.
+ */
+Inkscape::XML::Node* SPGaussianBlur::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) {
+ /* TODO: Don't just clone, but create a new repr node and write all
+ * relevant values into it */
+ if (!repr) {
+ repr = this->getRepr()->duplicate(doc);
+ }
+
+ SPFilterPrimitive::write(doc, repr, flags);
+
+ return repr;
+}
+
+void sp_gaussianBlur_setDeviation(SPGaussianBlur *blur, float num)
+{
+ blur->stdDeviation.setNumber(num);
+}
+
+void sp_gaussianBlur_setDeviation(SPGaussianBlur *blur, float num, float optnum)
+{
+ blur->stdDeviation.setNumber(num);
+ blur->stdDeviation.setOptNumber(optnum);
+}
+
+void SPGaussianBlur::build_renderer(Inkscape::Filters::Filter* filter) {
+ int handle = filter->add_primitive(Inkscape::Filters::NR_FILTER_GAUSSIANBLUR);
+ Inkscape::Filters::FilterPrimitive *nr_primitive = filter->get_primitive(handle);
+ Inkscape::Filters::FilterGaussian *nr_blur = dynamic_cast<Inkscape::Filters::FilterGaussian*>(nr_primitive);
+
+ this->renderer_common(nr_primitive);
+
+ gfloat num = this->stdDeviation.getNumber();
+
+ if (num >= 0.0) {
+ gfloat optnum = this->stdDeviation.getOptNumber();
+
+ if(optnum >= 0.0) {
+ nr_blur->set_deviation((double) num, (double) optnum);
+ } else {
+ nr_blur->set_deviation((double) num);
+ }
+ }
+}
+
+/*
+ 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:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/gaussian-blur.h b/src/object/filters/gaussian-blur.h
new file mode 100644
index 0000000..a2ba281
--- /dev/null
+++ b/src/object/filters/gaussian-blur.h
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** @file
+ * @brief SVG Gaussian blur filter effect
+ *//*
+ * Authors:
+ * Hugo Rodrigues <haa.rodrigues@gmail.com>
+ *
+ * Copyright (C) 2006 Hugo Rodrigues
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#ifndef SP_GAUSSIANBLUR_H_SEEN
+#define SP_GAUSSIANBLUR_H_SEEN
+
+#include "sp-filter-primitive.h"
+#include "number-opt-number.h"
+
+#define SP_GAUSSIANBLUR(obj) (dynamic_cast<SPGaussianBlur*>((SPObject*)obj))
+#define SP_IS_GAUSSIANBLUR(obj) (dynamic_cast<const SPGaussianBlur*>((SPObject*)obj) != NULL)
+
+class SPGaussianBlur : public SPFilterPrimitive {
+public:
+ SPGaussianBlur();
+ ~SPGaussianBlur() override;
+
+ /** stdDeviation attribute */
+ NumberOptNumber stdDeviation;
+
+protected:
+ void build(SPDocument* doc, Inkscape::XML::Node* repr) override;
+ void release() override;
+
+ void set(SPAttributeEnum key, const gchar* value) override;
+
+ void update(SPCtx* ctx, unsigned int flags) override;
+
+ Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags) override;
+
+ void build_renderer(Inkscape::Filters::Filter* filter) override;
+};
+
+void sp_gaussianBlur_setDeviation(SPGaussianBlur *blur, float num);
+void sp_gaussianBlur_setDeviation(SPGaussianBlur *blur, float num, float optnum);
+
+#endif /* !SP_GAUSSIANBLUR_H_SEEN */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/image.cpp b/src/object/filters/image.cpp
new file mode 100644
index 0000000..ea88d81
--- /dev/null
+++ b/src/object/filters/image.cpp
@@ -0,0 +1,261 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** \file
+ * SVG <feImage> implementation.
+ *
+ */
+/*
+ * Authors:
+ * Felipe Corrêa da Silva Sanches <juca@members.fsf.org>
+ * hugo Rodrigues <haa.rodrigues@gmail.com>
+ * Abhishek Sharma
+ *
+ * Copyright (C) 2007 Felipe Sanches
+ * Copyright (C) 2006 Hugo Rodrigues
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include "image.h"
+
+#include <sigc++/bind.h>
+
+#include "attributes.h"
+#include "enums.h"
+
+#include "bad-uri-exception.h"
+
+#include "object/sp-image.h"
+#include "object/uri.h"
+#include "object/uri-references.h"
+
+#include "display/nr-filter-image.h"
+#include "display/nr-filter.h"
+
+#include "xml/repr.h"
+
+
+SPFeImage::SPFeImage() : SPFilterPrimitive() {
+ this->href = nullptr;
+ this->from_element = false;
+ this->SVGElemRef = nullptr;
+ this->SVGElem = nullptr;
+
+ this->aspect_align = SP_ASPECT_XMID_YMID; // Default
+ this->aspect_clip = SP_ASPECT_MEET; // Default
+}
+
+SPFeImage::~SPFeImage() = default;
+
+/**
+ * Reads the Inkscape::XML::Node, and initializes SPFeImage variables. For this to get called,
+ * our name must be associated with a repr via "sp_object_type_register". Best done through
+ * sp-object-repr.cpp's repr_name_entries array.
+ */
+void SPFeImage::build(SPDocument *document, Inkscape::XML::Node *repr)
+{
+ SPFilterPrimitive::build(document, repr);
+
+ /*LOAD ATTRIBUTES FROM REPR HERE*/
+
+ this->readAttr( "preserveAspectRatio" );
+ this->readAttr( "xlink:href" );
+}
+
+/**
+ * Drops any allocated memory.
+ */
+void SPFeImage::release() {
+ this->_image_modified_connection.disconnect();
+ this->_href_modified_connection.disconnect();
+
+ if (this->SVGElemRef) {
+ delete this->SVGElemRef;
+ }
+
+ SPFilterPrimitive::release();
+}
+
+static void sp_feImage_elem_modified(SPObject* /*href*/, guint /*flags*/, SPObject* obj)
+{
+ obj->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+}
+
+static void sp_feImage_href_modified(SPObject* /*old_elem*/, SPObject* new_elem, SPObject* obj)
+{
+ SPFeImage *feImage = SP_FEIMAGE(obj);
+ feImage->_image_modified_connection.disconnect();
+ if (new_elem) {
+ feImage->SVGElem = SP_ITEM(new_elem);
+ feImage->_image_modified_connection = ((SPObject*) feImage->SVGElem)->connectModified(sigc::bind(sigc::ptr_fun(&sp_feImage_elem_modified), obj));
+ } else {
+ feImage->SVGElem = nullptr;
+ }
+
+ obj->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+}
+
+/**
+ * Sets a specific value in the SPFeImage.
+ */
+void SPFeImage::set(SPAttributeEnum key, gchar const *value) {
+ switch(key) {
+ /*DEAL WITH SETTING ATTRIBUTES HERE*/
+ case SP_ATTR_XLINK_HREF:
+ if (this->href) {
+ g_free(this->href);
+ }
+ this->href = (value) ? g_strdup (value) : nullptr;
+ if (!this->href) return;
+ delete this->SVGElemRef;
+ this->SVGElemRef = nullptr;
+ this->SVGElem = nullptr;
+ this->_image_modified_connection.disconnect();
+ this->_href_modified_connection.disconnect();
+ try{
+ Inkscape::URI SVGElem_uri(this->href);
+ this->SVGElemRef = new Inkscape::URIReference(this->document);
+ this->SVGElemRef->attach(SVGElem_uri);
+ this->from_element = true;
+ this->_href_modified_connection = this->SVGElemRef->changedSignal().connect(sigc::bind(sigc::ptr_fun(&sp_feImage_href_modified), this));
+ if (SPObject *elemref = this->SVGElemRef->getObject()) {
+ this->SVGElem = SP_ITEM(elemref);
+ this->_image_modified_connection = ((SPObject*) this->SVGElem)->connectModified(sigc::bind(sigc::ptr_fun(&sp_feImage_elem_modified), this));
+ this->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ break;
+ } else {
+ g_warning("SVG element URI was not found in the document while loading this: %s", value);
+ }
+ }
+ // catches either MalformedURIException or UnsupportedURIException
+ catch(const Inkscape::BadURIException & e)
+ {
+ this->from_element = false;
+ /* This occurs when using external image as the source */
+ //g_warning("caught Inkscape::BadURIException in sp_feImage_set");
+ break;
+ }
+ break;
+
+ case SP_ATTR_PRESERVEASPECTRATIO:
+ /* Copied from sp-image.cpp */
+ /* Do setup before, so we can use break to escape */
+ this->aspect_align = SP_ASPECT_XMID_YMID; // Default
+ this->aspect_clip = SP_ASPECT_MEET; // Default
+ this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG);
+ if (value) {
+ int len;
+ gchar c[256];
+ const gchar *p, *e;
+ unsigned int align, clip;
+ p = value;
+ while (*p && *p == 32) p += 1;
+ if (!*p) break;
+ e = p;
+ while (*e && *e != 32) e += 1;
+ len = e - p;
+ if (len > 8) break;
+ memcpy (c, value, len);
+ c[len] = 0;
+ /* Now the actual part */
+ if (!strcmp (c, "none")) {
+ align = SP_ASPECT_NONE;
+ } else if (!strcmp (c, "xMinYMin")) {
+ align = SP_ASPECT_XMIN_YMIN;
+ } else if (!strcmp (c, "xMidYMin")) {
+ align = SP_ASPECT_XMID_YMIN;
+ } else if (!strcmp (c, "xMaxYMin")) {
+ align = SP_ASPECT_XMAX_YMIN;
+ } else if (!strcmp (c, "xMinYMid")) {
+ align = SP_ASPECT_XMIN_YMID;
+ } else if (!strcmp (c, "xMidYMid")) {
+ align = SP_ASPECT_XMID_YMID;
+ } else if (!strcmp (c, "xMaxYMid")) {
+ align = SP_ASPECT_XMAX_YMID;
+ } else if (!strcmp (c, "xMinYMax")) {
+ align = SP_ASPECT_XMIN_YMAX;
+ } else if (!strcmp (c, "xMidYMax")) {
+ align = SP_ASPECT_XMID_YMAX;
+ } else if (!strcmp (c, "xMaxYMax")) {
+ align = SP_ASPECT_XMAX_YMAX;
+ } else {
+ g_warning("Illegal preserveAspectRatio: %s", c);
+ break;
+ }
+ clip = SP_ASPECT_MEET;
+ while (*e && *e == 32) e += 1;
+ if (*e) {
+ if (!strcmp (e, "meet")) {
+ clip = SP_ASPECT_MEET;
+ } else if (!strcmp (e, "slice")) {
+ clip = SP_ASPECT_SLICE;
+ } else {
+ break;
+ }
+ }
+ this->aspect_align = align;
+ this->aspect_clip = clip;
+ }
+ break;
+
+ default:
+ SPFilterPrimitive::set(key, value);
+ break;
+ }
+}
+
+/**
+ * Receives update notifications.
+ */
+void SPFeImage::update(SPCtx *ctx, guint flags) {
+ if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG |
+ SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
+
+ /* do something to trigger redisplay, updates? */
+ }
+
+ SPFilterPrimitive::update(ctx, flags);
+}
+
+/**
+ * Writes its settings to an incoming repr object, if any.
+ */
+Inkscape::XML::Node* SPFeImage::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) {
+ /* TODO: Don't just clone, but create a new repr node and write all
+ * relevant values into it */
+ if (!repr) {
+ repr = this->getRepr()->duplicate(doc);
+ }
+
+ SPFilterPrimitive::write(doc, repr, flags);
+
+ return repr;
+}
+
+void SPFeImage::build_renderer(Inkscape::Filters::Filter* filter) {
+ g_assert(filter != nullptr);
+
+ int primitive_n = filter->add_primitive(Inkscape::Filters::NR_FILTER_IMAGE);
+ Inkscape::Filters::FilterPrimitive *nr_primitive = filter->get_primitive(primitive_n);
+ Inkscape::Filters::FilterImage *nr_image = dynamic_cast<Inkscape::Filters::FilterImage*>(nr_primitive);
+ g_assert(nr_image != nullptr);
+
+ this->renderer_common(nr_primitive);
+
+ nr_image->from_element = this->from_element;
+ nr_image->SVGElem = this->SVGElem;
+ nr_image->set_align( this->aspect_align );
+ nr_image->set_clip( this->aspect_clip );
+ nr_image->set_href(this->href);
+ nr_image->set_document(this->document);
+}
+
+/*
+ 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:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/image.h b/src/object/filters/image.h
new file mode 100644
index 0000000..dcd78f3
--- /dev/null
+++ b/src/object/filters/image.h
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** @file
+ * @brief SVG image filter effect
+ *//*
+ * Authors:
+ * Felipe Corrêa da Silva Sanches <juca@members.fsf.org>
+ * Hugo Rodrigues <haa.rodrigues@gmail.com>
+ *
+ * Copyright (C) 2006 Hugo Rodrigues
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#ifndef SP_FEIMAGE_H_SEEN
+#define SP_FEIMAGE_H_SEEN
+
+#include "sp-filter-primitive.h"
+
+#define SP_FEIMAGE(obj) (dynamic_cast<SPFeImage*>((SPObject*)obj))
+#define SP_IS_FEIMAGE(obj) (dynamic_cast<const SPFeImage*>((SPObject*)obj) != NULL)
+
+class SPItem;
+
+namespace Inkscape {
+class URIReference;
+}
+
+class SPFeImage : public SPFilterPrimitive {
+public:
+ SPFeImage();
+ ~SPFeImage() override;
+
+ gchar *href;
+
+ /* preserveAspectRatio */
+ unsigned int aspect_align : 4;
+ unsigned int aspect_clip : 1;
+
+ bool from_element;
+ SPItem* SVGElem;
+ Inkscape::URIReference* SVGElemRef;
+ sigc::connection _image_modified_connection;
+ sigc::connection _href_modified_connection;
+
+protected:
+ void build(SPDocument* doc, Inkscape::XML::Node* repr) override;
+ void release() override;
+
+ void set(SPAttributeEnum key, const gchar* value) override;
+
+ void update(SPCtx* ctx, unsigned int flags) override;
+
+ Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags) override;
+
+ void build_renderer(Inkscape::Filters::Filter* filter) override;
+};
+
+#endif /* !SP_FEIMAGE_H_SEEN */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/merge.cpp b/src/object/filters/merge.cpp
new file mode 100644
index 0000000..5fd77c5
--- /dev/null
+++ b/src/object/filters/merge.cpp
@@ -0,0 +1,115 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** \file
+ * SVG <feMerge> implementation.
+ *
+ */
+/*
+ * Authors:
+ * hugo Rodrigues <haa.rodrigues@gmail.com>
+ *
+ * Copyright (C) 2006 Hugo Rodrigues
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include "attributes.h"
+#include "svg/svg.h"
+#include "xml/repr.h"
+
+#include "merge.h"
+#include "mergenode.h"
+#include "display/nr-filter.h"
+#include "display/nr-filter-merge.h"
+
+SPFeMerge::SPFeMerge() : SPFilterPrimitive() {
+}
+
+SPFeMerge::~SPFeMerge() = default;
+
+/**
+ * Reads the Inkscape::XML::Node, and initializes SPFeMerge variables. For this to get called,
+ * our name must be associated with a repr via "sp_object_type_register". Best done through
+ * sp-object-repr.cpp's repr_name_entries array.
+ */
+void SPFeMerge::build(SPDocument *document, Inkscape::XML::Node *repr) {
+ SPFilterPrimitive::build(document, repr);
+}
+
+/**
+ * Drops any allocated memory.
+ */
+void SPFeMerge::release() {
+ SPFilterPrimitive::release();
+}
+
+/**
+ * Sets a specific value in the SPFeMerge.
+ */
+void SPFeMerge::set(SPAttributeEnum key, gchar const *value) {
+ switch(key) {
+ /*DEAL WITH SETTING ATTRIBUTES HERE*/
+ default:
+ SPFilterPrimitive::set(key, value);
+ break;
+ }
+}
+
+/**
+ * Receives update notifications.
+ */
+void SPFeMerge::update(SPCtx *ctx, guint flags) {
+ if (flags & SP_OBJECT_MODIFIED_FLAG) {
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+
+ SPFilterPrimitive::update(ctx, flags);
+}
+
+/**
+ * Writes its settings to an incoming repr object, if any.
+ */
+Inkscape::XML::Node* SPFeMerge::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) {
+ /* TODO: Don't just clone, but create a new repr node and write all
+ * relevant values into it. And child nodes, too! */
+ if (!repr) {
+ repr = this->getRepr()->duplicate(doc);
+ }
+
+
+ SPFilterPrimitive::write(doc, repr, flags);
+
+ return repr;
+}
+
+void SPFeMerge::build_renderer(Inkscape::Filters::Filter* filter) {
+ g_assert(filter != nullptr);
+
+ int primitive_n = filter->add_primitive(Inkscape::Filters::NR_FILTER_MERGE);
+ Inkscape::Filters::FilterPrimitive *nr_primitive = filter->get_primitive(primitive_n);
+ Inkscape::Filters::FilterMerge *nr_merge = dynamic_cast<Inkscape::Filters::FilterMerge*>(nr_primitive);
+ g_assert(nr_merge != nullptr);
+
+ this->renderer_common(nr_primitive);
+
+ int in_nr = 0;
+
+ for(auto& input: children) {
+ if (SP_IS_FEMERGENODE(&input)) {
+ SPFeMergeNode *node = SP_FEMERGENODE(&input);
+ nr_merge->set_input(in_nr, node->input);
+ in_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:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/merge.h b/src/object/filters/merge.h
new file mode 100644
index 0000000..a2c87af
--- /dev/null
+++ b/src/object/filters/merge.h
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** \file
+ * SVG merge filter effect
+ *//*
+ * Authors:
+ * Hugo Rodrigues <haa.rodrigues@gmail.com>
+ *
+ * Copyright (C) 2006 Hugo Rodrigues
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+#ifndef SP_FEMERGE_H_SEEN
+#define SP_FEMERGE_H_SEEN
+
+#include "sp-filter-primitive.h"
+
+#define SP_FEMERGE(obj) (dynamic_cast<SPFeMerge*>((SPObject*)obj))
+#define SP_IS_FEMERGE(obj) (dynamic_cast<const SPFeMerge*>((SPObject*)obj) != NULL)
+
+class SPFeMerge : public SPFilterPrimitive {
+public:
+ SPFeMerge();
+ ~SPFeMerge() override;
+
+protected:
+ void build(SPDocument* doc, Inkscape::XML::Node* repr) override;
+ void release() override;
+
+ void set(SPAttributeEnum key, const gchar* value) override;
+
+ void update(SPCtx* ctx, unsigned int flags) override;
+
+ Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags) override;
+
+ void build_renderer(Inkscape::Filters::Filter* filter) override;
+};
+
+#endif /* !SP_FEMERGE_H_SEEN */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/mergenode.cpp b/src/object/filters/mergenode.cpp
new file mode 100644
index 0000000..e5e2efc
--- /dev/null
+++ b/src/object/filters/mergenode.cpp
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** \file
+ * feMergeNode implementation. A feMergeNode contains the name of one
+ * input image for feMerge.
+ */
+/*
+ * Authors:
+ * Kees Cook <kees@outflux.net>
+ * Niko Kiirala <niko@kiirala.com>
+ * Abhishek Sharma
+ *
+ * Copyright (C) 2004,2007 authors
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include "mergenode.h"
+#include "merge.h"
+
+#include "attributes.h"
+
+#include "display/nr-filter-types.h"
+
+#include "xml/repr.h"
+
+SPFeMergeNode::SPFeMergeNode()
+ : SPObject(), input(Inkscape::Filters::NR_FILTER_SLOT_NOT_SET) {
+}
+
+SPFeMergeNode::~SPFeMergeNode() = default;
+
+/**
+ * Reads the Inkscape::XML::Node, and initializes SPFeMergeNode variables. For this to get called,
+ * our name must be associated with a repr via "sp_object_type_register". Best done through
+ * sp-object-repr.cpp's repr_name_entries array.
+ */
+void SPFeMergeNode::build(SPDocument */*document*/, Inkscape::XML::Node */*repr*/) {
+ this->readAttr( "in" );
+}
+
+/**
+ * Drops any allocated memory.
+ */
+void SPFeMergeNode::release() {
+ SPObject::release();
+}
+
+/**
+ * Sets a specific value in the SPFeMergeNode.
+ */
+void SPFeMergeNode::set(SPAttributeEnum key, gchar const *value) {
+ SPFeMerge *parent = SP_FEMERGE(this->parent);
+
+ if (key == SP_ATTR_IN) {
+ int input = parent->read_in(value);
+ if (input != this->input) {
+ this->input = input;
+ this->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ }
+
+ /* See if any parents need this value. */
+ SPObject::set(key, value);
+}
+
+/**
+ * Receives update notifications.
+ */
+void SPFeMergeNode::update(SPCtx *ctx, guint flags) {
+ if (flags & SP_OBJECT_MODIFIED_FLAG) {
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+
+ SPObject::update(ctx, flags);
+}
+
+/**
+ * Writes its settings to an incoming repr object, if any.
+ */
+Inkscape::XML::Node* SPFeMergeNode::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) {
+ // Inkscape-only this, not copied during an "plain SVG" dump:
+ if (flags & SP_OBJECT_WRITE_EXT) {
+ if (repr) {
+ // is this sane?
+ //repr->mergeFrom(object->getRepr(), "id");
+ } else {
+ repr = this->getRepr()->duplicate(doc);
+ }
+ }
+
+ SPObject::write(doc, repr, flags);
+
+ return repr;
+}
+
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/mergenode.h b/src/object/filters/mergenode.h
new file mode 100644
index 0000000..36a4cc1
--- /dev/null
+++ b/src/object/filters/mergenode.h
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#ifndef SP_FEMERGENODE_H_SEEN
+#define SP_FEMERGENODE_H_SEEN
+
+/** \file
+ * feMergeNode implementation. A feMergeNode stores information about one
+ * input image for feMerge filter primitive.
+ */
+/*
+ * Authors:
+ * Kees Cook <kees@outflux.net>
+ * Niko Kiirala <niko@kiirala.com>
+ *
+ * Copyright (C) 2004,2007 authors
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include "object/sp-object.h"
+
+#define SP_FEMERGENODE(obj) (dynamic_cast<SPFeMergeNode*>((SPObject*)obj))
+#define SP_IS_FEMERGENODE(obj) (dynamic_cast<const SPFeMergeNode*>((SPObject*)obj) != NULL)
+
+class SPFeMergeNode : public SPObject {
+public:
+ SPFeMergeNode();
+ ~SPFeMergeNode() override;
+
+ int input;
+
+protected:
+ void build(SPDocument* doc, Inkscape::XML::Node* repr) override;
+ void release() override;
+
+ void set(SPAttributeEnum key, const gchar* value) override;
+
+ void update(SPCtx* ctx, unsigned int flags) override;
+
+ Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags) override;
+};
+
+#endif /* !SP_FEMERGENODE_H_SEEN */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/morphology.cpp b/src/object/filters/morphology.cpp
new file mode 100644
index 0000000..02ae005
--- /dev/null
+++ b/src/object/filters/morphology.cpp
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** \file
+ * SVG <feMorphology> implementation.
+ *
+ */
+/*
+ * Authors:
+ * Felipe Sanches <juca@members.fsf.org>
+ * Hugo Rodrigues <haa.rodrigues@gmail.com>
+ * Abhishek Sharma
+ *
+ * Copyright (C) 2006 Hugo Rodrigues
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include <cstring>
+
+#include "attributes.h"
+#include "svg/svg.h"
+#include "morphology.h"
+#include "xml/repr.h"
+#include "display/nr-filter.h"
+
+SPFeMorphology::SPFeMorphology() : SPFilterPrimitive() {
+ this->Operator = Inkscape::Filters::MORPHOLOGY_OPERATOR_ERODE;
+
+ //Setting default values:
+ this->radius.set("0");
+}
+
+SPFeMorphology::~SPFeMorphology() = default;
+
+/**
+ * Reads the Inkscape::XML::Node, and initializes SPFeMorphology variables. For this to get called,
+ * our name must be associated with a repr via "sp_object_type_register". Best done through
+ * sp-object-repr.cpp's repr_name_entries array.
+ */
+void SPFeMorphology::build(SPDocument *document, Inkscape::XML::Node *repr) {
+ SPFilterPrimitive::build(document, repr);
+
+ /*LOAD ATTRIBUTES FROM REPR HERE*/
+ this->readAttr( "operator" );
+ this->readAttr( "radius" );
+}
+
+/**
+ * Drops any allocated memory.
+ */
+void SPFeMorphology::release() {
+ SPFilterPrimitive::release();
+}
+
+static Inkscape::Filters::FilterMorphologyOperator sp_feMorphology_read_operator(gchar const *value){
+ if (!value) {
+ return Inkscape::Filters::MORPHOLOGY_OPERATOR_ERODE; //erode is default
+ }
+
+ switch(value[0]){
+ case 'e':
+ if (strncmp(value, "erode", 5) == 0) {
+ return Inkscape::Filters::MORPHOLOGY_OPERATOR_ERODE;
+ }
+ break;
+ case 'd':
+ if (strncmp(value, "dilate", 6) == 0) {
+ return Inkscape::Filters::MORPHOLOGY_OPERATOR_DILATE;
+ }
+ break;
+ }
+
+ return Inkscape::Filters::MORPHOLOGY_OPERATOR_ERODE; //erode is default
+}
+
+/**
+ * Sets a specific value in the SPFeMorphology.
+ */
+void SPFeMorphology::set(SPAttributeEnum key, gchar const *value) {
+ Inkscape::Filters::FilterMorphologyOperator read_operator;
+
+ switch(key) {
+ /*DEAL WITH SETTING ATTRIBUTES HERE*/
+ case SP_ATTR_OPERATOR:
+ read_operator = sp_feMorphology_read_operator(value);
+
+ if (read_operator != this->Operator){
+ this->Operator = read_operator;
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ case SP_ATTR_RADIUS:
+ this->radius.set(value);
+
+ //From SVG spec: If <y-radius> is not provided, it defaults to <x-radius>.
+ if (this->radius.optNumIsSet() == false) {
+ this->radius.setOptNumber(this->radius.getNumber());
+ }
+
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ break;
+ default:
+ SPFilterPrimitive::set(key, value);
+ break;
+ }
+
+}
+
+/**
+ * Receives update notifications.
+ */
+void SPFeMorphology::update(SPCtx *ctx, guint flags) {
+ if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG |
+ SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
+
+ /* do something to trigger redisplay, updates? */
+
+ }
+
+ SPFilterPrimitive::update(ctx, flags);
+}
+
+/**
+ * Writes its settings to an incoming repr object, if any.
+ */
+Inkscape::XML::Node* SPFeMorphology::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) {
+ /* TODO: Don't just clone, but create a new repr node and write all
+ * relevant values into it */
+ if (!repr) {
+ repr = this->getRepr()->duplicate(doc);
+ }
+
+ SPFilterPrimitive::write(doc, repr, flags);
+
+ return repr;
+}
+
+void SPFeMorphology::build_renderer(Inkscape::Filters::Filter* filter) {
+ g_assert(filter != nullptr);
+
+ int primitive_n = filter->add_primitive(Inkscape::Filters::NR_FILTER_MORPHOLOGY);
+ Inkscape::Filters::FilterPrimitive *nr_primitive = filter->get_primitive(primitive_n);
+ Inkscape::Filters::FilterMorphology *nr_morphology = dynamic_cast<Inkscape::Filters::FilterMorphology*>(nr_primitive);
+ g_assert(nr_morphology != nullptr);
+
+ this->renderer_common(nr_primitive);
+
+ nr_morphology->set_operator(this->Operator);
+ nr_morphology->set_xradius( this->radius.getNumber() );
+ nr_morphology->set_yradius( this->radius.getOptNumber() );
+}
+
+/*
+ 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:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/morphology.h b/src/object/filters/morphology.h
new file mode 100644
index 0000000..94842c4
--- /dev/null
+++ b/src/object/filters/morphology.h
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** \file
+ * @brief SVG morphology filter effect
+ *//*
+ * Authors:
+ * Hugo Rodrigues <haa.rodrigues@gmail.com>
+ *
+ * Copyright (C) 2006 Hugo Rodrigues
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#ifndef SP_FEMORPHOLOGY_H_SEEN
+#define SP_FEMORPHOLOGY_H_SEEN
+
+#include "sp-filter-primitive.h"
+#include "number-opt-number.h"
+#include "display/nr-filter-morphology.h"
+
+#define SP_FEMORPHOLOGY(obj) (dynamic_cast<SPFeMorphology*>((SPObject*)obj))
+#define SP_IS_FEMORPHOLOGY(obj) (dynamic_cast<const SPFeMorphology*>((SPObject*)obj) != NULL)
+
+class SPFeMorphology : public SPFilterPrimitive {
+public:
+ SPFeMorphology();
+ ~SPFeMorphology() override;
+
+ Inkscape::Filters::FilterMorphologyOperator Operator;
+ NumberOptNumber radius;
+
+protected:
+ void build(SPDocument* doc, Inkscape::XML::Node* repr) override;
+ void release() override;
+
+ void set(SPAttributeEnum key, const gchar* value) override;
+
+ void update(SPCtx* ctx, unsigned int flags) override;
+
+ Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags) override;
+
+ void build_renderer(Inkscape::Filters::Filter* filter) override;
+};
+
+#endif /* !SP_FEMORPHOLOGY_H_SEEN */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/offset.cpp b/src/object/filters/offset.cpp
new file mode 100644
index 0000000..5370348
--- /dev/null
+++ b/src/object/filters/offset.cpp
@@ -0,0 +1,137 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** \file
+ * SVG <feOffset> implementation.
+ *
+ */
+/*
+ * Authors:
+ * hugo Rodrigues <haa.rodrigues@gmail.com>
+ * Niko Kiirala <niko@kiirala.com>
+ * Abhishek Sharma
+ *
+ * Copyright (C) 2006,2007 authors
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include "offset.h"
+
+#include "attributes.h"
+#include "helper-fns.h"
+
+#include "display/nr-filter.h"
+#include "display/nr-filter-offset.h"
+
+#include "svg/svg.h"
+
+#include "xml/repr.h"
+
+SPFeOffset::SPFeOffset() : SPFilterPrimitive() {
+ this->dx = 0;
+ this->dy = 0;
+}
+
+SPFeOffset::~SPFeOffset() = default;
+
+/**
+ * Reads the Inkscape::XML::Node, and initializes SPFeOffset variables. For this to get called,
+ * our name must be associated with a repr via "sp_object_type_register". Best done through
+ * sp-object-repr.cpp's repr_name_entries array.
+ */
+void SPFeOffset::build(SPDocument *document, Inkscape::XML::Node *repr) {
+ SPFilterPrimitive::build(document, repr);
+
+ this->readAttr( "dx" );
+ this->readAttr( "dy" );
+}
+
+/**
+ * Drops any allocated memory.
+ */
+void SPFeOffset::release() {
+ SPFilterPrimitive::release();
+}
+
+/**
+ * Sets a specific value in the SPFeOffset.
+ */
+void SPFeOffset::set(SPAttributeEnum key, gchar const *value) {
+ double read_num;
+
+ switch(key) {
+ case SP_ATTR_DX:
+ read_num = value ? helperfns_read_number(value) : 0;
+
+ if (read_num != this->dx) {
+ this->dx = read_num;
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ case SP_ATTR_DY:
+ read_num = value ? helperfns_read_number(value) : 0;
+
+ if (read_num != this->dy) {
+ this->dy = read_num;
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+
+ /*DEAL WITH SETTING ATTRIBUTES HERE*/
+ default:
+ SPFilterPrimitive::set(key, value);
+ break;
+ }
+}
+
+/**
+ * Receives update notifications.
+ */
+void SPFeOffset::update(SPCtx *ctx, guint flags) {
+ if (flags & SP_OBJECT_MODIFIED_FLAG) {
+ this->readAttr( "dx" );
+ this->readAttr( "dy" );
+ }
+
+ SPFilterPrimitive::update(ctx, flags);
+}
+
+/**
+ * Writes its settings to an incoming repr object, if any.
+ */
+Inkscape::XML::Node* SPFeOffset::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) {
+ /* TODO: Don't just clone, but create a new repr node and write all
+ * relevant values into it */
+ if (!repr) {
+ repr = this->getRepr()->duplicate(doc);
+ }
+
+ SPFilterPrimitive::write(doc, repr, flags);
+
+ return repr;
+}
+
+void SPFeOffset::build_renderer(Inkscape::Filters::Filter* filter) {
+ g_assert(filter != nullptr);
+
+ int primitive_n = filter->add_primitive(Inkscape::Filters::NR_FILTER_OFFSET);
+ Inkscape::Filters::FilterPrimitive *nr_primitive = filter->get_primitive(primitive_n);
+ Inkscape::Filters::FilterOffset *nr_offset = dynamic_cast<Inkscape::Filters::FilterOffset*>(nr_primitive);
+ g_assert(nr_offset != nullptr);
+
+ this->renderer_common(nr_primitive);
+
+ nr_offset->set_dx(this->dx);
+ nr_offset->set_dy(this->dy);
+}
+
+
+/*
+ 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:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/offset.h b/src/object/filters/offset.h
new file mode 100644
index 0000000..7b9febb
--- /dev/null
+++ b/src/object/filters/offset.h
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** @file
+ * @brief SVG offset filter effect
+ *//*
+ * Authors:
+ * Hugo Rodrigues <haa.rodrigues@gmail.com>
+ *
+ * Copyright (C) 2006 Hugo Rodrigues
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#ifndef SP_FEOFFSET_H_SEEN
+#define SP_FEOFFSET_H_SEEN
+
+#include "sp-filter-primitive.h"
+
+#define SP_FEOFFSET(obj) (dynamic_cast<SPFeOffset*>((SPObject*)obj))
+#define SP_IS_FEOFFSET(obj) (dynamic_cast<const SPFeOffset*>((SPObject*)obj) != NULL)
+
+class SPFeOffset : public SPFilterPrimitive {
+public:
+ SPFeOffset();
+ ~SPFeOffset() override;
+
+ double dx, dy;
+
+protected:
+ void build(SPDocument* doc, Inkscape::XML::Node* repr) override;
+ void release() override;
+
+ void set(SPAttributeEnum key, const gchar* value) override;
+
+ void update(SPCtx* ctx, unsigned int flags) override;
+
+ Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags) override;
+
+ void build_renderer(Inkscape::Filters::Filter* filter) override;
+};
+
+#endif /* !SP_FEOFFSET_H_SEEN */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/pointlight.cpp b/src/object/filters/pointlight.cpp
new file mode 100644
index 0000000..1be7711
--- /dev/null
+++ b/src/object/filters/pointlight.cpp
@@ -0,0 +1,190 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** \file
+ * SVG <fepointlight> implementation.
+ */
+/*
+ * Authors:
+ * Hugo Rodrigues <haa.rodrigues@gmail.com>
+ * Niko Kiirala <niko@kiirala.com>
+ * Jean-Rene Reinhard <jr@komite.net>
+ * Abhishek Sharma
+ *
+ * Copyright (C) 2006,2007 Authors
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+// Same directory
+#include "pointlight.h"
+#include "diffuselighting.h"
+#include "specularlighting.h"
+
+#include <glib.h>
+
+#include "attributes.h"
+#include "document.h"
+
+
+#include "xml/node.h"
+#include "xml/repr.h"
+
+SPFePointLight::SPFePointLight()
+ : SPObject(), x(0), x_set(FALSE), y(0), y_set(FALSE), z(0), z_set(FALSE) {
+}
+
+SPFePointLight::~SPFePointLight() = default;
+
+
+/**
+ * Reads the Inkscape::XML::Node, and initializes SPPointLight variables. For this to get called,
+ * our name must be associated with a repr via "sp_object_type_register". Best done through
+ * sp-object-repr.cpp's repr_name_entries array.
+ */
+void SPFePointLight::build(SPDocument *document, Inkscape::XML::Node *repr) {
+ SPObject::build(document, repr);
+
+ //Read values of key attributes from XML nodes into object.
+ this->readAttr( "x" );
+ this->readAttr( "y" );
+ this->readAttr( "z" );
+
+//is this necessary?
+ document->addResource("fepointlight", this);
+}
+
+/**
+ * Drops any allocated memory.
+ */
+void SPFePointLight::release() {
+ if ( this->document ) {
+ // Unregister ourselves
+ this->document->removeResource("fepointlight", this);
+ }
+
+//TODO: release resources here
+}
+
+/**
+ * Sets a specific value in the SPFePointLight.
+ */
+void SPFePointLight::set(SPAttributeEnum key, gchar const *value) {
+ gchar *end_ptr;
+
+ switch (key) {
+ case SP_ATTR_X:
+ end_ptr = nullptr;
+
+ if (value) {
+ this->x = g_ascii_strtod(value, &end_ptr);
+
+ if (end_ptr) {
+ this->x_set = TRUE;
+ }
+ }
+
+ if (!value || !end_ptr) {
+ this->x = 0;
+ this->x_set = FALSE;
+ }
+
+ if (this->parent &&
+ (SP_IS_FEDIFFUSELIGHTING(this->parent) ||
+ SP_IS_FESPECULARLIGHTING(this->parent))) {
+ this->parent->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ case SP_ATTR_Y:
+ end_ptr = nullptr;
+
+ if (value) {
+ this->y = g_ascii_strtod(value, &end_ptr);
+
+ if (end_ptr) {
+ this->y_set = TRUE;
+ }
+ }
+
+ if (!value || !end_ptr) {
+ this->y = 0;
+ this->y_set = FALSE;
+ }
+
+ if (this->parent &&
+ (SP_IS_FEDIFFUSELIGHTING(this->parent) ||
+ SP_IS_FESPECULARLIGHTING(this->parent))) {
+ this->parent->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ case SP_ATTR_Z:
+ end_ptr = nullptr;
+
+ if (value) {
+ this->z = g_ascii_strtod(value, &end_ptr);
+
+ if (end_ptr) {
+ this->z_set = TRUE;
+ }
+ }
+
+ if (!value || !end_ptr) {
+ this->z = 0;
+ this->z_set = FALSE;
+ }
+
+ if (this->parent &&
+ (SP_IS_FEDIFFUSELIGHTING(this->parent) ||
+ SP_IS_FESPECULARLIGHTING(this->parent))) {
+ this->parent->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ default:
+ // See if any parents need this value.
+ SPObject::set(key, value);
+ break;
+ }
+}
+
+/**
+ * * Receives update notifications.
+ * */
+void SPFePointLight::update(SPCtx *ctx, guint flags) {
+ if (flags & SP_OBJECT_MODIFIED_FLAG) {
+ /* do something to trigger redisplay, updates? */
+ this->readAttr( "x" );
+ this->readAttr( "y" );
+ this->readAttr( "z" );
+ }
+
+ SPObject::update(ctx, flags);
+}
+
+/**
+ * Writes its settings to an incoming repr object, if any.
+ */
+Inkscape::XML::Node* SPFePointLight::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) {
+ if (!repr) {
+ repr = this->getRepr()->duplicate(doc);
+ }
+
+ if (this->x_set)
+ sp_repr_set_css_double(repr, "x", this->x);
+ if (this->y_set)
+ sp_repr_set_css_double(repr, "y", this->y);
+ if (this->z_set)
+ sp_repr_set_css_double(repr, "z", this->z);
+
+ SPObject::write(doc, repr, flags);
+
+ return repr;
+}
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/pointlight.h b/src/object/filters/pointlight.h
new file mode 100644
index 0000000..6eb374b
--- /dev/null
+++ b/src/object/filters/pointlight.h
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** \file
+ * SVG <filter> implementation, see sp-filter.cpp.
+ */
+#ifndef SP_FEPOINTLIGHT_H_SEEN
+#define SP_FEPOINTLIGHT_H_SEEN
+
+/*
+ * Authors:
+ * Hugo Rodrigues <haa.rodrigues@gmail.com>
+ * Niko Kiirala <niko@kiirala.com>
+ * Jean-Rene Reinhard <jr@komite.net>
+ *
+ * Copyright (C) 2006,2007 Authors
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include "object/sp-object.h"
+
+#define SP_FEPOINTLIGHT(obj) (dynamic_cast<SPFePointLight*>((SPObject*)obj))
+#define SP_IS_FEPOINTLIGHT(obj) (dynamic_cast<const SPFePointLight*>((SPObject*)obj) != NULL)
+
+class SPFePointLight : public SPObject {
+public:
+ SPFePointLight();
+ ~SPFePointLight() override;
+
+ /** x coordinate of the light source */
+ float x;
+ unsigned int x_set : 1;
+ /** y coordinate of the light source */
+ float y;
+ unsigned int y_set : 1;
+ /** z coordinate of the light source */
+ float z;
+ unsigned int z_set : 1;
+
+protected:
+ void build(SPDocument* doc, Inkscape::XML::Node* repr) override;
+ void release() override;
+
+ void set(SPAttributeEnum key, char const* value) override;
+
+ void update(SPCtx* ctx, unsigned int flags) override;
+
+ Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, unsigned int flags) override;
+};
+
+#endif /* !SP_FEPOINTLIGHT_H_SEEN */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/sp-filter-primitive.cpp b/src/object/filters/sp-filter-primitive.cpp
new file mode 100644
index 0000000..5d4c78b
--- /dev/null
+++ b/src/object/filters/sp-filter-primitive.cpp
@@ -0,0 +1,273 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** \file
+ * Superclass for all the filter primitives
+ *
+ */
+/*
+ * Authors:
+ * Kees Cook <kees@outflux.net>
+ * Niko Kiirala <niko@kiirala.com>
+ * Abhishek Sharma
+ *
+ * Copyright (C) 2004-2007 Authors
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include <cstring>
+
+#include "sp-filter-primitive.h"
+
+#include "attributes.h"
+
+#include "display/nr-filter-primitive.h"
+
+#include "style.h"
+
+
+// CPPIFY: Make pure virtual.
+//void SPFilterPrimitive::build_renderer(Inkscape::Filters::Filter* filter) {
+// throw;
+//}
+
+SPFilterPrimitive::SPFilterPrimitive() : SPObject() {
+ this->image_in = Inkscape::Filters::NR_FILTER_SLOT_NOT_SET;
+ this->image_out = Inkscape::Filters::NR_FILTER_SLOT_NOT_SET;
+
+ // We must keep track if a value is set or not, if not set then the region defaults to 0%, 0%,
+ // 100%, 100% ("x", "y", "width", "height") of the -> filter <- region. If set then
+ // percentages are in terms of bounding box or viewbox, depending on value of "primitiveUnits"
+
+ // NB: SVGLength.set takes prescaled percent values: 1 means 100%
+ this->x.unset(SVGLength::PERCENT, 0, 0);
+ this->y.unset(SVGLength::PERCENT, 0, 0);
+ this->width.unset(SVGLength::PERCENT, 1, 0);
+ this->height.unset(SVGLength::PERCENT, 1, 0);
+}
+
+SPFilterPrimitive::~SPFilterPrimitive() = default;
+
+/**
+ * Reads the Inkscape::XML::Node, and initializes SPFilterPrimitive variables. For this to get called,
+ * our name must be associated with a repr via "sp_object_type_register". Best done through
+ * sp-object-repr.cpp's repr_name_entries array.
+ */
+void SPFilterPrimitive::build(SPDocument *document, Inkscape::XML::Node *repr) {
+ SPFilterPrimitive* object = this;
+
+ object->readAttr( "style" ); // struct not derived from SPItem, we need to do this ourselves.
+ object->readAttr( "in" );
+ object->readAttr( "result" );
+ object->readAttr( "x" );
+ object->readAttr( "y" );
+ object->readAttr( "width" );
+ object->readAttr( "height" );
+
+ SPObject::build(document, repr);
+}
+
+/**
+ * Drops any allocated memory.
+ */
+void SPFilterPrimitive::release() {
+ SPObject::release();
+}
+
+/**
+ * Sets a specific value in the SPFilterPrimitive.
+ */
+void SPFilterPrimitive::set(SPAttributeEnum key, gchar const *value) {
+
+ int image_nr;
+ switch (key) {
+ case SP_ATTR_IN:
+ if (value) {
+ image_nr = this->read_in(value);
+ } else {
+ image_nr = Inkscape::Filters::NR_FILTER_SLOT_NOT_SET;
+ }
+ if (image_nr != this->image_in) {
+ this->image_in = image_nr;
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ case SP_ATTR_RESULT:
+ if (value) {
+ image_nr = this->read_result(value);
+ } else {
+ image_nr = Inkscape::Filters::NR_FILTER_SLOT_NOT_SET;
+ }
+ if (image_nr != this->image_out) {
+ this->image_out = image_nr;
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+
+ /* Filter primitive sub-region */
+ case SP_ATTR_X:
+ this->x.readOrUnset(value);
+ this->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ break;
+ case SP_ATTR_Y:
+ this->y.readOrUnset(value);
+ this->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ break;
+ case SP_ATTR_WIDTH:
+ this->width.readOrUnset(value);
+ this->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ break;
+ case SP_ATTR_HEIGHT:
+ this->height.readOrUnset(value);
+ this->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ break;
+ }
+
+ /* See if any parents need this value. */
+ SPObject::set(key, value);
+}
+
+/**
+ * Receives update notifications.
+ */
+void SPFilterPrimitive::update(SPCtx *ctx, guint flags) {
+
+ SPItemCtx *ictx = (SPItemCtx *) ctx;
+
+ // Do here since we know viewport (Bounding box case handled during rendering)
+ SPFilter *parent = SP_FILTER(this->parent);
+
+ if( parent->primitiveUnits == SP_FILTER_UNITS_USERSPACEONUSE ) {
+ this->calcDimsFromParentViewport(ictx, true);
+ }
+
+ SPObject::update(ctx, flags);
+}
+
+/**
+ * Writes its settings to an incoming repr object, if any.
+ */
+Inkscape::XML::Node* SPFilterPrimitive::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) {
+ SPFilterPrimitive* object = this;
+
+ SPFilterPrimitive *prim = SP_FILTER_PRIMITIVE(object);
+ SPFilter *parent = SP_FILTER(object->parent);
+
+ if (!repr) {
+ repr = object->getRepr()->duplicate(doc);
+ }
+
+ gchar const *in_name = parent->name_for_image(prim->image_in);
+ repr->setAttribute("in", in_name);
+
+ gchar const *out_name = parent->name_for_image(prim->image_out);
+ repr->setAttribute("result", out_name);
+
+ /* Do we need to add x,y,width,height? */
+ SPObject::write(doc, repr, flags);
+
+ return repr;
+}
+
+int SPFilterPrimitive::read_in(gchar const *name)
+{
+ if (!name){
+ return Inkscape::Filters::NR_FILTER_SLOT_NOT_SET;
+ }
+ // TODO: are these case sensitive or not? (assumed yes)
+ switch (name[0]) {
+ case 'S':
+ if (strcmp(name, "SourceGraphic") == 0)
+ return Inkscape::Filters::NR_FILTER_SOURCEGRAPHIC;
+ if (strcmp(name, "SourceAlpha") == 0)
+ return Inkscape::Filters::NR_FILTER_SOURCEALPHA;
+ if (strcmp(name, "StrokePaint") == 0)
+ return Inkscape::Filters::NR_FILTER_STROKEPAINT;
+ break;
+ case 'B':
+ if (strcmp(name, "BackgroundImage") == 0)
+ return Inkscape::Filters::NR_FILTER_BACKGROUNDIMAGE;
+ if (strcmp(name, "BackgroundAlpha") == 0)
+ return Inkscape::Filters::NR_FILTER_BACKGROUNDALPHA;
+ break;
+ case 'F':
+ if (strcmp(name, "FillPaint") == 0)
+ return Inkscape::Filters::NR_FILTER_FILLPAINT;
+ break;
+ }
+
+ SPFilter *parent = SP_FILTER(this->parent);
+ int ret = parent->get_image_name(name);
+ if (ret >= 0) return ret;
+
+ return Inkscape::Filters::NR_FILTER_SLOT_NOT_SET;
+}
+
+int SPFilterPrimitive::read_result(gchar const *name)
+{
+ SPFilter *parent = SP_FILTER(this->parent);
+ int ret = parent->get_image_name(name);
+ if (ret >= 0) return ret;
+
+ ret = parent->set_image_name(name);
+ if (ret >= 0) return ret;
+
+ return Inkscape::Filters::NR_FILTER_SLOT_NOT_SET;
+}
+
+/**
+ * Gives name for output of previous filter. Makes things clearer when 'this'
+ * is a filter with two or more inputs. Returns the slot number of result
+ * of previous primitive, or NR_FILTER_SOURCEGRAPHIC if this is the first
+ * primitive.
+ */
+int SPFilterPrimitive::name_previous_out() {
+ SPFilter *parent = SP_FILTER(this->parent);
+ SPObject *i = parent->firstChild();
+ while (i && i->getNext() != this) {
+ i = i->getNext();
+ }
+ if (i) {
+ SPFilterPrimitive *i_prim = SP_FILTER_PRIMITIVE(i);
+ if (i_prim->image_out < 0) {
+ Glib::ustring name = parent->get_new_result_name();
+ int slot = parent->set_image_name(name.c_str());
+ i_prim->image_out = slot;
+ //XML Tree is being directly used while it shouldn't be.
+ i_prim->setAttributeOrRemoveIfEmpty("result", name);
+ return slot;
+ } else {
+ return i_prim->image_out;
+ }
+ }
+ return Inkscape::Filters::NR_FILTER_SOURCEGRAPHIC;
+}
+
+/* Common initialization for filter primitives */
+void SPFilterPrimitive::renderer_common(Inkscape::Filters::FilterPrimitive *nr_prim)
+{
+ g_assert(nr_prim != nullptr);
+
+
+ nr_prim->set_input(this->image_in);
+ nr_prim->set_output(this->image_out);
+
+ /* TODO: place here code to handle input images, filter area etc. */
+ // We don't know current viewport or bounding box, this is wrong approach.
+ nr_prim->set_subregion( this->x, this->y, this->width, this->height );
+
+ // Give renderer access to filter properties
+ nr_prim->setStyle( this->style );
+}
+
+
+
+/*
+ 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:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/sp-filter-primitive.h b/src/object/filters/sp-filter-primitive.h
new file mode 100644
index 0000000..ae33a02
--- /dev/null
+++ b/src/object/filters/sp-filter-primitive.h
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#ifndef SEEN_SP_FILTER_PRIMITIVE_H
+#define SEEN_SP_FILTER_PRIMITIVE_H
+
+/** \file
+ * Document level base class for all SVG filter primitives.
+ */
+/*
+ * Authors:
+ * Hugo Rodrigues <haa.rodrigues@gmail.com>
+ * Niko Kiirala <niko@kiirala.com>
+ *
+ * Copyright (C) 2006,2007 Authors
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include "../sp-object.h"
+#include "../sp-dimensions.h"
+
+#define SP_FILTER_PRIMITIVE(obj) (dynamic_cast<SPFilterPrimitive*>((SPObject*)obj))
+#define SP_IS_FILTER_PRIMITIVE(obj) (dynamic_cast<const SPFilterPrimitive*>((SPObject*)obj) != NULL)
+
+namespace Inkscape {
+namespace Filters {
+class Filter;
+class FilterPrimitive;
+} }
+
+class SPFilterPrimitive : public SPObject, public SPDimensions {
+public:
+ SPFilterPrimitive();
+ ~SPFilterPrimitive() override;
+
+ int image_in, image_out;
+
+protected:
+ void build(SPDocument* doc, Inkscape::XML::Node* repr) override;
+ void release() override;
+
+ void set(SPAttributeEnum key, char const* value) override;
+
+ void update(SPCtx* ctx, unsigned int flags) override;
+
+ Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, unsigned int flags) override;
+
+public:
+ virtual void build_renderer(Inkscape::Filters::Filter* filter) = 0;
+
+ /* Common initialization for filter primitives */
+ void renderer_common(Inkscape::Filters::FilterPrimitive *nr_prim);
+
+ int name_previous_out();
+ int read_in(char const *name);
+ int read_result(char const *name);
+};
+
+#endif
+/*
+ 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:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/specularlighting.cpp b/src/object/filters/specularlighting.cpp
new file mode 100644
index 0000000..52af6ee
--- /dev/null
+++ b/src/object/filters/specularlighting.cpp
@@ -0,0 +1,340 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** \file
+ * SVG <feSpecularLighting> implementation.
+ *
+ */
+/*
+ * Authors:
+ * hugo Rodrigues <haa.rodrigues@gmail.com>
+ * Jean-Rene Reinhard <jr@komite.net>
+ * Abhishek Sharma
+ *
+ * Copyright (C) 2006 Hugo Rodrigues
+ * 2007 authors
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+// Same directory
+#include "specularlighting.h"
+#include "distantlight.h"
+#include "pointlight.h"
+#include "spotlight.h"
+
+#include "attributes.h"
+#include "strneq.h"
+
+#include "display/nr-filter.h"
+#include "display/nr-filter-specularlighting.h"
+
+#include "object/sp-object.h"
+
+#include "svg/svg.h"
+#include "svg/svg-color.h"
+#include "svg/svg-icc-color.h"
+
+#include "xml/repr.h"
+
+/* FeSpecularLighting base class */
+static void sp_feSpecularLighting_children_modified(SPFeSpecularLighting *sp_specularlighting);
+
+SPFeSpecularLighting::SPFeSpecularLighting() : SPFilterPrimitive() {
+ this->surfaceScale = 1;
+ this->specularConstant = 1;
+ this->specularExponent = 1;
+ this->lighting_color = 0xffffffff;
+ this->icc = nullptr;
+
+ //TODO kernelUnit
+ this->renderer = nullptr;
+
+ this->surfaceScale_set = FALSE;
+ this->specularConstant_set = FALSE;
+ this->specularExponent_set = FALSE;
+ this->lighting_color_set = FALSE;
+}
+
+SPFeSpecularLighting::~SPFeSpecularLighting() = default;
+
+/**
+ * Reads the Inkscape::XML::Node, and initializes SPFeSpecularLighting variables. For this to get called,
+ * our name must be associated with a repr via "sp_object_type_register". Best done through
+ * sp-object-repr.cpp's repr_name_entries array.
+ */
+void SPFeSpecularLighting::build(SPDocument *document, Inkscape::XML::Node *repr) {
+ SPFilterPrimitive::build(document, repr);
+
+ /*LOAD ATTRIBUTES FROM REPR HERE*/
+ this->readAttr( "surfaceScale" );
+ this->readAttr( "specularConstant" );
+ this->readAttr( "specularExponent" );
+ this->readAttr( "kernelUnitLength" );
+ this->readAttr( "lighting-color" );
+}
+
+/**
+ * Drops any allocated memory.
+ */
+void SPFeSpecularLighting::release() {
+ SPFilterPrimitive::release();
+}
+
+/**
+ * Sets a specific value in the SPFeSpecularLighting.
+ */
+void SPFeSpecularLighting::set(SPAttributeEnum key, gchar const *value) {
+ gchar const *cend_ptr = nullptr;
+ gchar *end_ptr = nullptr;
+
+ switch(key) {
+ /*DEAL WITH SETTING ATTRIBUTES HERE*/
+//TODO test forbidden values
+ case SP_ATTR_SURFACESCALE:
+ end_ptr = nullptr;
+ if (value) {
+ this->surfaceScale = g_ascii_strtod(value, &end_ptr);
+ if (end_ptr) {
+ this->surfaceScale_set = TRUE;
+ } else {
+ g_warning("this: surfaceScale should be a number ... defaulting to 1");
+ }
+
+ }
+ //if the attribute is not set or has an unreadable value
+ if (!value || !end_ptr) {
+ this->surfaceScale = 1;
+ this->surfaceScale_set = FALSE;
+ }
+ if (this->renderer) {
+ this->renderer->surfaceScale = this->surfaceScale;
+ }
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ break;
+ case SP_ATTR_SPECULARCONSTANT:
+ end_ptr = nullptr;
+ if (value) {
+ this->specularConstant = g_ascii_strtod(value, &end_ptr);
+ if (end_ptr && this->specularConstant >= 0) {
+ this->specularConstant_set = TRUE;
+ } else {
+ end_ptr = nullptr;
+ g_warning("this: specularConstant should be a positive number ... defaulting to 1");
+ }
+ }
+ if (!value || !end_ptr) {
+ this->specularConstant = 1;
+ this->specularConstant_set = FALSE;
+ }
+ if (this->renderer) {
+ this->renderer->specularConstant = this->specularConstant;
+ }
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ break;
+ case SP_ATTR_SPECULAREXPONENT:
+ end_ptr = nullptr;
+ if (value) {
+ this->specularExponent = g_ascii_strtod(value, &end_ptr);
+ if (this->specularExponent >= 1 && this->specularExponent <= 128) {
+ this->specularExponent_set = TRUE;
+ } else {
+ end_ptr = nullptr;
+ g_warning("this: specularExponent should be a number in range [1, 128] ... defaulting to 1");
+ }
+ }
+ if (!value || !end_ptr) {
+ this->specularExponent = 1;
+ this->specularExponent_set = FALSE;
+ }
+ if (this->renderer) {
+ this->renderer->specularExponent = this->specularExponent;
+ }
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ break;
+ case SP_ATTR_KERNELUNITLENGTH:
+ //TODO kernelUnit
+ //this->kernelUnitLength.set(value);
+ /*TODOif (feSpecularLighting->renderer) {
+ feSpecularLighting->renderer->surfaceScale = feSpecularLighting->renderer;
+ }
+ */
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ break;
+ case SP_PROP_LIGHTING_COLOR:
+ cend_ptr = nullptr;
+ this->lighting_color = sp_svg_read_color(value, &cend_ptr, 0xffffffff);
+ //if a value was read
+ if (cend_ptr) {
+ while (g_ascii_isspace(*cend_ptr)) {
+ ++cend_ptr;
+ }
+ if (strneq(cend_ptr, "icc-color(", 10)) {
+ if (!this->icc) this->icc = new SVGICCColor();
+ if ( ! sp_svg_read_icc_color( cend_ptr, this->icc ) ) {
+ delete this->icc;
+ this->icc = nullptr;
+ }
+ }
+ this->lighting_color_set = TRUE;
+ } else {
+ //lighting_color already contains the default value
+ this->lighting_color_set = FALSE;
+ }
+ if (this->renderer) {
+ this->renderer->lighting_color = this->lighting_color;
+ }
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ break;
+ default:
+ SPFilterPrimitive::set(key, value);
+ break;
+ }
+}
+
+/**
+ * Receives update notifications.
+ */
+void SPFeSpecularLighting::update(SPCtx *ctx, guint flags) {
+ if (flags & (SP_OBJECT_MODIFIED_FLAG)) {
+ this->readAttr( "surfaceScale" );
+ this->readAttr( "specularConstant" );
+ this->readAttr( "specularExponent" );
+ this->readAttr( "kernelUnitLength" );
+ this->readAttr( "lighting-color" );
+ }
+
+ SPFilterPrimitive::update(ctx, flags);
+}
+
+/**
+ * Writes its settings to an incoming repr object, if any.
+ */
+Inkscape::XML::Node* SPFeSpecularLighting::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) {
+ /* TODO: Don't just clone, but create a new repr node and write all
+ * relevant values _and children_ into it */
+ if (!repr) {
+ repr = this->getRepr()->duplicate(doc);
+ //repr = doc->createElement("svg:feSpecularLighting");
+ }
+
+ if (this->surfaceScale_set) {
+ sp_repr_set_css_double(repr, "surfaceScale", this->surfaceScale);
+ }
+
+ if (this->specularConstant_set) {
+ sp_repr_set_css_double(repr, "specularConstant", this->specularConstant);
+ }
+
+ if (this->specularExponent_set) {
+ sp_repr_set_css_double(repr, "specularExponent", this->specularExponent);
+ }
+
+ /*TODO kernelUnits */
+ if (this->lighting_color_set) {
+ gchar c[64];
+ sp_svg_write_color(c, sizeof(c), this->lighting_color);
+ repr->setAttribute("lighting-color", c);
+ }
+
+ SPFilterPrimitive::write(doc, repr, flags);
+
+ return repr;
+}
+
+/**
+ * Callback for child_added event.
+ */
+void SPFeSpecularLighting::child_added(Inkscape::XML::Node *child, Inkscape::XML::Node *ref) {
+ SPFilterPrimitive::child_added(child, ref);
+
+ sp_feSpecularLighting_children_modified(this);
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+}
+
+/**
+ * Callback for remove_child event.
+ */
+void SPFeSpecularLighting::remove_child(Inkscape::XML::Node *child) {
+ SPFilterPrimitive::remove_child(child);
+
+ sp_feSpecularLighting_children_modified(this);
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+}
+
+void SPFeSpecularLighting::order_changed(Inkscape::XML::Node *child, Inkscape::XML::Node *old_ref, Inkscape::XML::Node *new_ref) {
+ SPFilterPrimitive::order_changed(child, old_ref, new_ref);
+
+ sp_feSpecularLighting_children_modified(this);
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+}
+
+static void sp_feSpecularLighting_children_modified(SPFeSpecularLighting *sp_specularlighting) {
+ if (sp_specularlighting->renderer) {
+ sp_specularlighting->renderer->light_type = Inkscape::Filters::NO_LIGHT;
+
+ if (SP_IS_FEDISTANTLIGHT(sp_specularlighting->firstChild())) {
+ sp_specularlighting->renderer->light_type = Inkscape::Filters::DISTANT_LIGHT;
+ sp_specularlighting->renderer->light.distant = SP_FEDISTANTLIGHT(sp_specularlighting->firstChild());
+ }
+
+ if (SP_IS_FEPOINTLIGHT(sp_specularlighting->firstChild())) {
+ sp_specularlighting->renderer->light_type = Inkscape::Filters::POINT_LIGHT;
+ sp_specularlighting->renderer->light.point = SP_FEPOINTLIGHT(sp_specularlighting->firstChild());
+ }
+
+ if (SP_IS_FESPOTLIGHT(sp_specularlighting->firstChild())) {
+ sp_specularlighting->renderer->light_type = Inkscape::Filters::SPOT_LIGHT;
+ sp_specularlighting->renderer->light.spot = SP_FESPOTLIGHT(sp_specularlighting->firstChild());
+ }
+ }
+}
+
+void SPFeSpecularLighting::build_renderer(Inkscape::Filters::Filter* filter) {
+ g_assert(filter != nullptr);
+
+ int primitive_n = filter->add_primitive(Inkscape::Filters::NR_FILTER_SPECULARLIGHTING);
+ Inkscape::Filters::FilterPrimitive *nr_primitive = filter->get_primitive(primitive_n);
+ Inkscape::Filters::FilterSpecularLighting *nr_specularlighting = dynamic_cast<Inkscape::Filters::FilterSpecularLighting*>(nr_primitive);
+ g_assert(nr_specularlighting != nullptr);
+
+ this->renderer = nr_specularlighting;
+ this->renderer_common(nr_primitive);
+
+ nr_specularlighting->specularConstant = this->specularConstant;
+ nr_specularlighting->specularExponent = this->specularExponent;
+ nr_specularlighting->surfaceScale = this->surfaceScale;
+ nr_specularlighting->lighting_color = this->lighting_color;
+ nr_specularlighting->set_icc(this->icc);
+
+ //We assume there is at most one child
+ nr_specularlighting->light_type = Inkscape::Filters::NO_LIGHT;
+
+ if (SP_IS_FEDISTANTLIGHT(this->firstChild())) {
+ nr_specularlighting->light_type = Inkscape::Filters::DISTANT_LIGHT;
+ nr_specularlighting->light.distant = SP_FEDISTANTLIGHT(this->firstChild());
+ }
+
+ if (SP_IS_FEPOINTLIGHT(this->firstChild())) {
+ nr_specularlighting->light_type = Inkscape::Filters::POINT_LIGHT;
+ nr_specularlighting->light.point = SP_FEPOINTLIGHT(this->firstChild());
+ }
+
+ if (SP_IS_FESPOTLIGHT(this->firstChild())) {
+ nr_specularlighting->light_type = Inkscape::Filters::SPOT_LIGHT;
+ nr_specularlighting->light.spot = SP_FESPOTLIGHT(this->firstChild());
+ }
+
+ //nr_offset->set_dx(sp_offset->dx);
+ //nr_offset->set_dy(sp_offset->dy);
+}
+
+
+/*
+ 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:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/specularlighting.h b/src/object/filters/specularlighting.h
new file mode 100644
index 0000000..427cbce
--- /dev/null
+++ b/src/object/filters/specularlighting.h
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** @file
+ * @brief SVG specular lighting filter effect
+ *//*
+ * Authors:
+ * Hugo Rodrigues <haa.rodrigues@gmail.com>
+ * Jean-Rene Reinhard <jr@komite.net>
+ *
+ * Copyright (C) 2006 Hugo Rodrigues
+ * 2007 authors
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#ifndef SP_FESPECULARLIGHTING_H_SEEN
+#define SP_FESPECULARLIGHTING_H_SEEN
+
+#include "sp-filter-primitive.h"
+#include "number-opt-number.h"
+
+#define SP_FESPECULARLIGHTING(obj) (dynamic_cast<SPFeSpecularLighting*>((SPObject*)obj))
+#define SP_IS_FESPECULARLIGHTING(obj) (dynamic_cast<const SPFeSpecularLighting*>((SPObject*)obj) != NULL)
+
+struct SVGICCColor;
+
+namespace Inkscape {
+namespace Filters {
+class FilterSpecularLighting;
+}
+}
+
+class SPFeSpecularLighting : public SPFilterPrimitive {
+public:
+ SPFeSpecularLighting();
+ ~SPFeSpecularLighting() override;
+
+ gfloat surfaceScale;
+ guint surfaceScale_set : 1;
+ gfloat specularConstant;
+ guint specularConstant_set : 1;
+ gfloat specularExponent;
+ guint specularExponent_set : 1;
+ NumberOptNumber kernelUnitLength;
+ guint32 lighting_color;
+ guint lighting_color_set : 1;
+ SVGICCColor *icc;
+
+ Inkscape::Filters::FilterSpecularLighting *renderer;
+
+protected:
+ void build(SPDocument* doc, Inkscape::XML::Node* repr) override;
+ void release() override;
+
+ void child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref) override;
+ void remove_child(Inkscape::XML::Node* child) override;
+
+ void order_changed(Inkscape::XML::Node* child, Inkscape::XML::Node* old_repr, Inkscape::XML::Node* new_repr) override;
+
+ void set(SPAttributeEnum key, const gchar* value) override;
+
+ void update(SPCtx* ctx, unsigned int flags) override;
+
+ Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags) override;
+
+ void build_renderer(Inkscape::Filters::Filter* filter) override;
+};
+
+#endif /* !SP_FESPECULARLIGHTING_H_SEEN */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/spotlight.cpp b/src/object/filters/spotlight.cpp
new file mode 100644
index 0000000..dcc71b7
--- /dev/null
+++ b/src/object/filters/spotlight.cpp
@@ -0,0 +1,320 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** \file
+ * SVG <fespotlight> implementation.
+ */
+/*
+ * Authors:
+ * Hugo Rodrigues <haa.rodrigues@gmail.com>
+ * Niko Kiirala <niko@kiirala.com>
+ * Jean-Rene Reinhard <jr@komite.net>
+ * Abhishek Sharma
+ *
+ * Copyright (C) 2006,2007 Authors
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+// Same directory
+#include "spotlight.h"
+#include "diffuselighting.h"
+#include "specularlighting.h"
+
+#include "attributes.h"
+#include "document.h"
+
+#include "xml/repr.h"
+
+SPFeSpotLight::SPFeSpotLight()
+ : SPObject(), x(0), x_set(FALSE), y(0), y_set(FALSE), z(0), z_set(FALSE), pointsAtX(0), pointsAtX_set(FALSE),
+ pointsAtY(0), pointsAtY_set(FALSE), pointsAtZ(0), pointsAtZ_set(FALSE),
+ specularExponent(1), specularExponent_set(FALSE), limitingConeAngle(90),
+ limitingConeAngle_set(FALSE)
+{
+}
+
+SPFeSpotLight::~SPFeSpotLight() = default;
+
+
+/**
+ * Reads the Inkscape::XML::Node, and initializes SPPointLight variables. For this to get called,
+ * our name must be associated with a repr via "sp_object_type_register". Best done through
+ * sp-object-repr.cpp's repr_name_entries array.
+ */
+void SPFeSpotLight::build(SPDocument *document, Inkscape::XML::Node *repr) {
+ SPObject::build(document, repr);
+
+ //Read values of key attributes from XML nodes into object.
+ this->readAttr( "x" );
+ this->readAttr( "y" );
+ this->readAttr( "z" );
+ this->readAttr( "pointsAtX" );
+ this->readAttr( "pointsAtY" );
+ this->readAttr( "pointsAtZ" );
+ this->readAttr( "specularExponent" );
+ this->readAttr( "limitingConeAngle" );
+
+//is this necessary?
+ document->addResource("fespotlight", this);
+}
+
+/**
+ * Drops any allocated memory.
+ */
+void SPFeSpotLight::release() {
+ if ( this->document ) {
+ // Unregister ourselves
+ this->document->removeResource("fespotlight", this);
+ }
+
+//TODO: release resources here
+}
+
+/**
+ * Sets a specific value in the SPFeSpotLight.
+ */
+void SPFeSpotLight::set(SPAttributeEnum key, gchar const *value) {
+ gchar *end_ptr;
+
+ switch (key) {
+ case SP_ATTR_X:
+ end_ptr = nullptr;
+
+ if (value) {
+ this->x = g_ascii_strtod(value, &end_ptr);
+
+ if (end_ptr) {
+ this->x_set = TRUE;
+ }
+ }
+
+ if(!value || !end_ptr) {
+ this->x = 0;
+ this->x_set = FALSE;
+ }
+
+ if (this->parent &&
+ (SP_IS_FEDIFFUSELIGHTING(this->parent) ||
+ SP_IS_FESPECULARLIGHTING(this->parent))) {
+ this->parent->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ case SP_ATTR_Y:
+ end_ptr = nullptr;
+
+ if (value) {
+ this->y = g_ascii_strtod(value, &end_ptr);
+
+ if (end_ptr) {
+ this->y_set = TRUE;
+ }
+ }
+
+ if(!value || !end_ptr) {
+ this->y = 0;
+ this->y_set = FALSE;
+ }
+
+ if (this->parent &&
+ (SP_IS_FEDIFFUSELIGHTING(this->parent) ||
+ SP_IS_FESPECULARLIGHTING(this->parent))) {
+ this->parent->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ case SP_ATTR_Z:
+ end_ptr = nullptr;
+
+ if (value) {
+ this->z = g_ascii_strtod(value, &end_ptr);
+
+ if (end_ptr) {
+ this->z_set = TRUE;
+ }
+ }
+
+ if(!value || !end_ptr) {
+ this->z = 0;
+ this->z_set = FALSE;
+ }
+
+ if (this->parent &&
+ (SP_IS_FEDIFFUSELIGHTING(this->parent) ||
+ SP_IS_FESPECULARLIGHTING(this->parent))) {
+ this->parent->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ case SP_ATTR_POINTSATX:
+ end_ptr = nullptr;
+
+ if (value) {
+ this->pointsAtX = g_ascii_strtod(value, &end_ptr);
+
+ if (end_ptr) {
+ this->pointsAtX_set = TRUE;
+ }
+ }
+
+ if(!value || !end_ptr) {
+ this->pointsAtX = 0;
+ this->pointsAtX_set = FALSE;
+ }
+
+ if (this->parent &&
+ (SP_IS_FEDIFFUSELIGHTING(this->parent) ||
+ SP_IS_FESPECULARLIGHTING(this->parent))) {
+ this->parent->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ case SP_ATTR_POINTSATY:
+ end_ptr = nullptr;
+
+ if (value) {
+ this->pointsAtY = g_ascii_strtod(value, &end_ptr);
+
+ if (end_ptr) {
+ this->pointsAtY_set = TRUE;
+ }
+ }
+
+ if(!value || !end_ptr) {
+ this->pointsAtY = 0;
+ this->pointsAtY_set = FALSE;
+ }
+
+ if (this->parent &&
+ (SP_IS_FEDIFFUSELIGHTING(this->parent) ||
+ SP_IS_FESPECULARLIGHTING(this->parent))) {
+ this->parent->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ case SP_ATTR_POINTSATZ:
+ end_ptr = nullptr;
+
+ if (value) {
+ this->pointsAtZ = g_ascii_strtod(value, &end_ptr);
+
+ if (end_ptr) {
+ this->pointsAtZ_set = TRUE;
+ }
+ }
+
+ if(!value || !end_ptr) {
+ this->pointsAtZ = 0;
+ this->pointsAtZ_set = FALSE;
+ }
+
+ if (this->parent &&
+ (SP_IS_FEDIFFUSELIGHTING(this->parent) ||
+ SP_IS_FESPECULARLIGHTING(this->parent))) {
+ this->parent->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ case SP_ATTR_SPECULAREXPONENT:
+ end_ptr = nullptr;
+
+ if (value) {
+ this->specularExponent = g_ascii_strtod(value, &end_ptr);
+
+ if (end_ptr) {
+ this->specularExponent_set = TRUE;
+ }
+ }
+
+ if(!value || !end_ptr) {
+ this->specularExponent = 1;
+ this->specularExponent_set = FALSE;
+ }
+
+ if (this->parent &&
+ (SP_IS_FEDIFFUSELIGHTING(this->parent) ||
+ SP_IS_FESPECULARLIGHTING(this->parent))) {
+ this->parent->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ case SP_ATTR_LIMITINGCONEANGLE:
+ end_ptr = nullptr;
+
+ if (value) {
+ this->limitingConeAngle = g_ascii_strtod(value, &end_ptr);
+
+ if (end_ptr) {
+ this->limitingConeAngle_set = TRUE;
+ }
+ }
+
+ if(!value || !end_ptr) {
+ this->limitingConeAngle = 90;
+ this->limitingConeAngle_set = FALSE;
+ }
+
+ if (this->parent &&
+ (SP_IS_FEDIFFUSELIGHTING(this->parent) ||
+ SP_IS_FESPECULARLIGHTING(this->parent))) {
+ this->parent->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ default:
+ // See if any parents need this value.
+ SPObject::set(key, value);
+ break;
+ }
+}
+
+/**
+ * * Receives update notifications.
+ * */
+void SPFeSpotLight::update(SPCtx *ctx, guint flags) {
+ if (flags & SP_OBJECT_MODIFIED_FLAG) {
+ /* do something to trigger redisplay, updates? */
+ this->readAttr( "x" );
+ this->readAttr( "y" );
+ this->readAttr( "z" );
+ this->readAttr( "pointsAtX" );
+ this->readAttr( "pointsAtY" );
+ this->readAttr( "pointsAtZ" );
+ this->readAttr( "specularExponent" );
+ this->readAttr( "limitingConeAngle" );
+ }
+
+ SPObject::update(ctx, flags);
+}
+
+/**
+ * Writes its settings to an incoming repr object, if any.
+ */
+Inkscape::XML::Node* SPFeSpotLight::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) {
+ if (!repr) {
+ repr = this->getRepr()->duplicate(doc);
+ }
+
+ if (this->x_set)
+ sp_repr_set_css_double(repr, "x", this->x);
+ if (this->y_set)
+ sp_repr_set_css_double(repr, "y", this->y);
+ if (this->z_set)
+ sp_repr_set_css_double(repr, "z", this->z);
+ if (this->pointsAtX_set)
+ sp_repr_set_css_double(repr, "pointsAtX", this->pointsAtX);
+ if (this->pointsAtY_set)
+ sp_repr_set_css_double(repr, "pointsAtY", this->pointsAtY);
+ if (this->pointsAtZ_set)
+ sp_repr_set_css_double(repr, "pointsAtZ", this->pointsAtZ);
+ if (this->specularExponent_set)
+ sp_repr_set_css_double(repr, "specularExponent", this->specularExponent);
+ if (this->limitingConeAngle_set)
+ sp_repr_set_css_double(repr, "limitingConeAngle", this->limitingConeAngle);
+
+ SPObject::write(doc, repr, flags);
+
+ return repr;
+}
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/spotlight.h b/src/object/filters/spotlight.h
new file mode 100644
index 0000000..2169124
--- /dev/null
+++ b/src/object/filters/spotlight.h
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#ifndef SP_FESPOTLIGHT_H_SEEN
+#define SP_FESPOTLIGHT_H_SEEN
+
+/** \file
+ * SVG <filter> implementation, see sp-filter.cpp.
+ */
+/*
+ * Authors:
+ * Hugo Rodrigues <haa.rodrigues@gmail.com>
+ * Niko Kiirala <niko@kiirala.com>
+ * Jean-Rene Reinhard <jr@komite.net>
+ *
+ * Copyright (C) 2006,2007 Authors
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include "object/sp-object.h"
+
+#define SP_FESPOTLIGHT(obj) (dynamic_cast<SPFeSpotLight*>((SPObject*)obj))
+#define SP_IS_FESPOTLIGHT(obj) (dynamic_cast<const SPFeSpotLight*>((SPObject*)obj) != NULL)
+
+class SPFeSpotLight : public SPObject {
+public:
+ SPFeSpotLight();
+ ~SPFeSpotLight() override;
+
+ /** x coordinate of the light source */
+ float x;
+ unsigned int x_set : 1;
+ /** y coordinate of the light source */
+ float y;
+ unsigned int y_set : 1;
+ /** z coordinate of the light source */
+ float z;
+ unsigned int z_set : 1;
+ /** x coordinate of the point the source is pointing at */
+ float pointsAtX;
+ unsigned int pointsAtX_set : 1;
+ /** y coordinate of the point the source is pointing at */
+ float pointsAtY;
+ unsigned int pointsAtY_set : 1;
+ /** z coordinate of the point the source is pointing at */
+ float pointsAtZ;
+ unsigned int pointsAtZ_set : 1;
+ /** specular exponent (focus of the light) */
+ float specularExponent;
+ unsigned int specularExponent_set : 1;
+ /** limiting cone angle */
+ float limitingConeAngle;
+ unsigned int limitingConeAngle_set : 1;
+ //other fields
+
+protected:
+ void build(SPDocument* doc, Inkscape::XML::Node* repr) override;
+ void release() override;
+
+ void set(SPAttributeEnum key, char const* value) override;
+
+ void update(SPCtx* ctx, unsigned int flags) override;
+
+ Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, unsigned int flags) override;
+};
+
+#endif /* !SP_FESPOTLIGHT_H_SEEN */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/tile.cpp b/src/object/filters/tile.cpp
new file mode 100644
index 0000000..b8a22b8
--- /dev/null
+++ b/src/object/filters/tile.cpp
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** \file
+ * SVG <feTile> implementation.
+ *
+ */
+/*
+ * Authors:
+ * hugo Rodrigues <haa.rodrigues@gmail.com>
+ *
+ * Copyright (C) 2006 Hugo Rodrigues
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include "tile.h"
+
+#include "attributes.h"
+
+#include "display/nr-filter.h"
+#include "display/nr-filter-tile.h"
+
+#include "svg/svg.h"
+
+#include "xml/repr.h"
+
+SPFeTile::SPFeTile() : SPFilterPrimitive() {
+}
+
+SPFeTile::~SPFeTile() = default;
+
+/**
+ * Reads the Inkscape::XML::Node, and initializes SPFeTile variables. For this to get called,
+ * our name must be associated with a repr via "sp_object_type_register". Best done through
+ * sp-object-repr.cpp's repr_name_entries array.
+ */
+void SPFeTile::build(SPDocument *document, Inkscape::XML::Node *repr) {
+ SPFilterPrimitive::build(document, repr);
+}
+
+/**
+ * Drops any allocated memory.
+ */
+void SPFeTile::release() {
+ SPFilterPrimitive::release();
+}
+
+/**
+ * Sets a specific value in the SPFeTile.
+ */
+void SPFeTile::set(SPAttributeEnum key, gchar const *value) {
+ switch(key) {
+ /*DEAL WITH SETTING ATTRIBUTES HERE*/
+ default:
+ SPFilterPrimitive::set(key, value);
+ break;
+ }
+}
+
+/**
+ * Receives update notifications.
+ */
+void SPFeTile::update(SPCtx *ctx, guint flags) {
+ if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG |
+ SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
+
+ /* do something to trigger redisplay, updates? */
+
+ }
+
+ SPFilterPrimitive::update(ctx, flags);
+}
+
+/**
+ * Writes its settings to an incoming repr object, if any.
+ */
+Inkscape::XML::Node* SPFeTile::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) {
+ /* TODO: Don't just clone, but create a new repr node and write all
+ * relevant values into it */
+ if (!repr) {
+ repr = this->getRepr()->duplicate(doc);
+ }
+
+ SPFilterPrimitive::write(doc, repr, flags);
+
+ return repr;
+}
+
+void SPFeTile::build_renderer(Inkscape::Filters::Filter* filter) {
+ g_assert(filter != nullptr);
+
+ int primitive_n = filter->add_primitive(Inkscape::Filters::NR_FILTER_TILE);
+ Inkscape::Filters::FilterPrimitive *nr_primitive = filter->get_primitive(primitive_n);
+ Inkscape::Filters::FilterTile *nr_tile = dynamic_cast<Inkscape::Filters::FilterTile*>(nr_primitive);
+ g_assert(nr_tile != nullptr);
+
+ this->renderer_common(nr_primitive);
+}
+
+/*
+ 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:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/tile.h b/src/object/filters/tile.h
new file mode 100644
index 0000000..1f18c61
--- /dev/null
+++ b/src/object/filters/tile.h
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** @file
+ * @brief SVG tile filter effect
+ *//*
+ * Authors:
+ * Hugo Rodrigues <haa.rodrigues@gmail.com>
+ *
+ * Copyright (C) 2006 Hugo Rodrigues
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#ifndef SP_FETILE_H_SEEN
+#define SP_FETILE_H_SEEN
+
+#include "sp-filter-primitive.h"
+
+#define SP_FETILE(obj) (dynamic_cast<SPFeTile*>((SPObject*)obj))
+#define SP_IS_FETILE(obj) (dynamic_cast<const SPFeTile*>((SPObject*)obj) != NULL)
+
+/* FeTile base class */
+class SPFeTile : public SPFilterPrimitive {
+public:
+ SPFeTile();
+ ~SPFeTile() override;
+
+protected:
+ void build(SPDocument* doc, Inkscape::XML::Node* repr) override;
+ void release() override;
+
+ void set(SPAttributeEnum key, const gchar* value) override;
+
+ void update(SPCtx* ctx, unsigned int flags) override;
+
+ Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags) override;
+
+ void build_renderer(Inkscape::Filters::Filter* filter) override;
+};
+
+#endif /* !SP_FETILE_H_SEEN */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/turbulence.cpp b/src/object/filters/turbulence.cpp
new file mode 100644
index 0000000..d1221f4
--- /dev/null
+++ b/src/object/filters/turbulence.cpp
@@ -0,0 +1,229 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** \file
+ * SVG <feTurbulence> implementation.
+ *
+ */
+/*
+ * Authors:
+ * Felipe Corrêa da Silva Sanches <juca@members.fsf.org>
+ * hugo Rodrigues <haa.rodrigues@gmail.com>
+ * Abhishek Sharma
+ *
+ * Copyright (C) 2007 Felipe Sanches
+ * Copyright (C) 2006 Hugo Rodrigues
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include "attributes.h"
+#include "svg/svg.h"
+#include "turbulence.h"
+#include "helper-fns.h"
+#include "xml/repr.h"
+
+#include "display/nr-filter.h"
+
+SPFeTurbulence::SPFeTurbulence() : SPFilterPrimitive() {
+ this->stitchTiles = false;
+ this->seed = 0;
+ this->numOctaves = 0;
+ this->type = Inkscape::Filters::TURBULENCE_FRACTALNOISE;
+
+ this->updated=false;
+}
+
+SPFeTurbulence::~SPFeTurbulence() = default;
+
+/**
+ * Reads the Inkscape::XML::Node, and initializes SPFeTurbulence variables. For this to get called,
+ * our name must be associated with a repr via "sp_object_type_register". Best done through
+ * sp-object-repr.cpp's repr_name_entries array.
+ */
+void SPFeTurbulence::build(SPDocument *document, Inkscape::XML::Node *repr) {
+ SPFilterPrimitive::build(document, repr);
+
+ /*LOAD ATTRIBUTES FROM REPR HERE*/
+ this->readAttr( "baseFrequency" );
+ this->readAttr( "numOctaves" );
+ this->readAttr( "seed" );
+ this->readAttr( "stitchTiles" );
+ this->readAttr( "type" );
+}
+
+/**
+ * Drops any allocated memory.
+ */
+void SPFeTurbulence::release() {
+ SPFilterPrimitive::release();
+}
+
+static bool sp_feTurbulence_read_stitchTiles(gchar const *value){
+ if (!value) {
+ return false; // 'noStitch' is default
+ }
+
+ switch(value[0]){
+ case 's':
+ if (strncmp(value, "stitch", 6) == 0) {
+ return true;
+ }
+ break;
+ case 'n':
+ if (strncmp(value, "noStitch", 8) == 0) {
+ return false;
+ }
+ break;
+ }
+
+ return false; // 'noStitch' is default
+}
+
+static Inkscape::Filters::FilterTurbulenceType sp_feTurbulence_read_type(gchar const *value){
+ if (!value) {
+ return Inkscape::Filters::TURBULENCE_TURBULENCE; // 'turbulence' is default
+ }
+
+ switch(value[0]){
+ case 'f':
+ if (strncmp(value, "fractalNoise", 12) == 0) {
+ return Inkscape::Filters::TURBULENCE_FRACTALNOISE;
+ }
+ break;
+ case 't':
+ if (strncmp(value, "turbulence", 10) == 0) {
+ return Inkscape::Filters::TURBULENCE_TURBULENCE;
+ }
+ break;
+ }
+
+ return Inkscape::Filters::TURBULENCE_TURBULENCE; // 'turbulence' is default
+}
+
+/**
+ * Sets a specific value in the SPFeTurbulence.
+ */
+void SPFeTurbulence::set(SPAttributeEnum key, gchar const *value) {
+ int read_int;
+ double read_num;
+ bool read_bool;
+ Inkscape::Filters::FilterTurbulenceType read_type;
+
+ switch(key) {
+ /*DEAL WITH SETTING ATTRIBUTES HERE*/
+ case SP_ATTR_BASEFREQUENCY:
+ this->baseFrequency.set(value);
+
+ // From SVG spec: If two <number>s are provided, the first number represents
+ // a base frequency in the X direction and the second value represents a base
+ // frequency in the Y direction. If one number is provided, then that value is
+ // used for both X and Y.
+ if (this->baseFrequency.optNumIsSet() == false) {
+ this->baseFrequency.setOptNumber(this->baseFrequency.getNumber());
+ }
+
+ this->updated = false;
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ break;
+ case SP_ATTR_NUMOCTAVES:
+ read_int = value ? (int)floor(helperfns_read_number(value)) : 1;
+
+ if (read_int != this->numOctaves){
+ this->numOctaves = read_int;
+ this->updated = false;
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ case SP_ATTR_SEED:
+ read_num = value ? helperfns_read_number(value) : 0;
+
+ if (read_num != this->seed){
+ this->seed = read_num;
+ this->updated = false;
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ case SP_ATTR_STITCHTILES:
+ read_bool = sp_feTurbulence_read_stitchTiles(value);
+
+ if (read_bool != this->stitchTiles){
+ this->stitchTiles = read_bool;
+ this->updated = false;
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ case SP_ATTR_TYPE:
+ read_type = sp_feTurbulence_read_type(value);
+
+ if (read_type != this->type){
+ this->type = read_type;
+ this->updated = false;
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ default:
+ SPFilterPrimitive::set(key, value);
+ break;
+ }
+}
+
+/**
+ * Receives update notifications.
+ */
+void SPFeTurbulence::update(SPCtx *ctx, guint flags) {
+ if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG |
+ SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
+
+ /* do something to trigger redisplay, updates? */
+
+ }
+
+ SPFilterPrimitive::update(ctx, flags);
+}
+
+/**
+ * Writes its settings to an incoming repr object, if any.
+ */
+Inkscape::XML::Node* SPFeTurbulence::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) {
+ /* TODO: Don't just clone, but create a new repr node and write all
+ * relevant values into it */
+ if (!repr) {
+ repr = this->getRepr()->duplicate(doc);
+ }
+
+ SPFilterPrimitive::write(doc, repr, flags);
+
+ /* turbulence doesn't take input */
+ repr->removeAttribute("in");
+
+ return repr;
+}
+
+void SPFeTurbulence::build_renderer(Inkscape::Filters::Filter* filter) {
+ g_assert(filter != nullptr);
+
+ int primitive_n = filter->add_primitive(Inkscape::Filters::NR_FILTER_TURBULENCE);
+ Inkscape::Filters::FilterPrimitive *nr_primitive = filter->get_primitive(primitive_n);
+ Inkscape::Filters::FilterTurbulence *nr_turbulence = dynamic_cast<Inkscape::Filters::FilterTurbulence*>(nr_primitive);
+ g_assert(nr_turbulence != nullptr);
+
+ this->renderer_common(nr_primitive);
+
+ nr_turbulence->set_baseFrequency(0, this->baseFrequency.getNumber());
+ nr_turbulence->set_baseFrequency(1, this->baseFrequency.getOptNumber());
+ nr_turbulence->set_numOctaves(this->numOctaves);
+ nr_turbulence->set_seed(this->seed);
+ nr_turbulence->set_stitchTiles(this->stitchTiles);
+ nr_turbulence->set_type(this->type);
+ nr_turbulence->set_updated(this->updated);
+}
+
+/*
+ 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:fileencoding=utf-8:textwidth=99 :
diff --git a/src/object/filters/turbulence.h b/src/object/filters/turbulence.h
new file mode 100644
index 0000000..c43e322
--- /dev/null
+++ b/src/object/filters/turbulence.h
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** @file
+ * @brief SVG turbulence filter effect
+ *//*
+ * Authors:
+ * Felipe Corrêa da Silva Sanches <juca@members.fsf.org>
+ * Hugo Rodrigues <haa.rodrigues@gmail.com>
+ *
+ * Copyright (C) 2006 Hugo Rodrigues
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#ifndef SP_FETURBULENCE_H_SEEN
+#define SP_FETURBULENCE_H_SEEN
+
+#include "sp-filter-primitive.h"
+#include "number-opt-number.h"
+#include "display/nr-filter-turbulence.h"
+
+#define SP_FETURBULENCE(obj) (dynamic_cast<SPFeTurbulence*>((SPObject*)obj))
+#define SP_IS_FETURBULENCE(obj) (dynamic_cast<const SPFeTurbulence*>((SPObject*)obj) != NULL)
+
+/* FeTurbulence base class */
+
+class SPFeTurbulence : public SPFilterPrimitive {
+public:
+ SPFeTurbulence();
+ ~SPFeTurbulence() override;
+
+ /** TURBULENCE ATTRIBUTES HERE */
+ NumberOptNumber baseFrequency;
+ int numOctaves;
+ double seed;
+ bool stitchTiles;
+ Inkscape::Filters::FilterTurbulenceType type;
+ SVGLength x, y, height, width;
+ bool updated;
+
+protected:
+ void build(SPDocument* doc, Inkscape::XML::Node* repr) override;
+ void release() override;
+
+ void set(SPAttributeEnum key, const gchar* value) override;
+
+ void update(SPCtx* ctx, unsigned int flags) override;
+
+ Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags) override;
+
+ void build_renderer(Inkscape::Filters::Filter* filter) override;
+};
+
+#endif /* !SP_FETURBULENCE_H_SEEN */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :