From cca66b9ec4e494c1d919bff0f71a820d8afab1fa Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 20:24:48 +0200 Subject: Adding upstream version 1.2.2. Signed-off-by: Daniel Baumann --- src/object/filters/composite.cpp | 299 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 299 insertions(+) create mode 100644 src/object/filters/composite.cpp (limited to 'src/object/filters/composite.cpp') 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 implementation. + * + */ +/* + * Authors: + * hugo Rodrigues + * 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(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 : -- cgit v1.2.3