Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
sp-path.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * SVG <path> implementation
4 *
5 * Authors:
6 * Lauris Kaplinski <lauris@kaplinski.com>
7 * David Turner <novalis@gnu.org>
8 * Abhishek Sharma
9 * Johan Engelen
10 *
11 * Copyright (C) 2004 David Turner
12 * Copyright (C) 1999-2002 Lauris Kaplinski
13 * Copyright (C) 2000-2001 Ximian, Inc.
14 * Copyright (C) 1999-2012 Authors
15 *
16 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
17 */
18
19#include "sp-path.h"
20
21#include <glibmm/i18n.h>
22#include <glibmm/regex.h>
23
24#include <2geom/curves.h>
25
26#include "attributes.h"
27#include "sp-guide.h"
28#include "sp-lpe-item.h"
29#include "style.h"
30
31#include "display/curve.h"
32#include "helper/geom-curves.h"
33#include "live_effects/effect.h"
36#include "svg/svg.h"
37#include "xml/repr.h"
38
39
40#define noPATH_VERBOSE
41
43{
44 return _curve ? _curve->nodes_in_path() : 0;
45}
46
47const char* SPPath::typeName() const {
48 return "path";
49}
50
51const char* SPPath::displayName() const {
52 return _("Path");
53}
54
55gchar* SPPath::description() const {
56 int count = this->nodesInPath();
57 char *lpe_desc = g_strdup("");
58
59 if (hasPathEffect()) {
60 Glib::ustring s;
61 PathEffectList effect_list = this->getEffectList();
62
63 for (auto & it : effect_list)
64 {
65 LivePathEffectObject *lpeobj = it->lpeobject;
66
67 if (!lpeobj || !lpeobj->get_lpe()) {
68 break;
69 }
70
71 if (s.empty()) {
72 s = lpeobj->get_lpe()->getName();
73 } else {
74 s = s + ", " + lpeobj->get_lpe()->getName();
75 }
76 }
77 lpe_desc = g_strdup_printf(_(", path effect: %s"), s.c_str());
78 }
79 char *ret = g_strdup_printf(ngettext(
80 "%i node%s", "%i nodes%s", count), count, lpe_desc);
81 g_free(lpe_desc);
82 return ret;
83}
84
86 if (!this->_curve) {
87 return;
88 }
89
90 std::list<std::pair<Geom::Point, Geom::Point> > pts;
91
92 Geom::Affine const i2dt(this->i2dt_affine());
93 Geom::PathVector const & pv = this->_curve->get_pathvector();
94
95 for(const auto & pit : pv) {
96 for(Geom::Path::const_iterator cit = pit.begin(); cit != pit.end_default(); ++cit) {
97 // only add curves for straight line segments
98 if( is_straight_curve(*cit) )
99 {
100 pts.emplace_back(cit->initialPoint() * i2dt, cit->finalPoint() * i2dt);
101 }
102 }
103 }
104
106}
107
108SPPath::SPPath() : SPShape(), connEndPair(this) {
109}
110
111SPPath::~SPPath() = default;
112
114 /* Are these calls actually necessary? */
119
121
122 SPShape::build(document, repr);
123 // Our code depends on 'd' being an attribute (LPE's, etc.). To support 'd' as a property, we
124 // check it here (after the style property has been evaluated, this allows us to properly
125 // handled precedence of property vs attribute). If we read in a 'd' set by styling, convert it
126 // to an attribute. We'll convert it back on output.
127
128 d_source = style->d.style_src;
129
130 if (style->d.set &&
131
133
134 if (char const *d_val = style->d.value()) {
135 // Chrome shipped with a different syntax for property vs attribute.
136 // The SVG Working group decided to follow the Chrome syntax (which may
137 // allow future extensions of the 'd' property). The property syntax
138 // wraps the path data with "path(...)". We must strip that!
139
140 // Must be Glib::ustring or we get conversion errors!
141 Glib::ustring input = d_val;
142 Glib::ustring expression = R"A(path\‍("(.*)"\))A";
143 Glib::RefPtr<Glib::Regex> regex = Glib::Regex::create(expression);
144 Glib::MatchInfo matchInfo;
145 regex->match(input, matchInfo);
146
147 if (matchInfo.matches()) {
148 Glib::ustring value = matchInfo.fetch(1);
149
150 // Update curve
152
153 // Convert from property to attribute (convert back on write)
154 setAttributeOrRemoveIfEmpty("d", value);
155
156 SPCSSAttr *css = sp_repr_css_attr( getRepr(), "style");
158 sp_repr_css_set ( getRepr(), css, "style" );
160
161 style->d.style_src = SPStyleSrc::ATTRIBUTE;
162 }
163 }
164 // If any if statement is false, do nothing... don't overwrite 'd' from attribute
165 }
166
168 this->readAttr(SPAttr::D);
169
170 /* d is a required attribute */
171 char const *d = this->getAttribute("d");
172
173 if (d == nullptr) {
174 // First see if calculating the path effect will generate "d":
175 this->update_patheffect(true);
176 d = this->getAttribute("d");
177
178 // I guess that didn't work, now we have nothing useful to write ("")
179 if (d == nullptr) {
180 this->setKeyValue( sp_attribute_lookup("d"), "");
181 }
182 }
183}
184
186 this->connEndPair.release();
187
189}
190
191void SPPath::set(SPAttr key, const gchar* value) {
192 switch (key) {
194 if (value) {
196 } else {
197 setCurveBeforeLPE(nullptr);
198 }
199 break;
200
201 case SPAttr::D:
202 if (value) {
204 } else {
205 setCurve(nullptr);
206 }
207 break;
208
209 case SPAttr::MARKER:
211 this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
212 break;
215 this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
216 break;
219 this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
220 break;
223 this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
224 break;
225
232 this->connEndPair.setAttr(key, value);
233 break;
234
235 default:
236 SPShape::set(key, value);
237 break;
238 }
239}
240
242 if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) {
243 repr = xml_doc->createElement("svg:path");
244 }
245
246#ifdef PATH_VERBOSE
247g_message("sp_path_write writes 'd' attribute");
248#endif
249
250 if (this->_curve) {
251 repr->setAttribute("d", sp_svg_write_path(this->_curve->get_pathvector()));
252 } else {
253 repr->removeAttribute("d");
254 }
255
256 if (flags & SP_OBJECT_WRITE_EXT) {
257 if (_curve_before_lpe) {
258 repr->setAttribute("inkscape:original-d", sp_svg_write_path(_curve_before_lpe->get_pathvector()));
259 } else {
260 repr->removeAttribute("inkscape:original-d");
261 }
262 }
263
264 this->connEndPair.writeRepr(repr);
265
266 SPShape::write(xml_doc, repr, flags);
267
268 return repr;
269}
270
274
275void SPPath::update(SPCtx *ctx, guint flags) {
276 if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
277 flags &= ~SP_OBJECT_USER_MODIFIED_FLAG_B; // since we change the description, it's not a "just translation" anymore
278 }
279
280 SPShape::update(ctx, flags);
281 this->connEndPair.update();
282}
283
285 if (!_curve) { // 0 nodes, nothing to transform
286 return Geom::identity();
287 }
289 return transform;
290 }
292 if (!_curve_before_lpe) {
293 // we are inside a LPE group creating a new element
294 // and the original-d curve is not defined,
295 // This fix a issue with calligrapic tool that make a transform just when draw
297 }
298 _curve_before_lpe->transform(transform);
299 // fix issue https://gitlab.com/inkscape/inbox/-/issues/5460
300 sp_lpe_item_update_patheffect(this, false, false);
301 } else {
302 setCurve(_curve->transformed(transform));
303 }
304 // Adjust stroke
305 this->adjust_stroke(transform.descrim());
306
307 // Adjust pattern fill
308 this->adjust_pattern(transform);
309
310 // Adjust gradient fill
311 this->adjust_gradient(transform);
312
313 // nothing remains - we've written all of the transform, so return identity
314 return Geom::identity();
315}
316
318{
319 if (!_curve)
320 return;
321
322 auto transform = i2i_affine(root, this).inverse();
323
325 _curve_before_lpe->transform(transform);
326 sp_lpe_item_update_patheffect(this, false, false);
327 } else {
328 setCurve(_curve->transformed(transform));
329 }
330 setAttribute("d", sp_svg_write_path(_curve->get_pathvector()));
334 adjust_clip(transform, true);
335 removeAttribute("transform");
337}
338
339/*
340 Local Variables:
341 mode:c++
342 c-file-style:"stroustrup"
343 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
344 indent-tabs-mode:nil
345 fill-column:99
346 End:
347*/
348// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
SPAttr sp_attribute_lookup(gchar const *key)
Get attribute id by name.
Lookup dictionary for attributes/properties.
SPAttr
Definition attributes.h:27
@ CONNECTOR_TYPE
@ INKSCAPE_ORIGINAL_D
@ CONNECTION_START
@ CONNECTOR_CURVATURE
@ MARKER_START
@ MARKER_MID
@ MARKER_END
@ CONNECTION_START_POINT
@ CONNECTION_END_POINT
@ CONNECTION_END
3x3 matrix representing an affine transformation.
Definition affine.h:70
Coord descrim() const
Calculate the descriminant.
Definition affine.cpp:434
Affine inverse() const
Compute the inverse matrix.
Definition affine.cpp:388
Sequence of subpaths.
Definition pathvector.h:122
Glib::ustring getName() const
Definition effect.cpp:1173
Interface for refcounted XML nodes.
Definition node.h:80
void setAttribute(Util::const_char_ptr key, Util::const_char_ptr value)
Change an attribute of this node.
Definition node.cpp:25
void removeAttribute(Inkscape::Util::const_char_ptr key)
Remove an attribute of this node.
Definition node.h:280
Inkscape::LivePathEffect::Effect * get_lpe()
Definition lpeobject.h:51
void writeRepr(Inkscape::XML::Node *const repr) const
void setAttr(const SPAttr key, char const *const value)
Wrapper around a Geom::PathVector object.
Definition curve.h:26
Typed SVG document implementation.
Definition document.h:103
Geom::Affine i2dt_affine() const
Returns the transformation from item to desktop coords.
Definition sp-item.cpp:1821
void adjust_gradient(Geom::Affine const &postmul, bool set=false)
Definition sp-item.cpp:1426
Geom::Affine transform
Definition sp-item.h:138
void adjust_pattern(Geom::Affine const &postmul, bool set=false, PaintServerTransform=TRANSFORM_BOTH)
Definition sp-item.cpp:1380
void adjust_stroke(double ex)
Definition sp-item.cpp:1472
void remove_clip_transforms()
Definition sp-item.cpp:1465
void adjust_clip(Geom::Affine const &postmul, bool set=false)
Definition sp-item.cpp:1458
bool hasPathEffect() const
PathEffectList getEffectList()
bool hasPathEffectRecursive() const
bool pathEffectsEnabled() const
bool optimizeTransforms()
returns false when LPE write unoptimiced
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
void setAttributeOrRemoveIfEmpty(Inkscape::Util::const_char_ptr key, Inkscape::Util::const_char_ptr value)
Definition sp-object.h:785
void setAttribute(Inkscape::Util::const_char_ptr key, Inkscape::Util::const_char_ptr value)
void removeAttribute(char const *key)
void setKeyValue(SPAttr key, char const *value)
Call virtual set() function of object.
SPDocument * document
Definition sp-object.h:188
SPStyle * style
Represents the style properties, whether from presentation attributes, the style attribute,...
Definition sp-object.h:248
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.
char const * getAttribute(char const *name) const
void requestDisplayUpdate(unsigned int flags)
Queues an deferred update of this object's display.
SPConnEndPair connEndPair
Definition sp-path.h:37
void removeTransformsRecursively(SPObject const *root) override
Definition sp-path.cpp:317
~SPPath() override
Geom::Affine set_transform(Geom::Affine const &transform) override
Definition sp-path.cpp:284
const char * typeName() const override
The item's type name, not node tag name.
Definition sp-path.cpp:47
int nodesInPath() const
Definition sp-path.cpp:42
char * description() const override
Definition sp-path.cpp:55
void release() override
Definition sp-path.cpp:185
SPStyleSrc d_source
Definition sp-path.h:54
void update_patheffect(bool write) override
Definition sp-path.cpp:271
const char * displayName() const override
The item's type name as a translated human string.
Definition sp-path.cpp:51
void convert_to_guides() const override
Definition sp-path.cpp:85
Inkscape::XML::Node * write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, unsigned int flags) override
Definition sp-path.cpp:241
void set(SPAttr key, char const *value) override
Definition sp-path.cpp:191
void update(SPCtx *ctx, unsigned int flags) override
Definition sp-path.cpp:275
void build(SPDocument *document, Inkscape::XML::Node *repr) override
Definition sp-path.cpp:113
Base class for shapes, including <path> element.
Definition sp-shape.h:38
void update(SPCtx *ctx, unsigned int flags) override
Definition sp-shape.cpp:125
void setCurveInsync(SPCurve const *)
Definition sp-shape.cpp:958
std::optional< SPCurve > _curve_before_lpe
Definition sp-shape.h:69
void release() override
Removes, releases and unrefs all children of object.
Definition sp-shape.cpp:92
void set(SPAttr key, char const *value) override
Definition sp-shape.cpp:115
void setCurveBeforeLPE(SPCurve const *)
Definition sp-shape.cpp:942
void build(SPDocument *document, Inkscape::XML::Node *repr) override
Definition sp-shape.cpp:63
void set_marker(unsigned key, char const *value)
Adds a new marker to shape object at the location indicated by key.
Definition sp-shape.cpp:874
void update_patheffect(bool write) override
Definition sp-shape.cpp:650
std::shared_ptr< SPCurve const > _curve
Definition sp-shape.h:70
Inkscape::XML::Node * write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, unsigned int flags) override
Definition sp-shape.cpp:120
void setCurve(SPCurve const *)
Definition sp-shape.cpp:926
T< SPAttr::D, SPIString > d
Path data.
Definition style.h:103
RootCluster root
std::shared_ptr< Css const > css
Include all curve types.
Specific curve type functions for Inkscape, not provided by lib2geom.
bool is_straight_curve(Geom::BezierCurve const &c)
Definition geom-curves.h:22
Affine identity()
Create an identity matrix.
Definition affine.h:210
static cairo_user_data_key_t key
void sp_repr_css_set(Node *repr, SPCSSAttr *css, gchar const *attr)
Sets an attribute (e.g.
Definition repr-css.cpp:265
void sp_repr_css_attr_unref(SPCSSAttr *css)
Unreferences an SPCSSAttr (will be garbage collected if no references remain).
Definition repr-css.cpp:76
SPCSSAttr * sp_repr_css_attr(Node const *repr, gchar const *attr)
Creates a new SPCSSAttr with one attribute (i.e.
Definition repr-css.cpp:88
void sp_repr_css_unset_property(SPCSSAttr *css, gchar const *name)
Set a style property to "inkscape:unset".
Definition repr-css.cpp:202
C facade to Inkscape::XML::Node.
void sp_conn_end_pair_build(SPObject *object)
void sp_guide_pt_pairs_to_guides(SPDocument *doc, std::list< std::pair< Geom::Point, Geom::Point > > &pts)
Definition sp-guide.cpp:268
SPGuide – a guideline.
Geom::Affine i2i_affine(SPObject const *src, SPObject const *dest)
Definition sp-item.cpp:1806
void sp_lpe_item_update_patheffect(SPLPEItem *lpeitem, bool wholetree, bool write, bool with_satellites)
Calls any registered handlers for the update_patheffect action.
Base class for live path effect items.
std::list< PathEffectSharedPtr > PathEffectList
Definition sp-lpe-item.h:46
@ SP_MARKER_LOC_START
@ SP_MARKER_LOC_END
@ SP_MARKER_LOC_MID
@ SP_MARKER_LOC
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.
Geom::PathVector sp_svg_read_pathv(char const *str)
Definition svg-path.cpp:37
static void sp_svg_write_path(Inkscape::SVG::PathString &str, Geom::Path const &p, bool normalize=false)
Definition svg-path.cpp:109