Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
sp-root.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
5/*
6 * Authors:
7 * Lauris Kaplinski <lauris@kaplinski.com>
8 * Jon A. Cruz <jon@joncruz.org>
9 * Abhishek Sharma
10 *
11 * Copyright (C) 1999-2002 Lauris Kaplinski
12 * Copyright (C) 2000-2001 Ximian, Inc.
13 *
14 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
15 */
16
17#include "sp-root.h"
18
19#include <2geom/affine.h> // for identity, Affine
20#include "attributes.h" // for SPAttr
21#include "display/drawing-group.h" // for DrawingGroup
22#include "display/drawing-item-ptr.h" // for DrawingItemPtr
23#include "document.h" // for SPDocument
24#include "print.h" // for SPPrintContext
25#include <2geom/rect.h> // for Rect
26#include "sp-defs.h" // for SPDefs
27#include "sp-namedview.h" // for SPNamedView
28#include "sp-use.h" // for SPUse
29#include "sp-item-group.h" // for SPGroup
30#include "sp-item.h" // for SPItemCtx, SPIte...
31#include "sp-object.h" // for SP_OBJECT_VIEWPO...
32#include "viewbox.h" // for SPViewBox
33
34#include "svg/svg-length.h" // for SVGLength
35#include "svg/svg.h" // for sp_svg_length_wr...
36#include "util/units.h" // for Quantity
37#include "xml/document.h" // for Document
38
39namespace Inkscape {
40class Drawing;
41} // namespace Inkscape
42
44{
45 this->onload = nullptr;
46
47 this->unset_x_and_y();
48 this->width.unset(SVGLength::PERCENT, 1.0, 1.0);
49 this->height.unset(SVGLength::PERCENT, 1.0, 1.0);
50
51 this->defs = nullptr;
52}
53
55= default;
56
58{
59 this->x.unset(SVGLength::PERCENT, 0.0, 0.0); // Ignored for root SVG element
60 this->y.unset(SVGLength::PERCENT, 0.0, 0.0);
61}
62
64{
65 //XML Tree being used directly here while it shouldn't be.
66 if (!this->getRepr()->attribute("version")) {
67 repr->setAttribute("version", SVG_VERSION);
68 }
69
72 /* It is important to parse these here, so objects will have viewport build-time */
73 this->readAttr(SPAttr::X);
74 this->readAttr(SPAttr::Y);
80
81 SPGroup::build(document, repr);
82
83 // Search for first <defs> node
84 for (auto& o: children) {
85 if (is<SPDefs>(&o)) {
86 this->defs = cast<SPDefs>(&o);
87 break;
88 }
89 }
90
91 // clear transform, if any was read in - SVG does not allow transform= on <svg>
92 this->transform = Geom::identity();
93}
94
96{
97 this->defs = nullptr;
98
100}
101
102
103void SPRoot::set(SPAttr key, const gchar *value)
104{
105 switch (key) {
106 case SPAttr::VERSION:
107 if (auto version = Inkscape::Version::from_string(value)) {
108 svg_version = *version;
109 } else {
111 }
112 break;
113
115 if (auto version = Inkscape::Version::from_string(value)) {
116 inkscape_version = *version;
117 }
118 break;
119
120 case SPAttr::X:
121 /* Valid for non-root SVG elements; ex, em not handled correctly. */
122 if (!this->x.read(value)) {
123 this->x.unset(SVGLength::PERCENT, 0.0, 0.0);
124 }
125 root_x = x;
126
127 /* fixme: I am almost sure these do not require viewport flag (Lauris) */
129 break;
130
131 case SPAttr::Y:
132 /* Valid for non-root SVG elements; ex, em not handled correctly. */
133 if (!this->y.read(value)) {
134 this->y.unset(SVGLength::PERCENT, 0.0, 0.0);
135 }
136 root_y = y;
137
138 /* fixme: I am almost sure these do not require viewport flag (Lauris) */
140 break;
141
142 case SPAttr::WIDTH:
143 if (!this->width.read(value) || !(this->width.computed > 0.0)) {
144 this->width.unset(SVGLength::PERCENT, 1.0, 1.0);
145 }
147 break;
148
149 case SPAttr::HEIGHT:
150 if (!this->height.read(value) || !(this->height.computed > 0.0)) {
151 this->height.unset(SVGLength::PERCENT, 1.0, 1.0);
152 }
154 break;
155
156 case SPAttr::VIEWBOX:
157 set_viewBox( value );
159 break;
160
164 break;
165
166 case SPAttr::ONLOAD:
167 this->onload = (char *) value;
168 break;
169
170 default:
171 /* Pass the set event to the parent */
172 SPGroup::set(key, value);
173 break;
174 }
175}
176
178{
180
181 SPObject *co = this->document->getObjectByRepr(child);
182 // NOTE: some XML nodes do not have corresponding SP objects,
183 // for instance inkscape:clipboard used in the clipboard code.
184 // See LP bug #1227827
185 //g_assert (co != NULL || !strcmp("comment", child->name())); // comment repr node has no object
186
187 if (co && is<SPDefs>(co)) {
188 // We search for first <defs> node - it is not beautiful, but works
189 for (auto& c: children) {
190 if (is<SPDefs>(&c)) {
191 this->defs = cast<SPDefs>(&c);
192 break;
193 }
194 }
195 }
196}
197
199{
200 if (this->defs && (this->defs->getRepr() == child)) {
201 SPObject *iter = nullptr;
202
203 // We search for first remaining <defs> node - it is not beautiful, but works
204 for (auto& child: children) {
205 iter = &child;
206 if (is<SPDefs>(iter) && (SPDefs *)iter != this->defs) {
207 this->defs = (SPDefs *)iter;
208 break;
209 }
210 }
211
212 if (!iter) {
213 /* we should probably create a new <defs> here? */
214 this->defs = nullptr;
215 }
216 }
217
219}
220
222{
223 /*
224 * This is the root SVG element:
225 *
226 * x, y, width, and height apply to positioning the SVG element inside a parent.
227 * For the root SVG in Inkscape there is no parent, thus special rules apply:
228 * If width, height not set, width = 100%, height = 100% (as always).
229 * If width and height are in percent, they are percent of viewBox width/height.
230 * If width, height, and viewBox are not set... pick "random" width/height.
231 * x, y are ignored.
232 * initial viewport = (0 0 width height)
233 */
234 if( this->viewBox_set ) {
235
236 if( this->width._set ) {
237 // Check if this is necessary
238 if (this->width.unit == SVGLength::PERCENT) {
239 this->width.computed = this->width.value * this->viewBox.width();
240 }
241 } else {
242 this->width.set( SVGLength::PX, this->viewBox.width(), this->viewBox.width() );
243 }
244
245 if( this->height._set ) {
246 if (this->height.unit == SVGLength::PERCENT) {
247 this->height.computed = this->height.value * this->viewBox.height();
248 }
249 } else {
250 this->height.set(SVGLength::PX, this->viewBox.height(), this->viewBox.height() );
251 }
252
253 } else {
254
255 if( !this->width._set || this->width.unit == SVGLength::PERCENT) {
256 this->width.set( SVGLength::PX, 300, 300 ); // CSS/SVG default
257 }
258
259 if( !this->height._set || this->height.unit == SVGLength::PERCENT) {
260 this->height.set( SVGLength::PX, 150, 150 ); // CSS/SVG default
261 }
262 }
263
264 // Ignore x, y values for root element
265 this->unset_x_and_y();
266}
267
268void SPRoot::update(SPCtx *ctx, guint flags)
269{
270 SPItemCtx const *ictx = (SPItemCtx const *) ctx;
271
272 if( !this->parent ) {
273 this->setRootDimensions();
274 }
275
276 // Calculate x, y, width, height from parent/initial viewport
277 this->calcDimsFromParentViewport(ictx, false, cloned ? cast<SPUse>(parent) : nullptr);
278
279 // std::cout << "SPRoot::update: final:"
280 // << " x: " << x.computed
281 // << " y: " << y.computed
282 // << " width: " << width.computed
283 // << " height: " << height.computed << std::endl;
284
285 // Calculate new viewport
287 rctx.viewport = Geom::Rect::from_xywh( this->x.computed, this->y.computed,
288 this->width.computed, this->height.computed );
290
291 /* And invoke parent method */
292 SPGroup::update((SPCtx *) &rctx, flags);
293
294 /* As last step set additional transform of drawing group */
295 for (auto &v : views) {
296 auto g = cast<Inkscape::DrawingGroup>(v.drawingitem.get());
297 g->setChildTransform(c2p);
298 }
299}
300
301void SPRoot::modified(unsigned int flags)
302{
303 SPGroup::modified(flags);
304
305 if (!this->parent && (flags & SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
306 // Size of viewport has changed.
308 }
309}
310
311
313{
314 if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) {
315 repr = xml_doc->createElement("svg:svg");
316 }
317
318 if (!repr->attribute("version")) {
319 repr->setAttribute("version", svg_version.str());
320 }
321
322 // Inkscape_version doesn't need to be written as it's always
323 // replaced by the SVG output extension.
324
325 if (fabs(this->x.computed) > 1e-9) {
327 } else if (this->root_x) {
328 // Maintain data for root svgs, even when we don't use it
329 repr->setAttributeSvgDouble("x", this->root_x.computed);
330 }
331
332 if (fabs(this->y.computed) > 1e-9) {
334 } else if (this->root_y) {
335 // Maintain data for root svgs, even when we don't use it
336 repr->setAttributeSvgDouble("y", this->root_y.computed);
337 }
338
339 /* Unlike all other SPObject, here we want to preserve absolute units too (and only here,
340 * according to the recommendation in http://www.w3.org/TR/SVG11/coords.html#Units).
341 */
343 repr->setAttribute("height", sp_svg_length_write_with_units(this->height));
344
345 this->write_viewBox(repr);
346 this->write_preserveAspectRatio(repr);
347
348 SPGroup::write(xml_doc, repr, flags);
349
350 return repr;
351}
352
353Inkscape::DrawingItem *SPRoot::show(Inkscape::Drawing &drawing, unsigned int key, unsigned int flags)
354{
355 Inkscape::DrawingItem *ai = SPGroup::show(drawing, key, flags);
356
357 if (ai) {
359 g->setChildTransform(this->c2p);
360 }
361
362 // Uncomment to print out XML tree
363 // getRepr()->recursivePrintTree(0);
364
365 // Uncomment to print out SP Object tree
366 // recursivePrintTree(0);
367
368 // Uncomment to print out Display Item tree
369 // ai->recursivePrintTree(0);
370
371 return ai;
372}
373
375{
376 ctx->bind(this->c2p, 1.0);
377
378 SPGroup::print(ctx);
379
380 ctx->release();
381}
382
383const char *SPRoot::typeName() const {
384 return "image";
385}
386
387const char *SPRoot::displayName() const {
388 return "SVG"; // Do not translate
389}
390
391/*
392 Local Variables:
393 mode:c++
394 c-file-style:"stroustrup"
395 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
396 indent-tabs-mode:nil
397 fill-column:99
398 End:
399*/
400// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
3x3 affine transformation matrix.
Lookup dictionary for attributes/properties.
SPAttr
Definition attributes.h:27
@ INKSCAPE_VERSION
@ PRESERVEASPECTRATIO
static CRect from_xywh(Coord x, Coord y, Coord w, Coord h)
Create rectangle from origin and dimensions.
C height() const
Get the vertical extent of the rectangle.
C width() const
Get the horizontal extent of the rectangle.
SVG drawing item for display.
static double convert(double from_dist, Unit const *from, Unit const *to)
Convert distances.
Definition units.cpp:588
static std::optional< Version > from_string(const char *version_string)
Build a Version form a string, returning an empty optional in case of error.
Definition version.cpp:35
std::string const & str() const
Definition version.cpp:66
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
virtual char const * attribute(char const *key) const =0
Get the string representation of a node's attribute.
bool setAttributeSvgDouble(Util::const_char_ptr key, double val)
For attributes where an exponent is allowed.
Definition node.cpp:111
void calcDimsFromParentViewport(const SPItemCtx *ictx, bool assign_to_set=false, SPDimensions const *use=nullptr)
Update computed x/y/width/height for "percent" units and/or from its referencing clone parent.
SVGLength y
SVGLength height
SVGLength width
SVGLength x
Typed SVG document implementation.
Definition document.h:101
SPObject * getObjectByRepr(Inkscape::XML::Node *repr) const
SPNamedView * getNamedView()
Get the namedview for this document, creates it if it's not found.
Definition document.cpp:235
Inkscape::Util::Unit const * getDisplayUnit()
guaranteed not to return nullptr
Definition document.cpp:732
void release() override
Inkscape::DrawingItem * show(Inkscape::Drawing &drawing, unsigned int key, unsigned int flags) override
void remove_child(Inkscape::XML::Node *child) override
void print(SPPrintContext *ctx) override
Inkscape::XML::Node * write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, unsigned int flags) override
void set(SPAttr key, char const *value) override
void build(SPDocument *document, Inkscape::XML::Node *repr) override
void child_added(Inkscape::XML::Node *child, Inkscape::XML::Node *ref) override
void modified(unsigned int flags) override
void update(SPCtx *ctx, unsigned int flags) override
Geom::Affine transform
Definition sp-item.h:138
std::vector< SPItemView > views
Definition sp-item.h:163
void updateViewPort()
Update the visibility of the viewport space.
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
SPDocument * document
Definition sp-object.h:188
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.
unsigned int cloned
Definition sp-object.h:180
ChildrenList children
Definition sp-object.h:907
void requestDisplayUpdate(unsigned int flags)
Queues an deferred update of this object's display.
Inkscape::Version inkscape_version
Definition sp-root.h:68
void build(SPDocument *document, Inkscape::XML::Node *repr) override
Definition sp-root.cpp:63
void release() override
Definition sp-root.cpp:95
Inkscape::XML::Node * write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, unsigned int flags) override
Definition sp-root.cpp:312
Inkscape::Version svg_version
Definition sp-root.h:67
void setRootDimensions()
Definition sp-root.cpp:221
void set(SPAttr key, char const *value) override
Definition sp-root.cpp:103
~SPRoot() override
char * onload
Definition sp-root.h:37
void remove_child(Inkscape::XML::Node *child) override
Definition sp-root.cpp:198
SVGLength root_y
Definition sp-root.h:64
Inkscape::DrawingItem * show(Inkscape::Drawing &drawing, unsigned int key, unsigned int flags) override
Definition sp-root.cpp:353
void print(SPPrintContext *ctx) override
Definition sp-root.cpp:374
void unset_x_and_y()
Definition sp-root.cpp:57
void child_added(Inkscape::XML::Node *child, Inkscape::XML::Node *ref) override
Definition sp-root.cpp:177
void update(SPCtx *ctx, unsigned int flags) override
Definition sp-root.cpp:268
const char * displayName() const override
The item's type name as a translated human string.
Definition sp-root.cpp:387
SVGLength root_x
Definition sp-root.h:63
void modified(unsigned int flags) override
Definition sp-root.cpp:301
const char * typeName() const override
The item's type name, not node tag name.
Definition sp-root.cpp:383
SPDefs * defs
Primary <defs> element where we put new defs (patterns, gradients etc.).
Definition sp-root.h:45
SPRoot()
Definition sp-root.cpp:43
void set_viewBox(const gchar *value)
Definition viewbox.cpp:50
Geom::Rect viewBox
Definition viewbox.h:35
Geom::Affine c2p
Definition viewbox.h:43
void set_preserveAspectRatio(const gchar *value)
Definition viewbox.cpp:98
void write_preserveAspectRatio(Inkscape::XML::Node *repr) const
Write preserveAspectRatio attribute to XML, if set.
Definition viewbox.cpp:305
SPItemCtx get_rctx(const SPItemCtx *ictx, double scale_none=1.0)
Definition viewbox.cpp:260
void write_viewBox(Inkscape::XML::Node *repr) const
Write viewBox attribute to XML, if set.
Definition viewbox.cpp:289
bool viewBox_set
Definition viewbox.h:34
void set(Unit u, float v)
bool read(char const *str)
float value
Definition svg-length.h:47
bool _set
Definition svg-length.h:41
void unset(Unit u=NONE, float v=0, float c=0)
Unit unit
Definition svg-length.h:44
float computed
Definition svg-length.h:50
double c[8][4]
static char const *const parent
Definition dir-util.cpp:70
Group belonging to an SVG drawing element.
Affine identity()
Create an identity matrix.
Definition affine.h:210
Helper class to stream background task notifications as a series of messages.
static cairo_user_data_key_t key
Ocnode * child[8]
Definition quantize.cpp:33
Ocnode ** ref
Definition quantize.cpp:32
Axis-aligned rectangle.
Some things pertinent to all visible shapes: SPItem, SPItemView, SPItemCtx.
SPRoot: SVG <svg> implementation.
Interface for XML documents.
Definition document.h:43
Unused.
Definition sp-object.h:94
Contains transformations to document/viewport and the viewport size.
Definition sp-item.h:92
std::string sp_svg_length_write_with_units(SVGLength const &length)
N.B. This routine will sometimes return strings with ā€˜e’ notation, so is unsuitable for CSS lengths (...
Interface for XML documents.