1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /** @file
3  * @brief C facade to Inkscape::XML::Node
4  */
5 /* Authors:
6  *   Lauris Kaplinski <lauris@kaplinski.com>
7  *   Jon A. Cruz <jon@joncruz.org>
8  *
9  * Copyright (C) 1999-2002 authors
10  * Copyright (C) 2000-2002 Ximian, Inc.
11  *
12  * Released under GNU GPL v2+, read the file 'COPYING' for more information.
13  */
14 
15 #ifndef SEEN_SP_REPR_H
16 #define SEEN_SP_REPR_H
17 
18 #include <vector>
19 #include <glibmm/quark.h>
20 
21 #include "xml/node.h"
22 #include "xml/document.h"
23 
24 #define SP_SODIPODI_NS_URI "http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
25 #define SP_BROKEN_SODIPODI_NS_URI "http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
26 #define SP_INKSCAPE_NS_URI "http://www.inkscape.org/namespaces/inkscape"
27 #define SP_XLINK_NS_URI "http://www.w3.org/1999/xlink"
28 #define SP_SVG_NS_URI "http://www.w3.org/2000/svg"
29 #define SP_RDF_NS_URI "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
30 #define SP_CC_NS_URI "http://creativecommons.org/ns#"
31 #define SP_OLD_CC_NS_URI "http://web.resource.org/cc/"
32 #define SP_DC_NS_URI "http://purl.org/dc/elements/1.1/"
33 
34 class SPCSSAttr;
35 class SVGLength;
36 
37 namespace Inkscape {
38 namespace IO {
39 class Writer;
40 } // namespace IO
41 } // namespace Inkscape
42 
43 namespace Geom {
44 class Point;
45 }
46 
47 /* SPXMLNs */
48 char const *sp_xml_ns_uri_prefix(char const *uri, char const *suggested);
49 char const *sp_xml_ns_prefix_uri(char const *prefix);
50 
51 Inkscape::XML::Document *sp_repr_document_new(char const *rootname);
52 
53 /* IO */
54 
55 Inkscape::XML::Document *sp_repr_read_file(char const *filename, char const *default_ns);
56 Inkscape::XML::Document *sp_repr_read_mem(char const *buffer, int length, char const *default_ns);
57 void sp_repr_write_stream(Inkscape::XML::Node *repr, Inkscape::IO::Writer &out,
58                           int indent_level,  bool add_whitespace, Glib::QueryQuark elide_prefix,
59                           int inlineattrs, int indent,
60                           char const *old_href_base = nullptr,
61                           char const *new_href_base = nullptr);
62 Inkscape::XML::Document *sp_repr_read_buf (const Glib::ustring &buf, const char *default_ns);
63 Glib::ustring sp_repr_save_buf(Inkscape::XML::Document *doc);
64 
65 // TODO convert to std::string
66 void sp_repr_save_stream(Inkscape::XML::Document *doc, FILE *to_file,
67                          char const *default_ns = nullptr, bool compress = false,
68                          char const *old_href_base = nullptr,
69                          char const *new_href_base = nullptr);
70 
71 bool sp_repr_save_file(Inkscape::XML::Document *doc, char const *filename, char const *default_ns=nullptr);
72 bool sp_repr_save_rebased_file(Inkscape::XML::Document *doc, char const *filename_utf8,
73                                char const *default_ns,
74                                char const *old_base, char const *new_base_filename);
75 
76 
77 /* CSS stuff */
78 
79 SPCSSAttr *sp_repr_css_attr_new();
80 void sp_repr_css_attr_unref(SPCSSAttr *css);
81 SPCSSAttr *sp_repr_css_attr(Inkscape::XML::Node const *repr, char const *attr);
82 SPCSSAttr *sp_repr_css_attr_inherited(Inkscape::XML::Node const *repr, char const *attr);
83 SPCSSAttr *sp_repr_css_attr_unset_all(SPCSSAttr *css);
84 
85 char const *sp_repr_css_property(SPCSSAttr *css, char const *name, char const *defval);
86 Glib::ustring sp_repr_css_property(SPCSSAttr *css, Glib::ustring const &name, Glib::ustring const &defval);
87 void sp_repr_css_set_property(SPCSSAttr *css, char const *name, char const *value);
88 void sp_repr_css_unset_property(SPCSSAttr *css, char const *name);
89 bool sp_repr_css_property_is_unset(SPCSSAttr *css, char const *name);
90 double sp_repr_css_double_property(SPCSSAttr *css, char const *name, double defval);
91 
92 void sp_repr_css_write_string(SPCSSAttr *css, Glib::ustring &str);
93 void sp_repr_css_set(Inkscape::XML::Node *repr, SPCSSAttr *css, char const *key);
94 void sp_repr_css_merge(SPCSSAttr *dst, SPCSSAttr *src);
95 void sp_repr_css_attr_add_from_string(SPCSSAttr *css, const char *data);
96 void sp_repr_css_change(Inkscape::XML::Node *repr, SPCSSAttr *css, char const *key);
97 void sp_repr_css_change_recursive(Inkscape::XML::Node *repr, SPCSSAttr *css, char const *key);
98 void sp_repr_css_print(SPCSSAttr *css);
99 
100 /* Utility finctions */
101 /// Remove \a repr from children of its parent node.
sp_repr_unparent(Inkscape::XML::Node * repr)102 inline void sp_repr_unparent(Inkscape::XML::Node *repr) {
103     if (repr) {
104         Inkscape::XML::Node *parent=repr->parent();
105         if (parent) {
106             parent->removeChild(repr);
107         }
108     }
109 }
110 
111 bool sp_repr_is_meta_element(const Inkscape::XML::Node *node);
112 
113 /* Convenience */
114 unsigned sp_repr_get_boolean(Inkscape::XML::Node *repr, char const *key, unsigned *val);
115 unsigned sp_repr_get_int(Inkscape::XML::Node *repr, char const *key, int *val);
116 unsigned sp_repr_get_double(Inkscape::XML::Node *repr, char const *key, double *val);
117 unsigned sp_repr_set_boolean(Inkscape::XML::Node *repr, char const *key, unsigned val);
118 unsigned sp_repr_set_int(Inkscape::XML::Node *repr, char const *key, int val);
119 unsigned sp_repr_set_css_double(Inkscape::XML::Node *repr, char const *key, double val);
120 unsigned sp_repr_set_svg_double(Inkscape::XML::Node *repr, char const *key, double val);
121 unsigned sp_repr_set_svg_non_default_double(Inkscape::XML::Node *repr, char const *key, double val, double default_value);
122 unsigned sp_repr_set_svg_length(Inkscape::XML::Node *repr, char const *key, SVGLength &val);
123 unsigned sp_repr_set_point(Inkscape::XML::Node *repr, char const *key, Geom::Point const & val);
124 unsigned sp_repr_get_point(Inkscape::XML::Node *repr, char const *key, Geom::Point *val);
125 
126 //c++-style comparison : returns (bool)(a<b)
127 int sp_repr_compare_position(Inkscape::XML::Node const *first, Inkscape::XML::Node const *second);
128 bool sp_repr_compare_position_bool(Inkscape::XML::Node const *first, Inkscape::XML::Node const *second);
129 
130 // Searching
131 /**
132  * @brief Find an element node with the given name.
133  *
134  * This function searches the descendants of the specified node depth-first for
135  * the first XML node with the specified name.
136  *
137  * @param repr The node to start from
138  * @param name The name of the element node to find
139  * @param maxdepth Maximum search depth, or -1 for an unlimited depth
140  * @return  A pointer to the matching Inkscape::XML::Node
141  * @relatesalso Inkscape::XML::Node
142  */
143 Inkscape::XML::Node *sp_repr_lookup_name(Inkscape::XML::Node *repr,
144                                          char const *name,
145                                          int maxdepth = -1);
146 
147 Inkscape::XML::Node const *sp_repr_lookup_name(Inkscape::XML::Node const *repr,
148                                                char const *name,
149                                                int maxdepth = -1);
150 
151 std::vector<Inkscape::XML::Node const *> sp_repr_lookup_name_many(Inkscape::XML::Node const *repr,
152                                                                   char const *name,
153                                                                   int maxdepth = -1);
154 
155 // Find an element node using an unique attribute.
156 Inkscape::XML::Node *sp_repr_lookup_child(Inkscape::XML::Node *repr,
157                                           char const *key,
158                                           char const *value);
159 
160 // Find an element node using an unique attribute recursively.
161 Inkscape::XML::Node *sp_repr_lookup_descendant(Inkscape::XML::Node *repr,
162                                                char const *key,
163                                                char const *value);
164 
165 Inkscape::XML::Node const *sp_repr_lookup_descendant(Inkscape::XML::Node const *repr,
166                                                      char const *key,
167                                                      char const *value);
168 
169 // Find element nodes using a property value.
170 std::vector<Inkscape::XML::Node *> sp_repr_lookup_property_many(Inkscape::XML::Node *repr,
171                                                                 Glib::ustring const &property,
172                                                                 Glib::ustring const &value,
173                                                                 int maxdepth = -1);
174 
sp_repr_document_first_child(Inkscape::XML::Document const * doc)175 inline Inkscape::XML::Node *sp_repr_document_first_child(Inkscape::XML::Document const *doc) {
176     return const_cast<Inkscape::XML::Node *>(doc->firstChild());
177 }
178 
sp_repr_is_def(Inkscape::XML::Node const * node)179 inline bool sp_repr_is_def(Inkscape::XML::Node const *node) {
180     return node->parent() != nullptr &&
181         node->parent()->name() != nullptr &&
182         strcmp("svg:defs", node->parent()->name()) == 0;
183 }
184 
sp_repr_is_layer(Inkscape::XML::Node const * node)185 inline bool sp_repr_is_layer(Inkscape::XML::Node const *node) {
186     return node->attribute("inkscape:groupmode") != nullptr &&
187         strcmp("layer", node->attribute("inkscape:groupmode")) == 0;
188 }
189 
190 /**
191  * @brief Visit all descendants recursively.
192  *
193  * Traverse all descendants of node and call visitor on it.
194  * Stop descending when visitor returns false
195  *
196  * @param node The root node to start visiting
197  * @param visitor The visitor lambda (Node *) -> bool
198  *                If visitor returns false child nodes of current node are not visited.
199  * @relatesalso Inkscape::XML::Node
200  */
201 template <typename Visitor>
sp_repr_visit_descendants(Inkscape::XML::Node * node,Visitor visitor)202 void sp_repr_visit_descendants(Inkscape::XML::Node *node, Visitor visitor) {
203     if (!visitor(node)) {
204         return;
205     }
206     for (Inkscape::XML::Node *child = node->firstChild();
207             child != nullptr;
208             child = child->next()) {
209         sp_repr_visit_descendants(child, visitor);
210     }
211 }
212 
213 /**
214  * @brief Visit descendants of 2 nodes in parallel.
215  * The assumption is that one a and b trees are the same in terms of structure (like one is
216  * a duplicate of the other).
217  *
218  * @param a first node tree root
219  * @param b second node tree root
220  * @param visitor The visitor lambda (Node *, Node *) -> bool
221  *                If visitor returns false child nodes are not visited.
222  * @relatesalso Inkscape::XML::Node
223  */
224 template <typename Visitor>
sp_repr_visit_descendants(Inkscape::XML::Node * a,Inkscape::XML::Node * b,Visitor visitor)225 void sp_repr_visit_descendants(Inkscape::XML::Node *a, Inkscape::XML::Node *b, Visitor visitor) {
226     if (!visitor(a, b)) {
227         return;
228     }
229     for (Inkscape::XML::Node *ac = a->firstChild(), *bc = b->firstChild();
230             ac != nullptr && bc != nullptr;
231             ac = ac->next(), bc = bc->next()) {
232         sp_repr_visit_descendants(ac, bc, visitor);
233     }
234 }
235 
236 #endif // SEEN_SP_REPR_H
237 /*
238   Local Variables:
239   mode:c++
240   c-file-style:"stroustrup"
241   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
242   indent-tabs-mode:nil
243   fill-column:99
244   End:
245 */
246 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
247