Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
sp-clippath.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * SVG <clipPath> implementation
4 *
5 * Authors:
6 * Lauris Kaplinski <lauris@kaplinski.com>
7 * Jon A. Cruz <jon@joncruz.org>
8 * Abhishek Sharma
9 *
10 * Copyright (C) 2001-2002 authors
11 * Copyright (C) 2001 Ximian, Inc.
12 *
13 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
14 */
15
16#include "sp-clippath.h"
17
18#include <cstring>
19
20#include <2geom/transforms.h>
21
22#include "enums.h"
23#include "attributes.h"
24#include "document.h"
25#include "style.h"
26
27#include "sp-item.h"
28#include "sp-defs.h"
29#include "sp-text.h"
30#include "sp-use.h"
31
34
40
41SPClipPath::~SPClipPath() = default;
42
52
54{
55 if (document) {
56 document->removeResource("clipPath", this);
57 }
58
59 views.clear();
60
62}
63
64void SPClipPath::set(SPAttr key, char const *value)
65{
66 switch (key) {
69 clipPathUnits_set = false;
70
71 if (value) {
72 if (!std::strcmp(value, "userSpaceOnUse")) {
73 clipPathUnits_set = true;
74 } else if (!std::strcmp(value, "objectBoundingBox")) {
76 clipPathUnits_set = true;
77 }
78 }
79
80 requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
81 break;
82
83 default:
85 style->clear(key);
86 requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG);
87 } else {
88 SPObjectGroup::set(key, value);
89 }
90 break;
91 }
92}
93
95{
97
98 if (auto item = cast<SPItem>(document->getObjectByRepr(child))) {
99 for (auto &v : views) {
100 auto ac = item->invoke_show(v.drawingitem->drawing(), v.key, SP_ITEM_REFERENCE_FLAGS);
101 if (ac) {
102 v.drawingitem->prependChild(ac);
103 }
104 }
105 }
106}
107
108void SPClipPath::update(SPCtx *ctx, unsigned flags)
109{
110 auto const cflags = cascade_flags(flags);
111
112 for (auto c : childList(true)) {
113 if (cflags || (c->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
114 c->updateDisplay(ctx, cflags);
115 }
117 }
118
119 for (auto &v : views) {
120 update_view(v);
121 }
122}
123
125{
127 v.drawingitem->setChildTransform(Geom::Scale(v.bbox->dimensions()) * Geom::Translate(v.bbox->min()));
128 } else {
129 v.drawingitem->setChildTransform(Geom::identity());
130 }
131}
132
133void SPClipPath::modified(unsigned flags)
134{
135 auto const cflags = cascade_flags(flags);
136
137 for (auto c : childList(true)) {
138 if (cflags || (c->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
139 c->emitModified(cflags);
140 }
142 }
143}
144
146{
147 if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) {
148 repr = xml_doc->createElement("svg:clipPath");
149 }
150
151 SPObjectGroup::write(xml_doc, repr, flags);
152
153 return repr;
154}
155
157{
158 views.emplace_back(make_drawingitem<Inkscape::DrawingGroup>(drawing), bbox, key);
159 auto &v = views.back();
160 auto root = v.drawingitem.get();
161
162 for (auto &child : children) {
163 if (auto item = cast<SPItem>(&child)) {
164 auto ac = item->invoke_show(drawing, key, SP_ITEM_REFERENCE_FLAGS);
165 if (ac) {
166 // The order is not important in clippath.
167 root->appendChild(ac);
168 }
169 }
170 }
171
172 root->setStyle(style);
173
174 update_view(v);
175
176 return root;
177}
178
179void SPClipPath::hide(unsigned key)
180{
181 for (auto &child : children) {
182 if (auto item = cast<SPItem>(&child)) {
184 }
185 }
186
187 auto it = std::find_if(views.begin(), views.end(), [=] (auto &v) {
188 return v.key == key;
189 });
190
191 if (it == views.end()) {
192 return;
193 }
194
195 views.erase(it);
196}
197
198void SPClipPath::setBBox(unsigned key, Geom::OptRect const &bbox)
199{
200 auto it = std::find_if(views.begin(), views.end(), [=] (auto &v) {
201 return v.key == key;
202 });
203 assert(it != views.end());
204 auto &v = *it;
205
206 v.bbox = bbox;
207 update_view(v);
208}
209
211{
212 Geom::OptRect bbox;
213 for (auto &child : children) {
214 if (auto item = cast<SPItem>(&child)) {
215 bbox.unionWith(item->geometricBounds(item->transform * transform));
216 }
217 }
218 return bbox;
219}
220
222{
223 for (auto &clip : children) {
224 if (auto item = cast<SPItem>(&clip)) {
225 if (set) {
226 item->doWriteTransform(item->transform * postmul);
227 } else {
229 }
230 }
231 }
232}
233
235{
236 for (auto &clip : children) {
237 if (auto item = cast<SPItem>(&clip)) {
239 }
240 }
241}
242
248{
250 auto add_curve = [&ret](SPObject const *obj, Geom::Affine const &tr) {
251 if (auto shape = cast<SPShape>(obj)) {
252 if (!shape->curve()) {
253 return;
254 }
255 for (auto &path : *shape->curve()) {
256 if (!path.empty()) {
257 ret.push_back(path * (shape->transform * tr));
258 }
259 }
260 }
261 };
262
263 for (auto &child : children) {
264 if (auto use = cast<SPUse>(&child)) {
265 if (auto orig = use->get_original()) {
266 add_curve(orig, use->transform * transform);
267 }
268 } else {
269 add_curve(&child, transform);
270 }
271 }
272 return ret;
273}
274
279{
280 SPText const *ret = nullptr;
281 for (auto &child : children) {
282 if (auto text = cast<SPText>(&child)) {
283 if (ret) { // One text object only.
284 return nullptr;
285 }
286 ret = text;
287 } else if (is<SPShape>(&child)) {
288 return nullptr; // Failure, has a path shape.
289 }
290 }
291 return ret;
292}
293
294// Create a mask element (using passed elements), add it to <defs>
295char const *SPClipPath::create(std::vector<Inkscape::XML::Node*> &reprs, SPDocument *document)
296{
297 auto defsrepr = document->getDefs()->getRepr();
298
299 auto xml_doc = document->getReprDoc();
300 auto repr = xml_doc->createElement("svg:clipPath");
301 repr->setAttribute("clipPathUnits", "userSpaceOnUse");
302
303 defsrepr->appendChild(repr);
304 auto id = repr->attribute("id");
305 auto clip_path_object = document->getObjectById(id);
306
307 for (auto node : reprs) {
308 clip_path_object->appendChildRepr(node);
309 }
310
312 return id;
313}
314
316{
317 if (!is<SPClipPath>(obj)) {
318 return false;
319 }
320
321 if (URIReference::_acceptObject(obj)) {
322 return true;
323 }
324
325 auto const owner = getOwner();
326 //XML Tree being used directly here while it shouldn't be...
327 auto const owner_repr = owner->getRepr();
328 //XML Tree being used directly here while it shouldn't be...
329 auto const obj_repr = obj->getRepr();
330 char const *owner_name = "";
331 char const *owner_clippath = "";
332 char const *obj_name = "";
333 char const *obj_id = "";
334 if (owner_repr) {
335 owner_name = owner_repr->name();
336 owner_clippath = owner_repr->attribute("clippath");
337 }
338 if (obj_repr) {
339 obj_name = obj_repr->name();
340 obj_id = obj_repr->attribute("id");
341 }
342 std::cerr << "WARNING: Ignoring recursive clippath reference "
343 << "<" << (owner_name ? owner_name : "(null)") << " clippath=\"" << (owner_clippath ? owner_clippath : "(null)") << "\">"
344 << " in <" << (obj_name ? obj_name : "(null)") << " id=\"" << (obj_id ? obj_id : "(null)") << "\">" << std::endl;
345
346 return false;
347}
348
349/*
350 Local Variables:
351 mode:c++
352 c-file-style:"stroustrup"
353 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
354 indent-tabs-mode:nil
355 fill-column:99
356 End:
357*/
358// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
bool SP_ATTRIBUTE_IS_CSS(SPAttr k)
True iff k is a property in SVG, i.e.
Lookup dictionary for attributes/properties.
SPAttr
Definition attributes.h:27
@ CLIPPATHUNITS
3x3 matrix representing an affine transformation.
Definition affine.h:70
void unionWith(CRect const &b)
Enlarge the rectangle to contain the argument.
Axis-aligned rectangle that can be empty.
Definition rect.h:203
Sequence of subpaths.
Definition pathvector.h:122
void push_back(Path const &path)
Append a path at the end.
Definition pathvector.h:172
Scaling from the origin.
Definition transforms.h:150
Translation by a vector.
Definition transforms.h:115
SVG drawing item for display.
void appendChild(DrawingItem *item)
SPObject * getOwner() const
Returns a pointer to the URIReference's owner.
Interface for refcounted XML nodes.
Definition node.h:80
virtual char const * name() const =0
Get the name of the element node.
void setAttribute(Util::const_char_ptr key, Util::const_char_ptr value)
Change an attribute of this node.
Definition node.cpp:25
virtual char const * attribute(char const *key) const =0
Get the string representation of a node's attribute.
bool _acceptObject(SPObject *obj) const override
If the owner element of this reference (the element with <... clippath="...">) is a child of the clip...
void modified(unsigned flags) override
Inkscape::XML::Node * write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, unsigned flags) override
void setBBox(unsigned key, Geom::OptRect const &bbox)
void set(SPAttr key, char const *value) override
~SPClipPath() override
Geom::OptRect geometricBounds(Geom::Affine const &transform) const
void removeTransformsRecursively(SPObject const *root)
Geom::PathVector getPathVector(Geom::Affine const &transform) const
This gets a compiled path vector from all the objects.
bool clipPathUnits
Definition sp-clippath.h:69
void transform_multiply(Geom::Affine postmul, bool set=true)
void build(SPDocument *doc, Inkscape::XML::Node *repr) override
bool clipPathUnits_set
Definition sp-clippath.h:68
SPText const * getTextObject() const
This gets a text object, if the clip path is made up of a single sp-text.
void update(SPCtx *ctx, unsigned flags) override
void hide(unsigned key)
void update_view(View &v)
void child_added(Inkscape::XML::Node *child, Inkscape::XML::Node *ref) override
void release() override
static char const * create(std::vector< Inkscape::XML::Node * > &reprs, SPDocument *document)
Inkscape::DrawingItem * show(Inkscape::Drawing &drawing, unsigned key, Geom::OptRect const &bbox)
std::vector< View > views
Definition sp-clippath.h:72
Typed SVG document implementation.
Definition document.h:101
bool removeResource(char const *key, SPObject *object)
bool addResource(char const *key, SPObject *object)
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
SPObject * getObjectByRepr(Inkscape::XML::Node *repr) const
void set_item_transform(Geom::Affine const &transform_matrix)
Sets item private transform (not propagated to repr), without compensating stroke widths,...
Definition sp-item.cpp:1780
Inkscape::DrawingItem * invoke_show(Inkscape::Drawing &drawing, unsigned int key, unsigned int flags)
Definition sp-item.cpp:1277
Geom::Affine transform
Definition sp-item.h:138
void invoke_hide(unsigned int key)
Definition sp-item.cpp:1328
virtual void removeTransformsRecursively(SPObject const *root)
Definition sp-item.cpp:1633
Geom::OptRect geometricBounds(Geom::Affine const &transform=Geom::identity()) const
Get item's geometric bounding box in this item's coordinate system.
Definition sp-item.cpp:919
void doWriteTransform(Geom::Affine const &transform, Geom::Affine const *adv=nullptr, bool compensate=true)
Set a new transform on an object.
Definition sp-item.cpp:1666
Inkscape::XML::Node * write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, unsigned int flags) override
void child_added(Inkscape::XML::Node *child, Inkscape::XML::Node *ref) override
SPObject is an abstract base class of all of the document nodes at the SVG document level.
Definition sp-object.h:160
Inkscape::XML::Node * repr
Definition sp-object.h:193
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,...
SPDocument * document
Definition sp-object.h:188
virtual void set(SPAttr key, const char *value)
char * id
Definition sp-object.h:192
SPStyle * style
Represents the style properties, whether from presentation attributes, the style attribute,...
Definition sp-object.h:248
virtual void release()
void readAttr(char const *key)
Read value of key attribute from XML node into object.
Inkscape::XML::Node * getRepr()
Returns the XML representation of tree.
SPObject * appendChildRepr(Inkscape::XML::Node *repr)
Append repr as child of this object.
virtual void build(SPDocument *doc, Inkscape::XML::Node *repr)
ChildrenList children
Definition sp-object.h:907
void requestDisplayUpdate(unsigned int flags)
Queues an deferred update of this object's display.
void clear()
Definition style.cpp:505
RootCluster root
double c[8][4]
Geom::Point orig
Group belonging to an SVG drawing element.
Canvas item belonging to an SVG drawing element.
@ SP_CONTENT_UNITS_OBJECTBOUNDINGBOX
Definition enums.h:64
@ SP_CONTENT_UNITS_USERSPACEONUSE
Definition enums.h:63
SPItem * item
Inkscape::XML::Node * node
Affine identity()
Create an identity matrix.
Definition affine.h:210
static R & release(R &r)
Decrements the reference count of a anchored object.
static T clip(T const &v, T const &a, T const &b)
static cairo_user_data_key_t key
Ocnode * child[8]
Definition quantize.cpp:33
Ocnode ** ref
Definition quantize.cpp:32
Some things pertinent to all visible shapes: SPItem, SPItemView, SPItemCtx.
SPObject * sp_object_unref(SPObject *object, SPObject *owner)
Decrease reference count of object, with possible debugging and finalization.
unsigned cascade_flags(unsigned flags)
Definition sp-object.h:60
Interface for XML documents.
Definition document.h:43
virtual Node * createElement(char const *name)=0
Unused.
Definition sp-object.h:94
SPStyle - a style object for SPItem objects.
Affine transformation classes.