Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
id-clash.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Routines for resolving ID clashes when importing or pasting.
4 *
5 * Authors:
6 * Stephen Silver <sasilver@users.sourceforge.net>
7 * Jon A. Cruz <jon@joncruz.org>
8 * Abhishek Sharma
9 *
10 * Copyright (C) 2008 authors
11 *
12 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
13 */
14
15#include "id-clash.h"
16
17#include <cstdlib>
18#include <cstring>
19#include <list>
20#include <map>
21#include <string>
22#include <utility>
23
24#include <glibmm/regex.h>
25
26#include "attributes.h" // for SPAttr
27#include "document.h" // for SPDocument
28#include "style-internal.h" // for SPIPaint, SPIShapes
29#include "style.h" // for SPStyle, sp_styl...
30#include "util/uri.h" // for extract_uri
31
32#include "live_effects/effect.h"
35#include "object/sp-gradient.h"
36#include "object/sp-object.h"
38#include "object/sp-root.h"
39#include "object/sp-use.h"
40
42
43struct IdReference {
45 SPObject *elem;
46 const char *attr; // property or href-like attribute
47};
48
49typedef std::map<Glib::ustring, std::list<IdReference> > refmap_type;
50
51typedef std::pair<SPObject*, Glib::ustring> id_changeitem_type;
52typedef std::list<id_changeitem_type> id_changelist_type;
53
54const char *href_like_attributes[] = {"inkscape:connection-end",
55 "inkscape:connection-end-point",
56 "inkscape:connection-start",
57 "inkscape:connection-start-point",
58 "inkscape:href",
59 "inkscape:path-effect",
60 "inkscape:perspectiveID",
61 "inkscape:linked-fill",
62 "inkscape:tiled-clone-of",
63 "href",
64 "xlink:href"};
65#define NUM_HREF_LIKE_ATTRIBUTES (sizeof(href_like_attributes) / sizeof(*href_like_attributes))
66
68 //&SPStyle::color,
69 reinterpret_cast<SPIPaint SPStyle::*>(&SPStyle::fill),
70 reinterpret_cast<SPIPaint SPStyle::*>(&SPStyle::stroke),
71};
72const char* SPIPaint_properties[] = {
73 //"color",
74 "fill",
75 "stroke",
76};
77#define NUM_SPIPAINT_PROPERTIES (sizeof(SPIPaint_properties) / sizeof(*SPIPaint_properties))
78
80 reinterpret_cast<SPIShapes SPStyle::*>(&SPStyle::shape_inside),
81 reinterpret_cast<SPIShapes SPStyle::*>(&SPStyle::shape_subtract),
82};
83const char *SPIShapes_properties[] = {
84 "shape-inside",
85 "shape-subtract",
86};
87#define NUM_SPISHAPES_PROPERTIES (sizeof(SPIShapes_properties) / sizeof(*SPIShapes_properties))
88
89const char* other_url_properties[] = {
90 "clip-path",
91 "color-profile",
92 "cursor",
93 "marker-end",
94 "marker-mid",
95 "marker-start",
96 "mask",
97};
98#define NUM_OTHER_URL_PROPERTIES (sizeof(other_url_properties) / sizeof(*other_url_properties))
99
100const char* clipboard_properties[] = {
101 //"color",
102 "fill",
103 "filter",
104 "stroke",
105 "marker-end",
106 "marker-mid",
107 "marker-start"
108};
109#define NUM_CLIPBOARD_PROPERTIES (sizeof(clipboard_properties) / sizeof(*clipboard_properties))
110
114static void
115fix_ref(IdReference const &idref, SPObject *to_obj, const char *old_id) {
116 switch (idref.type) {
117 case REF_HREF: {
118 if (idref.elem->getAttribute(idref.attr)) {
119 gchar *new_uri = g_strdup_printf("#%s", to_obj->getId());
120 Glib::ustring value = idref.elem->getAttribute(idref.attr);
121 // look to values stores as separated id references like inkscape::path-effect or LPE satellites param
122 Glib::ustring old = "#";
123 old += old_id;
124 size_t posid = value.find(old_id);
125 if (new_uri && posid != Glib::ustring::npos) {
126 if (!g_strcmp0(idref.attr,"inkscape:linked-fill")) {
127 value = value.replace(posid, old.size() - 1, to_obj->getId());
128 } else {
129 value = value.replace(posid - 1, old.size(), new_uri);
130 }
131 idref.elem->setAttribute(idref.attr, value.c_str());
132 }
133 g_free(new_uri);
134 }
135 break;
136 }
137 case REF_STYLE: {
138 sp_style_set_property_url(idref.elem, idref.attr, to_obj, false);
139 break;
140 }
141 case REF_SHAPES: {
142 SPCSSAttr* css = sp_repr_css_attr (idref.elem->getRepr(), "style");
143 std::string prop = sp_repr_css_property (css, idref.attr, nullptr);
144 std::string oid; oid.append("url(#").append(old_id).append(")");
145 auto pos = prop.find(oid);
146 if (pos != std::string::npos) {
147 std::string nid; nid.append("url(#").append(to_obj->getId()).append(")");
148 prop.replace(pos, oid.size(), nid);
149 sp_repr_css_set_property (css, idref.attr, prop.c_str());
150 sp_repr_css_set (idref.elem->getRepr(), css, "style");
151 } else {
152 std::cerr << "Failed to switch id -- shouldn't happen" << std::endl;
153 }
154 break;
155 }
156 case REF_URL: {
157 gchar *url = g_strdup_printf("url(#%s)", to_obj->getId());
158 idref.elem->setAttribute(idref.attr, url);
159 g_free(url);
160 break;
161 }
162 case REF_CLIPBOARD: {
163 SPCSSAttr *style = sp_repr_css_attr(idref.elem->getRepr(), "style");
164 gchar *url = g_strdup_printf("url(#%s)", to_obj->getId());
165 sp_repr_css_set_property(style, idref.attr, url);
166 g_free(url);
167 Glib::ustring style_string;
168 sp_repr_css_write_string(style, style_string);
169 idref.elem->setAttributeOrRemoveIfEmpty("style", style_string);
170 break;
171 }
172 }
173}
174
180static void find_references(SPObject *elem, refmap_type &refmap, bool from_clipboard)
181{
182 if (elem->cloned) return;
183 Inkscape::XML::Node *repr_elem = elem->getRepr();
184 if (!repr_elem) return;
185 if (repr_elem->type() != Inkscape::XML::NodeType::ELEMENT_NODE) return;
186
187 /* check for references in inkscape:clipboard elements */
188 if (!std::strcmp(repr_elem->name(), "inkscape:clipboard")) {
189 SPCSSAttr *css = sp_repr_css_attr(repr_elem, "style");
190 if (css) {
191 for (auto attr : clipboard_properties) {
192 const gchar *value = sp_repr_css_property(css, attr, nullptr);
193 if (value) {
194 auto uri = extract_uri(value);
195 if (uri[0] == '#') {
196 IdReference idref = { REF_CLIPBOARD, elem, attr };
197 refmap[uri.c_str() + 1].push_back(idref);
198 }
199 }
200 }
201
202 }
203 // TODO: uncomment if clipboard issues
204 // if (!from_clipboard) {
205 // return; // nothing more to do for inkscape:clipboard elements
206 //}
207 }
208 if (!std::strcmp(repr_elem->name(), "inkscape:path-effect")) {
209 auto lpeobj = cast<LivePathEffectObject>(elem);
210 if (lpeobj) {
211 Inkscape::LivePathEffect::Effect *effect = lpeobj->get_lpe();
212 if (effect) {
213 for (auto &p : effect->param_vector) {
214 if (p->paramType() == Inkscape::LivePathEffect::SATELLITE ||
216 p->paramType() == Inkscape::LivePathEffect::PATH ||
217 p->paramType() == Inkscape::LivePathEffect::PATH_ARRAY ||
218 p->paramType() == Inkscape::LivePathEffect::ORIGINAL_PATH ||
220 {
221 const gchar *val = repr_elem->attribute(p->param_key.c_str());
222 if (val) {
223 gchar **strarray = g_strsplit(val, "|", 0);
224 if (strarray) {
225 unsigned int i = 0;
226 Glib::ustring realycopied = "";
227 bool write = false;
228 while (strarray[i]) {
229 gchar *splitid = g_strdup(g_strstrip(strarray[i]));
230 if (splitid[0] == '#') {
231 std::string id(splitid + 1);
232 if (size_t pos = id.find(",")) {
233 if (pos != Glib::ustring::npos) {
234 id.erase(pos);
235 }
236 }
237
238 IdReference idref = {REF_HREF, elem, p->param_key.c_str()};
239 SPObject *refobj = elem->document->getObjectById(id);
240 // special tweak to allow clone original LPE keep cloned on copypase without
241 // operand also added to path parameters
242 bool cloneoriginal = p->effectType() == Inkscape::LivePathEffect::CLONE_ORIGINAL;
243 bool bypass = ((p->param_key == "linkeditem") && cloneoriginal);
244 bypass = bypass || p->paramType() == Inkscape::LivePathEffect::ParamType::PATH;
245 bypass = bypass || p->paramType() == Inkscape::LivePathEffect::ParamType::ORIGINAL_PATH;
246 bypass = bypass || p->paramType() == Inkscape::LivePathEffect::ParamType::PATH_ARRAY;
247 bypass = bypass && !refobj;
248 if (refobj || bypass) {
249 if (!bypass) {
250 refmap[id].push_back(idref);
251 } else {
252 write = true;
253 }
254 if (!realycopied.empty()) {
255 realycopied += " | ";
256 }
257 realycopied += splitid;
258 } else {
259 write = true;
260 }
261 }
262 i++;
263 g_free(splitid);
264 }
265 if (write) {
266 repr_elem->setAttribute(p->param_key.c_str(), realycopied.c_str());
267 }
268 g_strfreev(strarray);
269 }
270 }
271 }
272 }
273 }
274 }
275 }
276 /* check for xlink:href="#..." and similar */
277 for (auto attr : href_like_attributes) {
278 Glib::ustring attfixed = "";
279 if (repr_elem->attribute(attr)) {
280 if (!g_strcmp0(attr,"inkscape:linked-fill")) {
281 attfixed += "#";
282 }
283 attfixed += repr_elem->attribute(attr);
284 }
285 const gchar *val = attfixed.c_str();
286 if (!attfixed.empty() && attfixed[0] == '#') {
287 gchar **strarray = g_strsplit(val, ";", 0);
288 if (strarray) {
289 unsigned int i = 0;
290 while (strarray[i]) {
291 if (strarray[i][0] == '#') {
292 std::string id(strarray[i] + 1);
293 IdReference idref = {REF_HREF, elem, attr};
294 refmap[id].push_back(idref);
295 }
296 i++;
297 }
298 g_strfreev(strarray);
299 }
300 }
301 }
302
303 SPStyle *style = elem->style;
304
305 /* check for url(#...) references in 'fill' or 'stroke' */
306 for (unsigned i = 0; i < NUM_SPIPAINT_PROPERTIES; ++i) {
307 const SPIPaint SPStyle::*prop = SPIPaint_members[i];
308 const SPIPaint *paint = &(style->*prop);
309 if (paint->isPaintserver() && paint->href) {
310 const SPObject *obj = paint->href->getObject();
311 if (obj) {
312 const gchar *id = obj->getId();
313 IdReference idref = { REF_STYLE, elem, SPIPaint_properties[i] };
314 refmap[id].push_back(idref);
315 }
316 }
317 }
318
319 /* check for shape-inside/shape-subtract that contain multiple url(#..) each */
320 for (unsigned i = 0; i < NUM_SPISHAPES_PROPERTIES; ++i) {
321 const SPIShapes SPStyle::*prop = SPIShapes_members[i];
322 const SPIShapes *shapes = &(style->*prop);
323 for (auto *href : shapes->hrefs) {
324 auto obj = href->getObject();
325 if (!obj)
326 continue;
327 auto shape_id = obj->getId();
328 IdReference idref = { REF_SHAPES, elem, SPIShapes_properties[i] };
329 refmap[shape_id].push_back(idref);
330 }
331 }
332
333 /* check for url(#...) references in 'filter' */
334 const SPIFilter *filter = &(style->filter);
335 if (filter->href) {
336 const SPObject *obj = filter->href->getObject();
337 if (obj) {
338 const gchar *id = obj->getId();
339 IdReference idref = { REF_STYLE, elem, "filter" };
340 refmap[id].push_back(idref);
341 }
342 }
343
344 /* check for url(#...) references in markers */
345 const gchar *markers[4] = { "", "marker-start", "marker-mid", "marker-end" };
346 for (unsigned i = SP_MARKER_LOC_START; i < SP_MARKER_LOC_QTY; i++) {
347 const gchar *value = style->marker_ptrs[i]->value();
348 if (value) {
349 auto uri = extract_uri(value);
350 if (uri[0] == '#') {
351 IdReference idref = { REF_STYLE, elem, markers[i] };
352 refmap[uri.c_str() + 1].push_back(idref);
353 }
354 }
355 }
356
357 /* check for other url(#...) references */
358 for (auto attr : other_url_properties) {
359 const gchar *value = repr_elem->attribute(attr);
360 if (value) {
361 auto uri = extract_uri(value);
362 if (uri[0] == '#') {
363 IdReference idref = { REF_URL, elem, attr };
364 refmap[uri.c_str() + 1].push_back(idref);
365 }
366 }
367 }
368
369 // recurse
370 for (auto& child: elem->children)
371 {
372 find_references(&child, refmap, from_clipboard);
373 }
374}
375
380static void change_clashing_ids(SPDocument *imported_doc, SPDocument *current_doc, SPObject *elem,
381 refmap_type const &refmap, id_changelist_type *id_changes, bool from_clipboard)
382{
383 const gchar *id = elem->getId();
384 bool fix_clashing_ids = true;
385
386 if (id && current_doc->getObjectById(id)) {
387 // Choose a new ID.
388 // To try to preserve any meaningfulness that the original ID
389 // may have had, the new ID is the old ID followed by a hyphen
390 // and one or more digits.
391
392 if (is<SPGradient>(elem)) {
393 SPObject *cd_obj = current_doc->getObjectById(id);
394
395 if (cd_obj && is<SPGradient>(cd_obj)) {
396 auto cd_gr = cast<SPGradient>(cd_obj);
397 if ( cd_gr->isEquivalent(cast<SPGradient>(elem))) {
398 fix_clashing_ids = false;
399 }
400 }
401 }
402
403 auto lpeobj = cast<LivePathEffectObject>(elem);
404 if (lpeobj) {
405 SPObject *cd_obj = current_doc->getObjectById(id);
406 auto cd_lpeobj = cast<LivePathEffectObject>(cd_obj);
407 if (cd_lpeobj && lpeobj->is_similar(cd_lpeobj)) {
408 fix_clashing_ids = from_clipboard;
409 }
410 }
411
412 if (fix_clashing_ids) {
413 std::string old_id(id);
414 std::string new_id(old_id + '-');
415 for (;;) {
416 new_id += "0123456789"[std::rand() % 10];
417 const char *str = new_id.c_str();
418 if (current_doc->getObjectById(str) == nullptr &&
419 imported_doc->getObjectById(str) == nullptr) break;
420 }
421 // Change to the new ID
422
423 elem->setAttribute("id", new_id);
424 // Make a note of this change, if we need to fix up refs to it
425 if (refmap.find(old_id) != refmap.end()) {
426 id_changes->emplace_back(elem, old_id);
427 }
428 }
429 }
430
431
432 // recurse
433 for (auto& child: elem->children)
434 {
435 change_clashing_ids(imported_doc, current_doc, &child, refmap, id_changes, from_clipboard);
436 }
437}
438
442static void
443fix_up_refs(refmap_type const &refmap, const id_changelist_type &id_changes)
444{
445 id_changelist_type::const_iterator pp;
446 const id_changelist_type::const_iterator pp_end = id_changes.end();
447 for (pp = id_changes.begin(); pp != pp_end; ++pp) {
448 SPObject *obj = pp->first;
449 refmap_type::const_iterator pos = refmap.find(pp->second);
450 std::list<IdReference>::const_iterator it;
451 const std::list<IdReference>::const_iterator it_end = pos->second.end();
452 for (it = pos->second.begin(); it != it_end; ++it) {
453 fix_ref(*it, obj, pp->second.c_str());
454 }
455 }
456}
457
464void prevent_id_clashes(SPDocument *imported_doc, SPDocument *current_doc, bool from_clipboard)
465{
466 refmap_type refmap;
467 id_changelist_type id_changes;
468 SPObject *imported_root = imported_doc->getRoot();
469
470 find_references(imported_root, refmap, from_clipboard);
471 change_clashing_ids(imported_doc, current_doc, imported_root, refmap, &id_changes, from_clipboard);
472 fix_up_refs(refmap, id_changes);
473}
474
475/*
476 * Change any references of svg:def from_obj into to_obj
477 */
478void
480{
481 refmap_type refmap;
482 SPDocument *current_doc = from_obj->document;
483 std::string old_id(from_obj->getId());
484
485 find_references(current_doc->getRoot(), refmap, false);
486
487 refmap_type::const_iterator pos = refmap.find(old_id);
488 if (pos != refmap.end()) {
489 std::list<IdReference>::const_iterator it;
490 const std::list<IdReference>::const_iterator it_end = pos->second.end();
491 for (it = pos->second.begin(); it != it_end; ++it) {
492 fix_ref(*it, to_obj, from_obj->getId());
493 }
494 }
495}
496
497// This is a subset of the valid XML 1.0 ID characters.
498const char valid_id_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.:";
499
505Glib::ustring sanitize_id(const Glib::ustring& input_id) {
506 // XML allows IDs of the form [a-zA-Z_:][a-zA-Z0-9\-_\.:]* plus some UTF8 characters.
507 // We restrict us to the ASCII subset for simplicity.
508 // https://www.w3.org/TR/2008/REC-xml-20081126/#id
509 // https://stackoverflow.com/questions/1077084/what-characters-are-allowed-in-dom-ids#1077111
510 if (input_id.empty())
511 return "_";
512
513 auto id = input_id;
514 for (auto pos = id.find_first_not_of(valid_id_chars);
515 pos != Glib::ustring::npos;
516 pos = id.find_first_not_of(valid_id_chars, pos)) {
517 id.replace(pos, 1, "_");
518 }
519 // ID cannot start with a digit, period, or minus (https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/id)
520 auto c = id[0];
521 if (isdigit(c) || c == '.' || c == '-') {
522 id.insert(0, "x");
523 }
524 return id;
525}
526
530Glib::ustring generate_similar_unique_id(SPDocument* document, const Glib::ustring& base_name) {
531 // replace illegal chars in base_name
532 auto id = base_name;
533 if (id.empty()) {
534 id = "id-0";
535 }
536 else {
537 id = sanitize_id(base_name);
538 }
539
540 if (!document) {
541 g_warning("No document provided in %s, ID will not be unique.", __func__);
542 }
543
544 if (document && document->getObjectById(id.c_str())) {
545 // conflict; check if id ends with "-<number>", so we can increase it;
546 // only accept numbers with up to 9 digits and ignore other/larger digit strings
547 Glib::RefPtr<Glib::Regex> regex = Glib::Regex::create("(.*)-(\\d{1,9})");
548 Glib::MatchInfo info;
549 regex->match(id, info);
550 unsigned long counter = 0;
551 auto base = id;
552 if (info.matches()) {
553 base = info.fetch(1);
554 counter = std::stoul(info.fetch(2));
555 }
556 base += '-';
557 for (;;) {
558 counter++;
559 id = base + std::to_string(counter);
560 if (document->getObjectById(id.c_str()) == nullptr) break;
561 }
562 }
563
564 return id;
565}
566
567/*
568 * Change the id of a SPObject to new_name
569 * If there is an id clash then rename to something similar
570 */
571void rename_id(SPObject *elem, Glib::ustring const &new_name)
572{
573 if (new_name.empty()){
574 g_message("Invalid Id, will not change.");
575 return;
576 }
577 gchar *id = g_strdup(new_name.c_str()); //id is not empty here as new_name is check to be not empty
578 g_strcanon (id, valid_id_chars, '_');
579 Glib::ustring new_name2 = id; //will not fail as id can not be NULL, see length check on new_name
580 if (!isalnum (new_name2[0])) {
581 g_message("Invalid Id, will not change.");
582 g_free (id);
583 return;
584 }
585
586 SPDocument *current_doc = elem->document;
587 refmap_type refmap;
588 find_references(current_doc->getRoot(), refmap, false);
589
590 std::string old_id(elem->getId());
591 if (current_doc->getObjectById(id)) {
592 // Choose a new ID.
593 // To try to preserve any meaningfulness that the original ID
594 // may have had, the new ID is the old ID followed by a hyphen
595 // and one or more digits.
596 new_name2 += '-';
597 for (;;) {
598 new_name2 += "0123456789"[std::rand() % 10];
599 if (current_doc->getObjectById(new_name2) == nullptr)
600 break;
601 }
602 }
603 g_free (id);
604 // Change to the new ID
605 elem->setAttribute("id", new_name2);
606 // Make a note of this change, if we need to fix up refs to it
607 id_changelist_type id_changes;
608 if (refmap.find(old_id) != refmap.end()) {
609 id_changes.emplace_back(elem, old_id);
610 }
611
612 fix_up_refs(refmap, id_changes);
613}
614
615/*
616 Local Variables:
617 mode:c++
618 c-file-style:"stroustrup"
619 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
620 indent-tabs-mode:nil
621 fill-column:99
622 End:
623*/
624// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
Lookup dictionary for attributes/properties.
std::vector< Parameter * > param_vector
Definition effect.h:178
Interface for refcounted XML nodes.
Definition node.h:80
virtual char const * name() const =0
Get the name of the element node.
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.
virtual NodeType type() const =0
Get the type of the node.
Typed SVG document implementation.
Definition document.h:101
SPRoot * getRoot()
Returns our SPRoot.
Definition document.h:200
SPObject * getObjectById(std::string const &id) const
SPFilter * getObject() const
Filter type internal to SPStyle.
SPFilterReference * href
Paint type internal to SPStyle.
bool isPaintserver() const
std::shared_ptr< SPPaintServerReference > href
Shapes type internal to SPStyle.
std::vector< SPShapeReference * > hrefs
char const * value() const
Get value if set, or inherited value, or default value (may be NULL)
SPObject is an abstract base class of all of the document nodes at the SVG document level.
Definition sp-object.h:160
void setAttribute(Inkscape::Util::const_char_ptr key, Inkscape::Util::const_char_ptr value)
SPDocument * document
Definition sp-object.h:188
char const * getId() const
Returns the objects current ID string.
SPStyle * style
Represents the style properties, whether from presentation attributes, the style attribute,...
Definition sp-object.h:248
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
An SVG style object.
Definition style.h:45
T< SPAttr::FILL, SPIPaint > fill
fill
Definition style.h:240
T< SPAttr::STROKE, SPIPaint > stroke
stroke
Definition style.h:247
T< SPAttr::SHAPE_INSIDE, SPIShapes > shape_inside
SVG2 Text Wrapping.
Definition style.h:179
T< SPAttr::FILTER, SPIFilter > filter
Filter effect.
Definition style.h:275
SPIString * marker_ptrs[SP_MARKER_LOC_QTY]
Definition style.h:270
T< SPAttr::SHAPE_SUBTRACT, SPIShapes > shape_subtract
Definition style.h:180
std::shared_ptr< Css const > css
double c[8][4]
void change_def_references(SPObject *from_obj, SPObject *to_obj)
Definition id-clash.cpp:479
const char * clipboard_properties[]
Definition id-clash.cpp:100
std::pair< SPObject *, Glib::ustring > id_changeitem_type
Definition id-clash.cpp:51
const SPIShapes SPStyle::* SPIShapes_members[]
Definition id-clash.cpp:79
const char * SPIShapes_properties[]
Definition id-clash.cpp:83
static void change_clashing_ids(SPDocument *imported_doc, SPDocument *current_doc, SPObject *elem, refmap_type const &refmap, id_changelist_type *id_changes, bool from_clipboard)
Change any IDs that clash with IDs in the current document, and make a list of those changes that wil...
Definition id-clash.cpp:380
static void find_references(SPObject *elem, refmap_type &refmap, bool from_clipboard)
Build a table of places where IDs are referenced, for a given element.
Definition id-clash.cpp:180
const char * other_url_properties[]
Definition id-clash.cpp:89
const SPIPaint SPStyle::* SPIPaint_members[]
Definition id-clash.cpp:67
std::list< id_changeitem_type > id_changelist_type
Definition id-clash.cpp:52
static void fix_up_refs(refmap_type const &refmap, const id_changelist_type &id_changes)
Fix up references to changed IDs.
Definition id-clash.cpp:443
std::map< Glib::ustring, std::list< IdReference > > refmap_type
Definition id-clash.cpp:49
const char valid_id_chars[]
Definition id-clash.cpp:498
void rename_id(SPObject *elem, Glib::ustring const &new_name)
Definition id-clash.cpp:571
const char * href_like_attributes[]
Definition id-clash.cpp:54
static void fix_ref(IdReference const &idref, SPObject *to_obj, const char *old_id)
Given an reference (idref), make it point to to_obj instead.
Definition id-clash.cpp:115
void prevent_id_clashes(SPDocument *imported_doc, SPDocument *current_doc, bool from_clipboard)
This function resolves ID clashes between the document being imported and the current open document: ...
Definition id-clash.cpp:464
ID_REF_TYPE
Definition id-clash.cpp:41
@ REF_URL
Definition id-clash.cpp:41
@ REF_CLIPBOARD
Definition id-clash.cpp:41
@ REF_HREF
Definition id-clash.cpp:41
@ REF_SHAPES
Definition id-clash.cpp:41
@ REF_STYLE
Definition id-clash.cpp:41
Glib::ustring sanitize_id(const Glib::ustring &input_id)
Convert string to valid XML id.
Definition id-clash.cpp:505
const char * SPIPaint_properties[]
Definition id-clash.cpp:72
Glib::ustring generate_similar_unique_id(SPDocument *document, const Glib::ustring &base_name)
Modify 'base_name' to create a new ID that is not used in the 'document'.
Definition id-clash.cpp:530
TODO: insert short description here.
GType type()
Returns the type used for storing an object of type T inside a value.
Definition value-utils.h:29
@ ELEMENT_NODE
Regular element node, e.g. <group />.
static gint counter
Definition box3d.cpp:39
Ocnode * child[8]
Definition quantize.cpp:33
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
void sp_repr_css_set(Node *repr, SPCSSAttr *css, gchar const *attr)
Sets an attribute (e.g.
Definition repr-css.cpp:264
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
char const * sp_repr_css_property(SPCSSAttr *css, gchar const *name, gchar const *defval)
Returns a character string of the value of a given style property or a default value if the attribute...
Definition repr-css.cpp:147
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
@ SP_MARKER_LOC_START
@ SP_MARKER_LOC_QTY
SPRoot: SVG <svg> implementation.
SPStyle internal: classes that are internal to SPStyle.
void sp_style_set_property_url(SPObject *item, gchar const *property, SPObject *linked, bool recursive)
Definition style.cpp:1380
SPStyle - a style object for SPItem objects.
std::string extract_uri(char const *s, char const **endptr)
Parse functional URI notation, as per 4.3.4 of CSS 2.1.
Definition uri.cpp:19
URI functions as per 4.3.4 of CSS 2.1 http://www.w3.org/TR/CSS21/syndata.html#uri.