diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:24:48 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:24:48 +0000 |
commit | cca66b9ec4e494c1d919bff0f71a820d8afab1fa (patch) | |
tree | 146f39ded1c938019e1ed42d30923c2ac9e86789 /src/object/filters | |
parent | Initial commit. (diff) | |
download | inkscape-cca66b9ec4e494c1d919bff0f71a820d8afab1fa.tar.xz inkscape-cca66b9ec4e494c1d919bff0f71a820d8afab1fa.zip |
Adding upstream version 1.2.2.upstream/1.2.2upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/object/filters')
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 : |