Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
attribute-rel-util.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
/*
5 * Authors: see git history
6 *
7 * Copyright (C) 2018 Authors
8 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
9 */
10/*
11 * attribute-rel-util.h
12 *
13 * Created on: Sep 8, 2011
14 * Author: tavmjong
15 */
16
21#include "attribute-rel-util.h"
22
23#include <fstream>
24#include <iostream>
25#include <sstream>
26
27#include <2geom/path-sink.h>
29
30#include "attribute-rel-css.h"
31#include "attribute-rel-svg.h"
32#include "preferences.h"
34
36
41{
43 unsigned int flags = 0;
44 if (prefs->getBool("/options/svgoutput/incorrect_attributes_warn"))
46 if (prefs->getBool("/options/svgoutput/incorrect_attributes_remove") &&
47 !prefs->getBool("/options/svgoutput/disable_optimizations"))
49 if (prefs->getBool("/options/svgoutput/incorrect_style_properties_warn"))
51 if (prefs->getBool("/options/svgoutput/incorrect_style_properties_remove") &&
52 !prefs->getBool("/options/svgoutput/disable_optimizations"))
54 if (prefs->getBool("/options/svgoutput/style_defaults_warn"))
56 if (prefs->getBool("/options/svgoutput/style_defaults_remove") &&
57 !prefs->getBool("/options/svgoutput/disable_optimizations"))
59
60 return flags;
61}
62
68{
69 g_return_if_fail(repr != nullptr);
70
71 unsigned int flags = sp_attribute_clean_get_prefs();
72
73 if (flags) {
75 }
76}
77
81void sp_attribute_clean_recursive(Node *repr, unsigned int flags)
82{
83 g_return_if_fail(repr != nullptr);
84
86 Glib::ustring element = repr->name();
87
88 // Only clean elements in svg namespace
89 if (element.substr(0, 4) == "svg:") {
90 sp_attribute_clean_element(repr, flags);
91 }
92 }
93
94 for (Node *child = repr->firstChild(); child; child = child->next()) {
95 // Don't remove default css values if element is in <defs> or is a <symbol>
96 Glib::ustring element = child->name();
97 unsigned int flags_temp = flags;
98 if (element.compare("svg:defs") == 0 || element.compare("svg:symbol") == 0) {
100 }
102 }
103}
104
108void sp_attribute_clean_element(Node *repr, unsigned int flags)
109{
110 g_return_if_fail(repr != nullptr);
111 g_return_if_fail(repr->type() == Inkscape::XML::NodeType::ELEMENT_NODE);
112
113 Glib::ustring element = repr->name();
114 Glib::ustring id = (repr->attribute("id") == nullptr ? "" : repr->attribute("id"));
115
116 // Clean style: this attribute is unique in that normally we want to change it and not simply
117 // delete it.
118 sp_attribute_clean_style(repr, flags);
119
120 // Clean attributes
121 std::set<Glib::ustring> attributesToDelete;
122 for (const auto &iter : repr->attributeList()) {
123 Glib::ustring attribute = g_quark_to_string(iter.key);
124 // Glib::ustring value = (const char*)iter->value;
125
126 bool is_useful = sp_attribute_check_attribute(element, id, attribute, flags & SP_ATTRCLEAN_ATTR_WARN);
127 if (!is_useful && (flags & SP_ATTRCLEAN_ATTR_REMOVE)) {
128 attributesToDelete.insert(attribute);
129 }
130 }
131
132 // Do actual deleting (done after so as not to perturb List iterator).
133 for (const auto &iter_d : attributesToDelete) {
134 repr->removeAttribute(iter_d);
135 }
136}
137
141void sp_attribute_clean_style(Node *repr, unsigned int flags)
142{
143 g_return_if_fail(repr != nullptr);
144 g_return_if_fail(repr->type() == Inkscape::XML::NodeType::ELEMENT_NODE);
145
146 // Find element's style
147 SPCSSAttr *css = sp_repr_css_attr(repr, "style");
148 sp_attribute_clean_style(repr, css, flags);
149
150 // Convert css node's properties data to string and set repr node's attribute "style" to that string.
151 // sp_repr_css_set( repr, css, "style"); // Don't use as it will cause loop.
152 Glib::ustring value;
154 repr->setAttributeOrRemoveIfEmpty("style", value);
155
157}
158
162Glib::ustring sp_attribute_clean_style(Node *repr, gchar const *string, unsigned int flags)
163{
164 g_return_val_if_fail(repr != nullptr, "");
165 g_return_val_if_fail(repr->type() == Inkscape::XML::NodeType::ELEMENT_NODE, "");
166
169 sp_attribute_clean_style(repr, css, flags);
170 Glib::ustring string_cleaned;
171 sp_repr_css_write_string(css, string_cleaned);
172
174
175 return string_cleaned;
176}
177
187void sp_attribute_clean_style(Node *repr, SPCSSAttr *css, unsigned int flags)
188{
189 g_return_if_fail(repr != nullptr);
190 g_return_if_fail(css != nullptr);
191
192 Glib::ustring element = repr->name();
193 Glib::ustring id = (repr->attribute("id") == nullptr ? "" : repr->attribute("id"));
194
195 // Find parent's style, including properties that are inherited.
196 // Note, a node may not have a parent if it has not yet been added to tree.
197 SPCSSAttr *css_parent = nullptr;
198 if (repr->parent())
199 css_parent = sp_repr_css_attr_inherited(repr->parent(), "style");
200
201 // Loop over all properties in "style" node, keeping track of which to delete.
202 std::set<Glib::ustring> toDelete;
203 for (const auto &iter : css->attributeList()) {
204 Glib::ustring property = g_quark_to_string(iter.key);
205 gchar const *value = iter.value;
206
207 // Check if a property is applicable to an element (i.e. is font-family useful for a <rect>?).
208 if (!SPAttributeRelCSS::findIfValid(property, element)) {
209 if (flags & SP_ATTRCLEAN_STYLE_WARN) {
210 g_warning("<%s id=\"%s\">: CSS Style property: \"%s\" is inappropriate.", element.c_str(), id.c_str(),
211 property.c_str());
212 }
213 if (flags & SP_ATTRCLEAN_STYLE_REMOVE) {
214 toDelete.insert(property);
215 }
216 continue;
217 }
218
219 // Find parent value for same property (property)
220 gchar const *value_p = nullptr;
221 if (css_parent != nullptr) {
222 for (const auto &iter_p : css_parent->attributeList()) {
223 gchar const *property_p = g_quark_to_string(iter_p.key);
224
225 if (!g_strcmp0(property.c_str(), property_p)) {
226 value_p = iter_p.value;
227 break;
228 }
229 }
230 }
231
232 // If parent has same property value and property is inherited, mark for deletion.
233 if (!g_strcmp0(value, value_p) && SPAttributeRelCSS::findIfInherit(property)) {
234 if (flags & SP_ATTRCLEAN_DEFAULT_WARN) {
235 g_warning("<%s id=\"%s\">: CSS Style property: \"%s\" has same value as parent (%s).", element.c_str(),
236 id.c_str(), property.c_str(), value);
237 }
238 if (flags & SP_ATTRCLEAN_DEFAULT_REMOVE) {
239 toDelete.insert(property);
240 }
241 continue;
242 }
243
244 // If property value is same as default and the parent value not set or property is not inherited,
245 // mark for deletion.
246 if (SPAttributeRelCSS::findIfDefault(property, value) &&
247 ((value_p == nullptr) || !SPAttributeRelCSS::findIfInherit(property))) {
248 if (flags & SP_ATTRCLEAN_DEFAULT_WARN) {
249 g_warning("<%s id=\"%s\">: CSS Style property: \"%s\" with default value (%s) not needed.",
250 element.c_str(), id.c_str(), property.c_str(), value);
251 }
252 if (flags & SP_ATTRCLEAN_DEFAULT_REMOVE) {
253 toDelete.insert(property);
254 }
255 continue;
256 }
257
258 } // End loop over style properties
259
260 // Delete unneeded style properties. Do this at the end so as to not perturb List iterator.
261 for (const auto &iter_d : toDelete) {
262 sp_repr_css_set_property(css, iter_d.c_str(), nullptr);
263 }
264}
265
270{
271 g_return_if_fail(css != nullptr);
272
273 // Loop over all properties in "style" node, keeping track of which to delete.
274 std::set<Glib::ustring> toDelete;
275 for (const auto &iter : css->attributeList()) {
276 Glib::ustring property = g_quark_to_string(iter.key);
277 gchar const *value = iter.value;
278
279 // If property value is same as default mark for deletion.
280 if (SPAttributeRelCSS::findIfDefault(property, value)) {
281 if (flags & SP_ATTRCLEAN_DEFAULT_WARN) {
282 g_warning("Preferences CSS Style property: \"%s\" with default value (%s) not needed.",
283 property.c_str(), value);
284 }
285 if (flags & SP_ATTRCLEAN_DEFAULT_REMOVE) {
286 toDelete.insert(property);
287 }
288 continue;
289 }
290
291 } // End loop over style properties
292
293 // Delete unneeded style properties. Do this at the end so as to not perturb List iterator.
294 for (const auto &iter_d : toDelete) {
295 sp_repr_css_set_property(css, iter_d.c_str(), nullptr);
296 }
297}
298
302bool sp_attribute_check_attribute(Glib::ustring const &element, Glib::ustring const &id, Glib::ustring const &attribute,
303 bool warn)
304{
305 bool is_useful = true;
306
307 if (SPAttributeRelCSS::findIfProperty(attribute)) {
308 // First check if it is a presentation attribute. Presentation attributes can be applied to
309 // any element. At the moment, we are only going to check if it is a possibly useful
310 // attribute. Note, we don't explicitly check against the list of elements where presentation
311 // attributes are allowed (See SVG1.1 spec, Appendix M.2).
312 if (!SPAttributeRelCSS::findIfValid(attribute, element)) {
313 // Non-useful presentation attribute on SVG <element>
314 if (warn) {
315 g_warning("<%s id=\"%s\">: Non-useful presentation attribute: \"%s\" found.", element.c_str(),
316 id.c_str(), attribute.c_str());
317 }
318 is_useful = false;
319 }
320
321 } else {
322 // Second check if it is a valid attribute
323 if (!SPAttributeRelSVG::findIfValid(attribute, element)) {
324 // Invalid attribute on SVG <element>
325 if (warn) {
326 g_warning("<%s id=\"%s\">: Invalid attribute: \"%s\" found.", element.c_str(), id.c_str(),
327 attribute.c_str());
328 }
329 is_useful = false;
330 }
331 }
332
333 return is_useful;
334}
335
336bool sp_is_valid_svg_path_d(Glib::ustring const &d)
337{
339 class PathBlackHole final : public Geom::PathSink
340 {
342 void moveTo(Geom::Point const &) final {}
343 void lineTo(Geom::Point const &) final {}
344 void curveTo(Geom::Point const &, Geom::Point const &, Geom::Point const &) final {}
345 void quadTo(Geom::Point const &, Geom::Point const &) final {}
346 void arcTo(Geom::Coord, Geom::Coord, Geom::Coord, bool, bool, Geom::Point const &) final {}
347 void closePath() final {}
348 void flush() final {}
349 void feed(Geom::Curve const &, bool) final {}
350 void feed(Geom::Path const &) final {}
351 void feed(Geom::PathVector const &) final {}
352 void feed(Geom::Rect const &) final {}
353 void feed(Geom::Circle const &) final {}
354 void feed(Geom::Ellipse const &) final {}
355 } dev_null;
356
357 auto validator = Geom::SVGPathParser(dev_null);
358 try {
359 validator.parse(static_cast<std::string>(d));
360 } catch (Geom::SVGPathParseError &) {
361 return false;
362 }
363 return true;
364}
365
366/*
367 Local Variables:
368 mode:c++
369 c-file-style:"stroustrup"
370 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
371 indent-tabs-mode:nil
372 fill-column:99
373 End:
374*/
375// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
TODO: insert short description here.
TODO: insert short description here.
TODO: insert short description here.
unsigned int sp_attribute_clean_get_prefs()
Get preferences.
void sp_attribute_clean_tree(Node *repr)
Remove or warn about inappropriate attributes and useless stype properties.
void sp_attribute_clean_recursive(Node *repr, unsigned int flags)
Clean recursively over all elements.
bool sp_is_valid_svg_path_d(Glib::ustring const &d)
Check whether the 'd' attribute on a <path> element parses correctly.
void sp_attribute_clean_style(Node *repr, unsigned int flags)
Clean CSS style on an element.
void sp_attribute_clean_element(Node *repr, unsigned int flags)
Clean attributes on an element.
bool sp_attribute_check_attribute(Glib::ustring const &element, Glib::ustring const &id, Glib::ustring const &attribute, bool warn)
Check one attribute on an element.
void sp_attribute_purge_default_style(SPCSSAttr *css, unsigned int flags)
Remove CSS style properties with default values.
Utility functions related to parsing and validation of XML attributes.
@ SP_ATTRCLEAN_STYLE_WARN
@ SP_ATTRCLEAN_ATTR_WARN
@ SP_ATTRCLEAN_DEFAULT_WARN
@ SP_ATTRCLEAN_ATTR_REMOVE
@ SP_ATTRCLEAN_STYLE_REMOVE
@ SP_ATTRCLEAN_DEFAULT_REMOVE
Set of all points at a fixed distance from the center.
Definition circle.h:55
Abstract continuous curve on a plane defined on [0,1].
Definition curve.h:78
Set of points with a constant sum of distances from two foci.
Definition ellipse.h:68
Callback interface for processing path data.
Definition path-sink.h:56
virtual void feed(Curve const &c, bool moveto_initial=true)
Definition path-sink.cpp:39
Sequence of subpaths.
Definition pathvector.h:122
Sequence of contiguous curves, aka spline.
Definition path.h:353
Two-dimensional point that doubles as a vector.
Definition point.h:66
Axis aligned, non-empty rectangle.
Definition rect.h:92
Read SVG path data and feed it to a PathSink.
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.
Interface for refcounted XML nodes.
Definition node.h:80
virtual Node * parent()=0
Get the parent of this node.
virtual char const * name() const =0
Get the name of the element node.
virtual const AttributeVector & attributeList() const =0
Get a list of the node's attributes.
void setAttributeOrRemoveIfEmpty(Inkscape::Util::const_char_ptr key, Inkscape::Util::const_char_ptr value)
Change an attribute of this node.
Definition node.cpp:167
virtual Node * firstChild()=0
Get the first child of this node.
virtual char const * attribute(char const *key) const =0
Get the string representation of a node's attribute.
void removeAttribute(Inkscape::Util::const_char_ptr key)
Remove an attribute of this node.
Definition node.h:280
virtual NodeType type() const =0
Get the type of the node.
static bool findIfValid(Glib::ustring const &property, Glib::ustring const &element)
static bool findIfProperty(Glib::ustring const &property)
static bool findIfDefault(Glib::ustring const &property, Glib::ustring const &value)
static bool findIfInherit(Glib::ustring const &property)
static bool findIfValid(Glib::ustring const &attribute, Glib::ustring const &element)
std::shared_ptr< Css const > css
double Coord
Floating point type used to store coordinates.
Definition coord.h:76
@ ELEMENT_NODE
Regular element node, e.g. <group />.
callback interface for SVG path data
Singleton class to access the preferences file in a convenient way.
Ocnode * child[8]
Definition quantize.cpp:33
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
SPCSSAttr * sp_repr_css_attr_inherited(Node const *repr, gchar const *attr)
Creates a new SPCSSAttr with one attribute whose value is determined by cascading.
Definition repr-css.cpp:116
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_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
parse SVG path specifications