summaryrefslogtreecommitdiffstats
path: root/src/xml/repr.h
blob: 4d80f396333f78f03f10405bebc4bdec4eacda73 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
// SPDX-License-Identifier: GPL-2.0-or-later
/** @file
 * @brief C facade to Inkscape::XML::Node
 */
/* Authors:
 *   Lauris Kaplinski <lauris@kaplinski.com>
 *   Jon A. Cruz <jon@joncruz.org>
 *
 * Copyright (C) 1999-2002 authors
 * Copyright (C) 2000-2002 Ximian, Inc.
 *
 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
 */

#ifndef SEEN_SP_REPR_H
#define SEEN_SP_REPR_H

#include <vector>
#include <glibmm/quark.h>

#include "xml/node.h"
#include "xml/document.h"

#define SP_SODIPODI_NS_URI "http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
#define SP_BROKEN_SODIPODI_NS_URI "http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
#define SP_INKSCAPE_NS_URI "http://www.inkscape.org/namespaces/inkscape"
#define SP_XLINK_NS_URI "http://www.w3.org/1999/xlink"
#define SP_SVG_NS_URI "http://www.w3.org/2000/svg"
#define SP_RDF_NS_URI "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
#define SP_CC_NS_URI "http://creativecommons.org/ns#"
#define SP_OLD_CC_NS_URI "http://web.resource.org/cc/"
#define SP_DC_NS_URI "http://purl.org/dc/elements/1.1/"

class SPCSSAttr;
class SVGLength;

namespace Inkscape {
namespace IO {
class Writer;
} // namespace IO
} // namespace Inkscape

namespace Geom {
class Point;
}

/* SPXMLNs */
char const *sp_xml_ns_uri_prefix(char const *uri, char const *suggested);
char const *sp_xml_ns_prefix_uri(char const *prefix);

Inkscape::XML::Document *sp_repr_document_new(char const *rootname);

/* IO */

Inkscape::XML::Document *sp_repr_read_file(char const *filename, char const *default_ns);
Inkscape::XML::Document *sp_repr_read_mem(char const *buffer, int length, char const *default_ns);
void sp_repr_write_stream(Inkscape::XML::Node *repr, Inkscape::IO::Writer &out,
                          int indent_level,  bool add_whitespace, Glib::QueryQuark elide_prefix,
                          int inlineattrs, int indent,
                          char const *old_href_base = nullptr,
                          char const *new_href_base = nullptr);
Inkscape::XML::Document *sp_repr_read_buf (const Glib::ustring &buf, const char *default_ns);
Glib::ustring sp_repr_save_buf(Inkscape::XML::Document *doc);

// TODO convert to std::string
void sp_repr_save_stream(Inkscape::XML::Document *doc, FILE *to_file,
                         char const *default_ns = nullptr, bool compress = false,
                         char const *old_href_base = nullptr,
                         char const *new_href_base = nullptr);

bool sp_repr_save_file(Inkscape::XML::Document *doc, char const *filename, char const *default_ns=nullptr);
bool sp_repr_save_rebased_file(Inkscape::XML::Document *doc, char const *filename_utf8,
                               char const *default_ns,
                               char const *old_base, char const *new_base_filename);


/* CSS stuff */

SPCSSAttr *sp_repr_css_attr_new();
void sp_repr_css_attr_unref(SPCSSAttr *css);
SPCSSAttr *sp_repr_css_attr(Inkscape::XML::Node const *repr, char const *attr);
SPCSSAttr *sp_repr_css_attr_inherited(Inkscape::XML::Node const *repr, char const *attr);
SPCSSAttr *sp_repr_css_attr_unset_all(SPCSSAttr *css);

char const *sp_repr_css_property(SPCSSAttr *css, char const *name, char const *defval);
Glib::ustring sp_repr_css_property(SPCSSAttr *css, Glib::ustring const &name, Glib::ustring const &defval);
void sp_repr_css_set_property(SPCSSAttr *css, char const *name, char const *value);
void sp_repr_css_unset_property(SPCSSAttr *css, char const *name);
bool sp_repr_css_property_is_unset(SPCSSAttr *css, char const *name);
double sp_repr_css_double_property(SPCSSAttr *css, char const *name, double defval);
void sp_repr_css_set_property_double(SPCSSAttr *css, char const *name, double value);

void sp_repr_css_write_string(SPCSSAttr *css, Glib::ustring &str);
void sp_repr_css_set(Inkscape::XML::Node *repr, SPCSSAttr *css, char const *key);
void sp_repr_css_merge(SPCSSAttr *dst, SPCSSAttr *src);
void sp_repr_css_attr_add_from_string(SPCSSAttr *css, const char *data);
void sp_repr_css_change(Inkscape::XML::Node *repr, SPCSSAttr *css, char const *key);
void sp_repr_css_change_recursive(Inkscape::XML::Node *repr, SPCSSAttr *css, char const *key);
void sp_repr_css_print(SPCSSAttr *css);

/* Utility finctions */
/// Remove \a repr from children of its parent node.
inline void sp_repr_unparent(Inkscape::XML::Node *repr) {
    if (repr) {
        Inkscape::XML::Node *parent=repr->parent();
        if (parent) {
            parent->removeChild(repr);
        }
    }
}

bool sp_repr_is_meta_element(const Inkscape::XML::Node *node);

//c++-style comparison : returns (bool)(a<b)
int sp_repr_compare_position(Inkscape::XML::Node const *first, Inkscape::XML::Node const *second);
bool sp_repr_compare_position_bool(Inkscape::XML::Node const *first, Inkscape::XML::Node const *second);

// Searching
/**
 * @brief Find an element node with the given name.
 *
 * This function searches the descendants of the specified node depth-first for
 * the first XML node with the specified name.
 *
 * @param repr The node to start from
 * @param name The name of the element node to find
 * @param maxdepth Maximum search depth, or -1 for an unlimited depth
 * @return  A pointer to the matching Inkscape::XML::Node
 * @relatesalso Inkscape::XML::Node
 */
Inkscape::XML::Node *sp_repr_lookup_name(Inkscape::XML::Node *repr,
                                         char const *name,
                                         int maxdepth = -1);

Inkscape::XML::Node const *sp_repr_lookup_name(Inkscape::XML::Node const *repr,
                                               char const *name,
                                               int maxdepth = -1);

std::vector<Inkscape::XML::Node const *> sp_repr_lookup_name_many(Inkscape::XML::Node const *repr,
                                                                  char const *name,
                                                                  int maxdepth = -1);

// Find an element node using an unique attribute.
Inkscape::XML::Node *sp_repr_lookup_child(Inkscape::XML::Node *repr,
                                          char const *key,
                                          char const *value);

// Find an element node using an unique attribute recursively.
Inkscape::XML::Node *sp_repr_lookup_descendant(Inkscape::XML::Node *repr,
                                               char const *key,
                                               char const *value);

Inkscape::XML::Node const *sp_repr_lookup_descendant(Inkscape::XML::Node const *repr,
                                                     char const *key,
                                                     char const *value);

// Find element nodes using a property value.
std::vector<Inkscape::XML::Node *> sp_repr_lookup_property_many(Inkscape::XML::Node *repr,
                                                                Glib::ustring const &property,
                                                                Glib::ustring const &value,
                                                                int maxdepth = -1);

inline Inkscape::XML::Node *sp_repr_document_first_child(Inkscape::XML::Document const *doc) {
    return const_cast<Inkscape::XML::Node *>(doc->firstChild());
}

inline bool sp_repr_is_def(Inkscape::XML::Node const *node) {
    return node->parent() != nullptr &&
        node->parent()->name() != nullptr &&
        strcmp("svg:defs", node->parent()->name()) == 0;
}

inline bool sp_repr_is_layer(Inkscape::XML::Node const *node) {
    return node->attribute("inkscape:groupmode") != nullptr &&
        strcmp("layer", node->attribute("inkscape:groupmode")) == 0;
}

/**
 * @brief Visit all descendants recursively.
 *
 * Traverse all descendants of node and call visitor on it.
 * Stop descending when visitor returns false
 *
 * @param node The root node to start visiting
 * @param visitor The visitor lambda (Node *) -> bool
 *                If visitor returns false child nodes of current node are not visited.
 * @relatesalso Inkscape::XML::Node
 */
template <typename Visitor>
void sp_repr_visit_descendants(Inkscape::XML::Node *node, Visitor visitor) {
    if (!visitor(node)) {
        return;
    }
    for (Inkscape::XML::Node *child = node->firstChild();
            child != nullptr;
            child = child->next()) {
        sp_repr_visit_descendants(child, visitor);
    }
}

/**
 * @brief Visit descendants of 2 nodes in parallel.
 * The assumption is that one a and b trees are the same in terms of structure (like one is
 * a duplicate of the other).
 *
 * @param a first node tree root
 * @param b second node tree root
 * @param visitor The visitor lambda (Node *, Node *) -> bool
 *                If visitor returns false child nodes are not visited.
 * @relatesalso Inkscape::XML::Node
 */
template <typename Visitor>
void sp_repr_visit_descendants(Inkscape::XML::Node *a, Inkscape::XML::Node *b, Visitor visitor) {
    if (!visitor(a, b)) {
        return;
    }
    for (Inkscape::XML::Node *ac = a->firstChild(), *bc = b->firstChild();
            ac != nullptr && bc != nullptr;
            ac = ac->next(), bc = bc->next()) {
        sp_repr_visit_descendants(ac, bc, visitor);
    }
}

#endif // SEEN_SP_REPR_H
/*
  Local Variables:
  mode:c++
  c-file-style:"stroustrup"
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
  indent-tabs-mode:nil
  fill-column:99
  End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :