summaryrefslogtreecommitdiffstats
path: root/src/object/filters
diff options
context:
space:
mode:
Diffstat (limited to 'src/object/filters')
-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.cpp187
-rw-r--r--src/object/filters/colormatrix.h58
-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.cpp299
-rw-r--r--src/object/filters/composite.h67
-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.cpp150
-rw-r--r--src/object/filters/gaussian-blur.h59
-rw-r--r--src/object/filters/image.cpp271
-rw-r--r--src/object/filters/image.h71
-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.cpp185
-rw-r--r--src/object/filters/morphology.h56
-rw-r--r--src/object/filters/offset.cpp155
-rw-r--r--src/object/filters/offset.h54
-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.cpp282
-rw-r--r--src/object/filters/sp-filter-primitive.h78
-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, 6298 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..49a7cd8
--- /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(SPAttr::MODE);
+ this->readAttr(SPAttr::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(SPAttr key, gchar const *value) {
+ SPBlendMode mode;
+ int input;
+
+ switch(key) {
+ /*DEAL WITH SETTING ATTRIBUTES HERE*/
+ case SPAttr::MODE:
+ mode = sp_feBlend_readmode(value);
+
+ if (mode != this->blend_mode) {
+ this->blend_mode = mode;
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ case SPAttr::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(SPAttr::MODE);
+ this->readAttr(SPAttr::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..7eee986
--- /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(SPAttr 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..a429554
--- /dev/null
+++ b/src/object/filters/colormatrix.cpp
@@ -0,0 +1,187 @@
+// 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()
+{
+}
+
+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(SPAttr::TYPE);
+ this->readAttr(SPAttr::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(SPAttr key, gchar const *str) {
+ Inkscape::Filters::FilterColorMatrixType read_type;
+
+ /*DEAL WITH SETTING ATTRIBUTES HERE*/
+ switch(key) {
+ case SPAttr::TYPE:
+ read_type = sp_feColorMatrix_read_type(str);
+
+ if (this->type != read_type){
+ this->type = read_type;
+
+ // Set the default value of "value" (this may happen if the attribute "Type" is changed interactively).
+ if (!value_set) {
+ value = 0;
+ if (type == Inkscape::Filters::COLORMATRIX_SATURATE) {
+ value = 1;
+ }
+ }
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+
+ case SPAttr::VALUES:
+ if (str) {
+ this->values = helperfns_read_vector(str);
+ this->value = helperfns_read_number(str, HELPERFNS_NO_WARNING);
+ value_set = true;
+ } else {
+ // Set defaults
+ switch (type) {
+ case Inkscape::Filters::COLORMATRIX_MATRIX:
+ values = {1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0 };
+ break;
+ case Inkscape::Filters::COLORMATRIX_SATURATE:
+ // Default value for saturate is 1.0 ("values" not used).
+ value = 1.0;
+ break;
+ case Inkscape::Filters::COLORMATRIX_HUEROTATE:
+ value = 0.0;
+ break;
+ case Inkscape::Filters::COLORMATRIX_LUMINANCETOALPHA:
+ // value, values not used.
+ break;
+ }
+ value_set = false;
+ }
+ 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..72dfa19
--- /dev/null
+++ b/src/object/filters/colormatrix.h
@@ -0,0 +1,58 @@
+// 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 = Inkscape::Filters::COLORMATRIX_MATRIX;
+ double value = 0;
+ std::vector<double> values;
+
+private:
+ bool value_set = false;
+
+protected:
+ void build(SPDocument* doc, Inkscape::XML::Node* repr) override;
+ void release() override;
+
+ void set(SPAttr 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..d73fbee
--- /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(SPAttr::TYPE);
+ this->readAttr(SPAttr::TABLEVALUES);
+ this->readAttr(SPAttr::SLOPE);
+ this->readAttr(SPAttr::INTERCEPT);
+ this->readAttr(SPAttr::AMPLITUDE);
+ this->readAttr(SPAttr::EXPONENT);
+ this->readAttr(SPAttr::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(SPAttr key, gchar const *value) {
+ Inkscape::Filters::FilterComponentTransferType type;
+ double read_num;
+
+ switch(key) {
+ case SPAttr::TYPE:
+ type = sp_feComponenttransfer_read_type(value);
+
+ if(type != this->type) {
+ this->type = type;
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ case SPAttr::TABLEVALUES:
+ if (value){
+ this->tableValues = helperfns_read_vector(value);
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+ case SPAttr::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 SPAttr::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 SPAttr::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 SPAttr::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 SPAttr::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(SPAttr::TYPE);
+ this->readAttr(SPAttr::TABLEVALUES);
+ this->readAttr(SPAttr::SLOPE);
+ this->readAttr(SPAttr::INTERCEPT);
+ this->readAttr(SPAttr::AMPLITUDE);
+ this->readAttr(SPAttr::EXPONENT);
+ this->readAttr(SPAttr::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..d16aacc
--- /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(SPAttr 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..b194902
--- /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(SPAttr 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..b0930a4
--- /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(SPAttr 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..cfd4336
--- /dev/null
+++ b/src/object/filters/composite.cpp
@@ -0,0 +1,299 @@
+// 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(SPAttr::OPERATOR);
+
+ if (this->composite_operator == COMPOSITE_ARITHMETIC) {
+ this->readAttr(SPAttr::K1);
+ this->readAttr(SPAttr::K2);
+ this->readAttr(SPAttr::K3);
+ this->readAttr(SPAttr::K4);
+ }
+
+ this->readAttr(SPAttr::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;
+ } else if (strcmp(value, "lighter") == 0) {
+ return COMPOSITE_LIGHTER;
+ }
+ std::cout << "Inkscape::Filters::FilterCompositeOperator: Unimplemented operator: " << value << std::endl;
+
+ return COMPOSITE_DEFAULT;
+}
+
+/**
+ * Sets a specific value in the SPFeComposite.
+ */
+void SPFeComposite::set(SPAttr key, gchar const *value) {
+ int input;
+ FeCompositeOperator op;
+ double k_n;
+
+ switch(key) {
+ /*DEAL WITH SETTING ATTRIBUTES HERE*/
+ case SPAttr::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 SPAttr::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 SPAttr::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 SPAttr::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 SPAttr::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 SPAttr::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;
+ case COMPOSITE_LIGHTER:
+ comp_op = "lighter"; break;
+ default:
+ comp_op = nullptr;
+ }
+
+ repr->setAttribute("operator", comp_op);
+
+ if (this->composite_operator == COMPOSITE_ARITHMETIC) {
+ repr->setAttributeSvgDouble("k1", this->k1);
+ repr->setAttributeSvgDouble("k2", this->k2);
+ repr->setAttributeSvgDouble("k3", this->k3);
+ repr->setAttributeSvgDouble("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..2a19e28
--- /dev/null
+++ b/src/object/filters/composite.h
@@ -0,0 +1,67 @@
+// 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 distinguish 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 */
+ COMPOSITE_LIGHTER, /* Plus, Add (Not a fundamental PorterDuff operator */
+ 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(SPAttr 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..69a4172
--- /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(SPAttr::ORDER);
+ this->readAttr(SPAttr::KERNELMATRIX);
+ this->readAttr(SPAttr::DIVISOR);
+ this->readAttr(SPAttr::BIAS);
+ this->readAttr(SPAttr::TARGETX);
+ this->readAttr(SPAttr::TARGETY);
+ this->readAttr(SPAttr::EDGEMODE);
+ this->readAttr(SPAttr::KERNELUNITLENGTH);
+ this->readAttr(SPAttr::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(SPAttr 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 SPAttr::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 SPAttr::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 SPAttr::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 SPAttr::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 SPAttr::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 SPAttr::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 SPAttr::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 SPAttr::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 SPAttr::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..501e3c5
--- /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(SPAttr 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..4c3eb4d
--- /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(SPAttr::SURFACESCALE);
+ this->readAttr(SPAttr::DIFFUSECONSTANT);
+ this->readAttr(SPAttr::KERNELUNITLENGTH);
+ this->readAttr(SPAttr::LIGHTING_COLOR);
+}
+
+/**
+ * Drops any allocated memory.
+ */
+void SPFeDiffuseLighting::release() {
+ SPFilterPrimitive::release();
+}
+
+/**
+ * Sets a specific value in the SPFeDiffuseLighting.
+ */
+void SPFeDiffuseLighting::set(SPAttr 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 SPAttr::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 SPAttr::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 SPAttr::KERNELUNITLENGTH:
+ //TODO kernelUnit
+ //this->kernelUnitLength.set(value);
+ /*TODOif (feDiffuseLighting->renderer) {
+ feDiffuseLighting->renderer->surfaceScale = feDiffuseLighting->renderer;
+ }
+ */
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ break;
+ case SPAttr::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(SPAttr::SURFACESCALE);
+ this->readAttr(SPAttr::DIFFUSECONSTANT);
+ this->readAttr(SPAttr::KERNELUNITLENGTH);
+ this->readAttr(SPAttr::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) {
+ repr->setAttributeCssDouble("surfaceScale", this->surfaceScale);
+ } else {
+ repr->removeAttribute("surfaceScale");
+ }
+
+ if (this->diffuseConstant_set) {
+ repr->setAttributeCssDouble("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..23f6778
--- /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(SPAttr 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..41ce4d1
--- /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(SPAttr::SCALE);
+ this->readAttr(SPAttr::IN2);
+ this->readAttr(SPAttr::XCHANNELSELECTOR);
+ this->readAttr(SPAttr::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(SPAttr key, gchar const *value) {
+ int input;
+ double read_num;
+ FilterDisplacementMapChannelSelector read_selector;
+
+ switch(key) {
+ /*DEAL WITH SETTING ATTRIBUTES HERE*/
+ case SPAttr::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 SPAttr::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 SPAttr::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 SPAttr::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");
+ }
+
+ repr->setAttributeSvgDouble("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..27243dc
--- /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(SPAttr 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..b438e46
--- /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(SPAttr::AZIMUTH);
+ this->readAttr(SPAttr::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(SPAttr key, gchar const *value) {
+ gchar *end_ptr;
+
+ switch (key) {
+ case SPAttr::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 SPAttr::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(SPAttr::AZIMUTH);
+ this->readAttr(SPAttr::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) {
+ repr->setAttributeCssDouble("azimuth", this->azimuth);
+ }
+
+ if (this->elevation_set) {
+ repr->setAttributeCssDouble("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..c2f1f0a
--- /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(SPAttr 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..9e179bf
--- /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(SPAttr::FLOOD_OPACITY);
+ this->readAttr(SPAttr::FLOOD_COLOR);
+}
+
+/**
+ * Drops any allocated memory.
+ */
+void SPFeFlood::release() {
+ SPFilterPrimitive::release();
+}
+
+/**
+ * Sets a specific value in the SPFeFlood.
+ */
+void SPFeFlood::set(SPAttr 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 SPAttr::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 SPAttr::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..908fffd
--- /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(SPAttr 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..c8460d0
--- /dev/null
+++ b/src/object/filters/gaussian-blur.cpp
@@ -0,0 +1,150 @@
+// 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(SPAttr::STDDEVIATION);
+}
+
+/**
+ * Drops any allocated memory.
+ */
+void SPGaussianBlur::release() {
+ SPFilterPrimitive::release();
+}
+
+/**
+ * Sets a specific value in the SPGaussianBlur.
+ */
+void SPGaussianBlur::set(SPAttr key, gchar const *value) {
+ switch(key) {
+ case SPAttr::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(SPAttr::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);
+ }
+ }
+}
+
+/* Calculate the region taken up by gaussian blur
+ *
+ * @param region The original shape's region or previous primitive's region output.
+ */
+Geom::Rect SPGaussianBlur::calculate_region(Geom::Rect region)
+{
+ double x = this->stdDeviation.getNumber();
+ double y = this->stdDeviation.getOptNumber();
+ if (y == -1.0)
+ y = x;
+ // If not within the default 10% margin (see
+ // http://www.w3.org/TR/SVG11/filters.html#FilterEffectsRegion), specify margins
+ // The 2.4 is an empirical coefficient: at that distance the cutoff is practically invisible
+ // (the opacity at 2.4 * radius is about 3e-3)
+ region.expandBy(2.4 * x, 2.4 * y);
+ return region;
+}
+
+/*
+ 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..04ad552
--- /dev/null
+++ b/src/object/filters/gaussian-blur.h
@@ -0,0 +1,59 @@
+// 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;
+
+ Geom::Rect calculate_region(Geom::Rect region) override;
+
+protected:
+ void build(SPDocument* doc, Inkscape::XML::Node* repr) override;
+ void release() override;
+
+ void set(SPAttr 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..8eecbd9
--- /dev/null
+++ b/src/object/filters/image.cpp
@@ -0,0 +1,271 @@
+// 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(SPAttr::PRESERVEASPECTRATIO);
+ this->readAttr(SPAttr::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(SPAttr key, gchar const *value) {
+ switch(key) {
+ /*DEAL WITH SETTING ATTRIBUTES HERE*/
+ case SPAttr::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 SPAttr::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;
+ }
+}
+
+/*
+ * Check if the object is being used in the filter's definition
+ * and returns true if it is being used (to avoid infinate loops)
+ */
+bool SPFeImage::valid_for(SPObject const *obj) const
+{
+ // SVGElem could be nullptr, but this should still work.
+ return obj && SP_ITEM(obj) != SVGElem;
+}
+
+/**
+ * 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..15c5337
--- /dev/null
+++ b/src/object/filters/image.h
@@ -0,0 +1,71 @@
+// 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;
+
+ bool valid_for(SPObject const *obj) const override;
+
+protected:
+ void build(SPDocument* doc, Inkscape::XML::Node* repr) override;
+ void release() override;
+
+ void set(SPAttr 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..2fe993b
--- /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(SPAttr 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..6621674
--- /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(SPAttr 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..59f0d3f
--- /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(SPAttr::IN_);
+}
+
+/**
+ * Drops any allocated memory.
+ */
+void SPFeMergeNode::release() {
+ SPObject::release();
+}
+
+/**
+ * Sets a specific value in the SPFeMergeNode.
+ */
+void SPFeMergeNode::set(SPAttr key, gchar const *value) {
+ SPFeMerge *parent = SP_FEMERGE(this->parent);
+
+ if (key == SPAttr::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..a065137
--- /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(SPAttr 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..3ed87a9
--- /dev/null
+++ b/src/object/filters/morphology.cpp
@@ -0,0 +1,185 @@
+// 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(SPAttr::OPERATOR);
+ this->readAttr(SPAttr::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(SPAttr key, gchar const *value) {
+ Inkscape::Filters::FilterMorphologyOperator read_operator;
+
+ switch(key) {
+ /*DEAL WITH SETTING ATTRIBUTES HERE*/
+ case SPAttr::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 SPAttr::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() );
+}
+
+/**
+ * Calculate the region taken up by a mophoplogy primitive
+ *
+ * @param region The original shape's region or previous primitive's region output.
+ */
+Geom::Rect SPFeMorphology::calculate_region(Geom::Rect region)
+{
+ auto r = region;
+ if (Operator == Inkscape::Filters::MORPHOLOGY_OPERATOR_DILATE) {
+ if (radius.optNumIsSet()) {
+ r.expandBy(radius.getNumber(), radius.getOptNumber());
+ } else {
+ r.expandBy(radius.getNumber());
+ }
+ } else if (Operator == Inkscape::Filters::MORPHOLOGY_OPERATOR_ERODE) {
+ if (radius.optNumIsSet()) {
+ r.expandBy(-1 * radius.getNumber(), -1 * radius.getOptNumber());
+ } else {
+ r.expandBy(-1 * radius.getNumber());
+ }
+ }
+ return r;
+}
+
+/*
+ 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..cf77ee7
--- /dev/null
+++ b/src/object/filters/morphology.h
@@ -0,0 +1,56 @@
+// 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;
+ Geom::Rect calculate_region(Geom::Rect region) override;
+
+protected:
+ void build(SPDocument* doc, Inkscape::XML::Node* repr) override;
+ void release() override;
+
+ void set(SPAttr 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..b859598
--- /dev/null
+++ b/src/object/filters/offset.cpp
@@ -0,0 +1,155 @@
+// 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 <2geom/transforms.h>
+
+#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(SPAttr::DX);
+ this->readAttr(SPAttr::DY);
+}
+
+/**
+ * Drops any allocated memory.
+ */
+void SPFeOffset::release() {
+ SPFilterPrimitive::release();
+}
+
+/**
+ * Sets a specific value in the SPFeOffset.
+ */
+void SPFeOffset::set(SPAttr key, gchar const *value) {
+ double read_num;
+
+ switch(key) {
+ case SPAttr::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 SPAttr::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(SPAttr::DX);
+ this->readAttr(SPAttr::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);
+}
+
+/**
+ * Calculate the region taken up by an offset
+ *
+ * @param region The original shape's region or previous primitive's region output.
+ */
+Geom::Rect SPFeOffset::calculate_region(Geom::Rect region)
+{
+ // Because blur calculates its drawing space based on the resulting region
+ // An offset will actually harm blur's ability to draw, even though it shouldn't
+ // A future fix would require the blur to figure out its region minus any downstream
+ // offset (this effects drop-shadows)
+ // TODO: region *= Geom::Translate(this->dx, this->dy);
+ region.unionWith(region * Geom::Translate(this->dx, this->dy));
+ return region;
+}
+
+
+/*
+ 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..a717b45
--- /dev/null
+++ b/src/object/filters/offset.h
@@ -0,0 +1,54 @@
+// 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;
+
+ Geom::Rect calculate_region(Geom::Rect region) override;
+
+protected:
+ void build(SPDocument* doc, Inkscape::XML::Node* repr) override;
+ void release() override;
+
+ void set(SPAttr 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..f305ac7
--- /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(SPAttr::X);
+ this->readAttr(SPAttr::Y);
+ this->readAttr(SPAttr::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(SPAttr key, gchar const *value) {
+ gchar *end_ptr;
+
+ switch (key) {
+ case SPAttr::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 SPAttr::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 SPAttr::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(SPAttr::X);
+ this->readAttr(SPAttr::Y);
+ this->readAttr(SPAttr::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)
+ repr->setAttributeCssDouble("x", this->x);
+ if (this->y_set)
+ repr->setAttributeCssDouble("y", this->y);
+ if (this->z_set)
+ repr->setAttributeCssDouble("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..6091b43
--- /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(SPAttr 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..d750cce
--- /dev/null
+++ b/src/object/filters/sp-filter-primitive.cpp
@@ -0,0 +1,282 @@
+// 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(SPAttr::STYLE); // struct not derived from SPItem, we need to do this ourselves.
+ object->readAttr(SPAttr::IN_);
+ object->readAttr(SPAttr::RESULT);
+ object->readAttr(SPAttr::X);
+ object->readAttr(SPAttr::Y);
+ object->readAttr(SPAttr::WIDTH);
+ object->readAttr(SPAttr::HEIGHT);
+
+ SPObject::build(document, repr);
+}
+
+/**
+ * Drops any allocated memory.
+ */
+void SPFilterPrimitive::release() {
+ SPObject::release();
+}
+
+/**
+ * Sets a specific value in the SPFilterPrimitive.
+ */
+void SPFilterPrimitive::set(SPAttr key, gchar const *value) {
+
+ int image_nr;
+ switch (key) {
+ case SPAttr::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 SPAttr::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 SPAttr::X:
+ this->x.readOrUnset(value);
+ this->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ break;
+ case SPAttr::Y:
+ this->y.readOrUnset(value);
+ this->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ break;
+ case SPAttr::WIDTH:
+ this->width.readOrUnset(value);
+ this->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ break;
+ case SPAttr::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 );
+}
+
+/* Calculate the region taken up by this filter, given the previous region.
+ *
+ * @param current_region The original shape's region or previous primitive's
+ * calcualte_region output.
+ */
+Geom::Rect SPFilterPrimitive::calculate_region(Geom::Rect region)
+{
+ return region; // No change.
+}
+
+
+/*
+ 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..8374827
--- /dev/null
+++ b/src/object/filters/sp-filter-primitive.h
@@ -0,0 +1,78 @@
+// 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 "2geom/rect.h"
+#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(SPAttr 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;
+
+ /* Calculate the filter's effect on the region */
+ virtual Geom::Rect calculate_region(Geom::Rect region);
+
+ /* Return true if the object should be allowed to use this filter */
+ virtual bool valid_for(SPObject const *obj) const {
+ // This is used by feImage to stop infinate loops.
+ return true;
+ };
+
+ /* 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..c6c14c1
--- /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(SPAttr::SURFACESCALE);
+ this->readAttr(SPAttr::SPECULARCONSTANT);
+ this->readAttr(SPAttr::SPECULAREXPONENT);
+ this->readAttr(SPAttr::KERNELUNITLENGTH);
+ this->readAttr(SPAttr::LIGHTING_COLOR);
+}
+
+/**
+ * Drops any allocated memory.
+ */
+void SPFeSpecularLighting::release() {
+ SPFilterPrimitive::release();
+}
+
+/**
+ * Sets a specific value in the SPFeSpecularLighting.
+ */
+void SPFeSpecularLighting::set(SPAttr 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 SPAttr::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 SPAttr::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 SPAttr::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 SPAttr::KERNELUNITLENGTH:
+ //TODO kernelUnit
+ //this->kernelUnitLength.set(value);
+ /*TODOif (feSpecularLighting->renderer) {
+ feSpecularLighting->renderer->surfaceScale = feSpecularLighting->renderer;
+ }
+ */
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ break;
+ case SPAttr::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(SPAttr::SURFACESCALE);
+ this->readAttr(SPAttr::SPECULARCONSTANT);
+ this->readAttr(SPAttr::SPECULAREXPONENT);
+ this->readAttr(SPAttr::KERNELUNITLENGTH);
+ this->readAttr(SPAttr::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) {
+ repr->setAttributeCssDouble("surfaceScale", this->surfaceScale);
+ }
+
+ if (this->specularConstant_set) {
+ repr->setAttributeCssDouble("specularConstant", this->specularConstant);
+ }
+
+ if (this->specularExponent_set) {
+ repr->setAttributeCssDouble("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..2892c37
--- /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(SPAttr 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..cea258b
--- /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(SPAttr::X);
+ this->readAttr(SPAttr::Y);
+ this->readAttr(SPAttr::Z);
+ this->readAttr(SPAttr::POINTSATX);
+ this->readAttr(SPAttr::POINTSATY);
+ this->readAttr(SPAttr::POINTSATZ);
+ this->readAttr(SPAttr::SPECULAREXPONENT);
+ this->readAttr(SPAttr::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(SPAttr key, gchar const *value) {
+ gchar *end_ptr;
+
+ switch (key) {
+ case SPAttr::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 SPAttr::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 SPAttr::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 SPAttr::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 SPAttr::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 SPAttr::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 SPAttr::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 SPAttr::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(SPAttr::X);
+ this->readAttr(SPAttr::Y);
+ this->readAttr(SPAttr::Z);
+ this->readAttr(SPAttr::POINTSATX);
+ this->readAttr(SPAttr::POINTSATY);
+ this->readAttr(SPAttr::POINTSATZ);
+ this->readAttr(SPAttr::SPECULAREXPONENT);
+ this->readAttr(SPAttr::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)
+ repr->setAttributeCssDouble("x", this->x);
+ if (this->y_set)
+ repr->setAttributeCssDouble("y", this->y);
+ if (this->z_set)
+ repr->setAttributeCssDouble("z", this->z);
+ if (this->pointsAtX_set)
+ repr->setAttributeCssDouble("pointsAtX", this->pointsAtX);
+ if (this->pointsAtY_set)
+ repr->setAttributeCssDouble("pointsAtY", this->pointsAtY);
+ if (this->pointsAtZ_set)
+ repr->setAttributeCssDouble("pointsAtZ", this->pointsAtZ);
+ if (this->specularExponent_set)
+ repr->setAttributeCssDouble("specularExponent", this->specularExponent);
+ if (this->limitingConeAngle_set)
+ repr->setAttributeCssDouble("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..55dea72
--- /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(SPAttr 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..860ca5a
--- /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(SPAttr 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..d13d702
--- /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(SPAttr 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..d8fe979
--- /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(SPAttr::BASEFREQUENCY);
+ this->readAttr(SPAttr::NUMOCTAVES);
+ this->readAttr(SPAttr::SEED);
+ this->readAttr(SPAttr::STITCHTILES);
+ this->readAttr(SPAttr::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(SPAttr 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 SPAttr::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 SPAttr::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 SPAttr::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 SPAttr::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 SPAttr::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..5bc1ad2
--- /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(SPAttr 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 :