Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
lpe-powermask.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
4 */
5#include "lpe-powermask.h"
6
7#include <glibmm/i18n.h>
8
9#include <bad-uri-exception.h>
10
13
14#include "inkscape.h"
15#include "preferences.h"
16#include "selection.h"
17
20#include "object/sp-defs.h"
22#include "object/sp-mask.h"
23#include "svg/stringstream.h"
24#include "svg/svg.h"
25#include "util/safe-printf.h"
26#include "util/uri.h"
27
28namespace Inkscape {
29namespace LivePathEffect {
30
32 : Effect(lpeobject),
33 uri("Store the uri of mask", "", "uri", &wr, this, "false", false),
34 invert(_("Invert mask"), _("Invert mask"), "invert", &wr, this, false),
35 //wrap(_("Wrap mask data"), _("Wrap mask data allowing previous filters"), "wrap", &wr, this, false),
36 hide_mask(_("Hide mask"), _("Hide mask"), "hide_mask", &wr, this, false),
37 background(_("Add background to mask"), _("Add background to mask"), "background", &wr, this, false),
38 background_color(_("Background color and opacity"), _("Set color and opacity of the background"), "background_color", &wr, this, Colors::Color(0xffffffff))
39{
46}
47
49
50Glib::ustring LPEPowerMask::getId() { return Glib::ustring("mask-powermask-") + Glib::ustring(getLPEObj()->getId()); }
51
52void
54{
55 SPLPEItem *item = const_cast<SPLPEItem*>(lpeitem);
56 SPObject * mask = item->getMaskObject();
57 bool hasit = false;
58 if (lpeitem->hasPathEffect() && lpeitem->pathEffectsEnabled()) {
59 PathEffectList path_effect_list(*lpeitem->path_effect_list);
60 for (auto &lperef : path_effect_list) {
61 LivePathEffectObject *lpeobj = lperef->lpeobject;
62 if (!lpeobj) {
66 g_warning("SPLPEItem::performPathEffect - NULL lpeobj in list!");
67 return;
68 }
69 if (LPETypeConverter.get_key(lpeobj->effecttype) == "powermask") {
70 hasit = true;
71 break;
72 }
73 }
74 }
75 if (!mask || hasit) {
76 item->removeCurrentPathEffect(false);
77 } else {
78 Glib::ustring newmask = getId();
79 Glib::ustring uri = Glib::ustring("url(#") + newmask + Glib::ustring(")");
80 mask->setAttribute("id", newmask);
81 item->setAttribute("mask", uri);
82 }
83}
84
86{
87 SPDocument *document = getSPDoc();
88 if (!document || !sp_lpe_item) {
89 return;
90 }
92 SPObject *elemref = document->getObjectById(getId().c_str());
93 if (!elemref && sp_lpe_item && mask) {
94 Glib::ustring newmask = getId();
95 Glib::ustring uri = Glib::ustring("url(#") + newmask + Glib::ustring(")");
96 Inkscape::XML::Document *xml_doc = document->getReprDoc();
97 Inkscape::XML::Node *fork = mask->getRepr()->duplicate(xml_doc);
98 mask = document->getDefs()->appendChildRepr(fork);
99 fork->setAttribute("id", newmask);
101 sp_lpe_item->setAttribute("mask", uri);
102 }
103}
104
105void
107 //To avoid close of color dialog and better performance on change color
108 tryForkMask();
110 auto uri_str = uri.param_getSVGValue();
111 if (hide_mask && mask) {
113 } else if (!hide_mask && !mask && !uri_str.empty()) {
114 sp_lpe_item->getMaskRef().try_attach(uri_str.c_str());
115 }
116 mask = sp_lpe_item->getMaskObject();
117 if (mask) {
120 setMask();
121 } else {
122 uri.param_setValue(Glib::ustring(extract_uri(sp_lpe_item->getAttribute("mask"))), true);
124 Geom::OptRect bbox = lpeitem->visualBounds();
125 if(!bbox) {
126 return;
127 }
128 uri_str = uri.param_getSVGValue();
129 sp_lpe_item->getMaskRef().try_attach(uri_str.c_str());
130
131 Geom::Rect bboxrect = (*bbox);
132 bboxrect.expandBy(1);
133 mask_box.clear();
134 mask_box = Geom::Path(bboxrect);
135 SPDocument *document = getSPDoc();
136 if (!document || !mask) {
137 return;
138 }
140 setMask();
141 }
142 } else if(!hide_mask) {
143 SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem);
144 item->removeCurrentPathEffect(false);
145 }
146}
147
148void
151 SPObject *elemref = nullptr;
152 SPDocument *document = getSPDoc();
153 if (!document || !mask) {
154 return;
155 }
156 Inkscape::XML::Document *xml_doc = document->getReprDoc();
157 Inkscape::XML::Node *box = nullptr;
158 Inkscape::XML::Node *filter = nullptr;
159 SPDefs * defs = document->getDefs();
160 Glib::ustring mask_id = getId();
161 Glib::ustring box_id = mask_id + (Glib::ustring)"_box";
162 Glib::ustring filter_id = mask_id + (Glib::ustring)"_inverse";
163 Glib::ustring filter_label = (Glib::ustring)"filter" + mask_id;
164 Glib::ustring filter_uri = (Glib::ustring)"url(#" + filter_id + (Glib::ustring)")";
165 if (!(elemref = document->getObjectById(filter_id))) {
166 filter = xml_doc->createElement("svg:filter");
167 filter->setAttribute("id", filter_id);
168 filter->setAttribute("inkscape:label", filter_label);
170 sp_repr_css_set_property(css, "color-interpolation-filters", "sRGB");
171 sp_repr_css_change(filter, css, "style");
173 filter->setAttribute("height", "100");
174 filter->setAttribute("width", "100");
175 filter->setAttribute("x", "-50");
176 filter->setAttribute("y", "-50");
177 Inkscape::XML::Node *primitive1 = xml_doc->createElement("svg:feColorMatrix");
178 Glib::ustring primitive1_id = (mask_id + (Glib::ustring)"_primitive1").c_str();
179 primitive1->setAttribute("id", primitive1_id);
180 primitive1->setAttribute("values", "1");
181 primitive1->setAttribute("type", "saturate");
182 primitive1->setAttribute("result", "fbSourceGraphic");
183 Inkscape::XML::Node *primitive2 = xml_doc->createElement("svg:feColorMatrix");
184 Glib::ustring primitive2_id = (mask_id + (Glib::ustring)"_primitive2").c_str();
185 primitive2->setAttribute("id", primitive2_id);
186 primitive2->setAttribute("values", "-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0 ");
187 primitive2->setAttribute("in", "fbSourceGraphic");
188 elemref = defs->appendChildRepr(filter);
189 Inkscape::GC::release(filter);
190 filter->appendChild(primitive1);
191 Inkscape::GC::release(primitive1);
192 filter->appendChild(primitive2);
193 Inkscape::GC::release(primitive2);
194 }
195 Glib::ustring g_data_id = mask_id + (Glib::ustring)"_container";
196 if((elemref = document->getObjectById(g_data_id))){
197 std::vector<SPItem*> item_list = cast<SPGroup>(elemref)->item_list();
198 for (auto iter : item_list) {
199 Inkscape::XML::Node *mask_node = iter->getRepr();
200 elemref->getRepr()->removeChild(mask_node);
201 mask->getRepr()->appendChild(mask_node);
202 Inkscape::GC::release(mask_node);
203 }
204 elemref->deleteObject(true);
205 }
206 std::vector<SPObject*> mask_list = mask->childList(true);
207 for (auto iter : mask_list) {
208 auto mask_data = cast<SPItem>(iter);
209 Inkscape::XML::Node *mask_node = mask_data->getRepr();
210 if (! strcmp(mask_data->getId(), box_id.c_str())){
211 continue;
212 }
213 Glib::ustring mask_data_id = (Glib::ustring)mask_data->getId();
215 if(mask_node->attribute("style")) {
216 sp_repr_css_attr_add_from_string(css, mask_node->attribute("style"));
217 }
218 char const* filter = sp_repr_css_property (css, "filter", nullptr);
219 if(!filter || !strcmp(filter, filter_uri.c_str())) {
220 if (invert && is_visible) {
221 sp_repr_css_set_property (css, "filter", filter_uri.c_str());
222 } else {
223 sp_repr_css_set_property (css, "filter", nullptr);
224 }
225 Glib::ustring css_str;
227 mask_node->setAttribute("style", css_str);
228 }
229 }
230 if ((elemref = document->getObjectById(box_id))) {
231 elemref->deleteObject(true);
232 }
233 if (background && is_visible) {
234 bool exist = true;
235 if (!(elemref = document->getObjectById(box_id))) {
236 box = xml_doc->createElement("svg:path");
237 box->setAttribute("id", box_id);
238 exist = false;
239 }
240
241 auto const css = sp_repr_css_attr_new();
243 sp_repr_css_set_property_double(css, "fill-opacity", background_color.get_value()->getOpacity());
244 sp_repr_css_set_property_string(css, "stroke", "none");
245
246 char const* filter = sp_repr_css_property (css, "filter", nullptr);
247 if(!filter || !strcmp(filter, filter_uri.c_str())) {
248 if (invert && is_visible) {
249 sp_repr_css_set_property (css, "filter", filter_uri.c_str());
250 } else {
251 sp_repr_css_set_property (css, "filter", nullptr);
252 }
253 }
254 sp_repr_css_change(box, css, "style");
257 if (!exist) {
258 elemref = mask->appendChildRepr(box);
260 }
261 box->setPosition(0);
262 } else if ((elemref = document->getObjectById(box_id))) {
263 elemref->deleteObject(true);
264 }
265 mask->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
266}
267
268void
270{
271 doBeforeEffect(lpeitem);
272}
273
275
276void
278{
279 SPMask *mask = lpeitem->getMaskObject();
280 if (mask) {
282 if (keep_paths || prefs->getBool("/options/onungroup", false)) {
283 return;
284 }
285 invert.param_setValue(false);
286 //wrap.param_setValue(false);
288 setMask();
289 SPObject *elemref = nullptr;
290 SPDocument *document = getSPDoc();
291 Glib::ustring mask_id = getId();
292 Glib::ustring filter_id = mask_id + (Glib::ustring)"_inverse";
293 if ((elemref = document->getObjectById(filter_id))) {
294 elemref->deleteObject(true);
295 }
296 }
297}
298
300 if (!sel->isEmpty()) {
301 SPDocument *document = SP_ACTIVE_DOCUMENT;
302 if (!document) {
303 return;
304 }
305 auto selList = sel->items();
306 for(auto i = boost::rbegin(selList); i != boost::rend(selList); ++i) {
307 auto lpeitem = cast<SPLPEItem>(*i);
308 if (lpeitem) {
309 SPMask *mask = lpeitem->getMaskObject();
310 if (mask) {
311 Effect::createAndApply(POWERMASK, SP_ACTIVE_DOCUMENT, lpeitem);
312 Effect* lpe = lpeitem->getCurrentLPE();
313 if (lpe) {
314 lpe->getRepr()->setAttribute("invert", "false");
315 lpe->getRepr()->setAttribute("is_visible", "true");
316 lpe->getRepr()->setAttribute("hide_mask", "false");
317 lpe->getRepr()->setAttribute("background", "true");
318 lpe->getRepr()->setAttribute("background_color", "#ffffffff");
319 }
320 }
321 }
322 }
323 }
324}
325
327 if (!sel->isEmpty()) {
328 auto selList = sel->items();
329 for (auto i = boost::rbegin(selList); i != boost::rend(selList); ++i) {
330 auto lpeitem = cast<SPLPEItem>(*i);
331 if (lpeitem) {
332 if (lpeitem->hasPathEffect() && lpeitem->pathEffectsEnabled()) {
333 PathEffectList path_effect_list(*lpeitem->path_effect_list);
334 for (auto &lperef : path_effect_list) {
335 LivePathEffectObject *lpeobj = lperef->lpeobject;
336 if (!lpeobj) {
341 g_warning("SPLPEItem::performPathEffect - NULL lpeobj in list!");
342 return;
343 }
344 if (LPETypeConverter.get_key(lpeobj->effecttype) == "powermask") {
345 lpeitem->setCurrentPathEffect(lperef);
346 lpeitem->removeCurrentPathEffect(false);
347 break;
348 }
349 }
350 }
351 }
352 }
353 }
354}
355
356}; //namespace LivePathEffect
357}; /* namespace Inkscape */
358
359/*
360 Local Variables:
361 mode:c++
362 c-file-style:"stroustrup"
363 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
364 indent-tabs-mode:nil
365 fill-column:99
366 End:
367*/
368// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
TODO: insert short description here.
void expandBy(C amount)
Expand the rectangle in both directions by the specified amount.
Axis-aligned rectangle that can be empty.
Definition rect.h:203
Sequence of subpaths.
Definition pathvector.h:122
Sequence of contiguous curves, aka spline.
Definition path.h:353
void clear()
Remove all curves from the path.
Definition path.cpp:337
Axis aligned, non-empty rectangle.
Definition rect.h:92
RAII-style mechanism for creating a temporary undo-insensitive context.
void param_setValue(bool newvalue)
Definition bool.cpp:89
std::optional< Colors::Color > get_value() const
Definition colorpicker.h:38
void registerParameter(Parameter *param)
Definition effect.cpp:1704
static void createAndApply(const char *name, SPDocument *doc, SPItem *item)
Definition effect.cpp:1118
LivePathEffectObject * lpeobj
Definition effect.h:219
Inkscape::XML::Node * getRepr()
Definition effect.cpp:1928
LivePathEffectObject * getLPEObj()
Definition effect.h:150
void param_setValue(Glib::ustring newvalue, bool write=false)
Definition hidden.cpp:71
Glib::ustring param_getSVGValue() const override
Definition hidden.cpp:53
LPEPowerMask(LivePathEffectObject *lpeobject)
void doEffect(Geom::PathVector &curve) override
std::optional< Colors::Color > previous_color
void doOnApply(SPLPEItem const *lpeitem) override
Is performed a single time when the effect is freshly applied to a path.
void doOnVisibilityToggled(SPLPEItem const *lpeitem) override
void doBeforeEffect(SPLPEItem const *lpeitem) override
Is performed each time before the effect is updated.
void doOnRemove(SPLPEItem const *) override
SPItemRange items()
Returns a range of selected SPItems.
Definition object-set.h:230
bool isEmpty()
Returns true if no items are selected.
Preference storage class.
Definition preferences.h:61
bool getBool(Glib::ustring const &pref_path, bool def=false)
Retrieve a Boolean value.
static Preferences * get()
Access the singleton Preferences object.
The set of selected SPObjects for a given document and layer model.
Definition selection.h:80
void detach()
Detaches from the currently attached URI target, if any; the current referrent is signaled as NULL.
bool try_attach(char const *uri)
Try to attach to a URI.
Interface for refcounted XML nodes.
Definition node.h:80
virtual void setPosition(int pos)=0
Set the position of this node in parent's child order.
virtual void appendChild(Node *child)=0
Append a node as the last child of this node.
void setAttribute(Util::const_char_ptr key, Util::const_char_ptr value)
Change an attribute of this node.
Definition node.cpp:25
virtual Node * duplicate(Document *doc) const =0
Create a duplicate of this node.
virtual char const * attribute(char const *key) const =0
Get the string representation of a node's attribute.
virtual void removeChild(Node *child)=0
Remove a child of this node.
Inkscape::LivePathEffect::EffectType effecttype
Definition lpeobject.h:39
Typed SVG document implementation.
Definition document.h:101
SPObject * getObjectById(std::string const &id) const
SPDefs * getDefs()
Return the main defs object for the document.
Definition document.cpp:247
Inkscape::XML::Document * getReprDoc()
Our Inkscape::XML::Document.
Definition document.h:211
SPMaskReference & getMaskRef()
Definition sp-item.cpp:182
SPMask * getMaskObject() const
Definition sp-item.cpp:177
Geom::OptRect visualBounds(Geom::Affine const &transform=Geom::identity(), bool wfilter=true, bool wclip=true, bool wmask=true) const
Get item's visual bounding box in this item's coordinate system.
Definition sp-item.cpp:924
bool hasPathEffect() const
bool pathEffectsEnabled() const
PathEffectList * path_effect_list
Definition sp-lpe-item.h:61
SPObject is an abstract base class of all of the document nodes at the SVG document level.
Definition sp-object.h:160
void setAttribute(Inkscape::Util::const_char_ptr key, Inkscape::Util::const_char_ptr value)
std::vector< SPObject * > childList(bool add_ref, Action action=ActionGeneral)
Retrieves the children as a std vector object, optionally ref'ing the children in the process,...
void deleteObject(bool propagate, bool propagate_descendants)
Deletes an object, unparenting it from its parent.
Inkscape::XML::Node * getRepr()
Returns the XML representation of tree.
char const * getAttribute(char const *name) const
SPObject * appendChildRepr(Inkscape::XML::Node *repr)
Append repr as child of this object.
void requestDisplayUpdate(unsigned int flags)
Queues an deferred update of this object's display.
std::shared_ptr< Css const > css
SPItem * item
Path intersection graph.
static R & release(R &r)
Decrements the reference count of a anchored object.
void sp_inverse_powermask(Inkscape::Selection *sel)
const EnumEffectDataConverter< EffectType > LPETypeConverter
defined in effect.cpp
void sp_remove_powermask(Inkscape::Selection *sel)
Helper class to stream background task notifications as a series of messages.
Path intersection.
Singleton class to access the preferences file in a convenient way.
SPCSSAttr * sp_repr_css_attr_new()
Creates an empty SPCSSAttr (a class for manipulating CSS style properties).
Definition repr-css.cpp:67
void sp_repr_css_write_string(SPCSSAttr *css, Glib::ustring &str)
Write a style attribute string from a list of properties stored in an SPCSAttr object.
Definition repr-css.cpp:242
void sp_repr_css_change(Node *repr, SPCSSAttr *css, gchar const *attr)
Creates a new SPCSAttr with the values filled from a repr, merges in properties from the given SPCSAt...
Definition repr-css.cpp:357
void sp_repr_css_set_property_double(SPCSSAttr *css, gchar const *name, double value)
Set a style property to a new float value (e.g.
Definition repr-css.cpp:223
void sp_repr_css_attr_unref(SPCSSAttr *css)
Unreferences an SPCSSAttr (will be garbage collected if no references remain).
Definition repr-css.cpp:76
void sp_repr_css_set_property_string(SPCSSAttr *css, char const *name, std::string const &value)
Set a style property to a standard string.
Definition repr-css.cpp:234
char const * sp_repr_css_property(SPCSSAttr *css, gchar const *name, gchar const *defval)
Returns a character string of the value of a given style property or a default value if the attribute...
Definition repr-css.cpp:147
void sp_repr_css_set_property(SPCSSAttr *css, gchar const *name, gchar const *value)
Set a style property to a new value (e.g.
Definition repr-css.cpp:190
void sp_repr_css_attr_add_from_string(SPCSSAttr *css, gchar const *p)
Use libcroco to parse a string for CSS properties and then merge them into an existing SPCSSAttr.
Definition repr-css.cpp:340
std::list< PathEffectSharedPtr > PathEffectList
Definition sp-lpe-item.h:45
void invert(const double v[16], double alpha[16])
Interface for XML documents.
Definition document.h:43
virtual Node * createElement(char const *name)=0
Definition curve.h:24
static void sp_svg_write_path(Inkscape::SVG::PathString &str, Geom::Path const &p, bool normalize=false)
Definition svg-path.cpp:109
TODO: insert short description here.
std::string extract_uri(char const *s, char const **endptr)
Parse functional URI notation, as per 4.3.4 of CSS 2.1.
Definition uri.cpp:19
URI functions as per 4.3.4 of CSS 2.1 http://www.w3.org/TR/CSS21/syndata.html#uri.