Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
simple-node.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 * Copyright 2003-2005 MenTaLguY <mental@rydia.net>
9 * Copyright 2003 Nathan Hurst
10 * Copyright 1999-2003 Lauris Kaplinski
11 * Copyright 2000-2002 Ximian Inc.
12 *
13 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
14 */
15
16// clang-format off
17#include "xml/node.h"
18#include "xml/simple-node.h"
19// clang-format on
20
21#include <algorithm>
22#include <cstring>
23#include <string>
24
25#include <glib.h>
26
27#include "preferences.h"
28
29#include "xml/node-fns.h"
30#include "debug/event-tracker.h"
31#include "debug/simple-event.h"
32#include "util/format.h"
33
34#include "attribute-rel-util.h"
35
36namespace Inkscape {
37
38namespace XML {
39
40namespace {
41
42std::shared_ptr<std::string> stringify_node(Node const &node) {
43 gchar *string;
44 switch (node.type()) {
46 char const *id=node.attribute("id");
47 if (id) {
48 string = g_strdup_printf("element(%p)=%s(#%s)", &node, node.name(), id);
49 } else {
50 string = g_strdup_printf("element(%p)=%s", &node, node.name());
51 }
52 } break;
54 string = g_strdup_printf("text(%p)=%s", &node, node.content());
55 break;
57 string = g_strdup_printf("comment(%p)=<!--%s-->", &node, node.content());
58 break;
60 string = g_strdup_printf("document(%p)", &node);
61 break;
62 default:
63 string = g_strdup_printf("unknown(%p)", &node);
64 }
65 std::shared_ptr<std::string> result = std::make_shared<std::string>(string);
66 g_free(string);
67 return result;
68}
69
71
72class DebugXMLNode : public DebugXML {
73public:
74 DebugXMLNode(Node const &node, char const *name)
75 : DebugXML(name)
76 {
77 _addProperty("node", stringify_node(node));
78 }
79};
80
81class DebugAddChild : public DebugXMLNode {
82public:
83 DebugAddChild(Node const &node, Node const &child, Node const *prev)
84 : DebugXMLNode(node, "add-child")
85 {
86 _addProperty("child", stringify_node(child));
87 _addProperty("position", prev ? prev->position() + 1 : 0 );
88 }
89};
90
91class DebugRemoveChild : public DebugXMLNode {
92public:
93 DebugRemoveChild(Node const &node, Node const &child)
94 : DebugXMLNode(node, "remove-child")
95 {
96 _addProperty("child", stringify_node(child));
97 }
98};
99
100class DebugSetChildPosition : public DebugXMLNode {
101public:
102 DebugSetChildPosition(Node const &node, Node const &child,
103 Node const *old_prev, Node const *new_prev)
104 : DebugXMLNode(node, "set-child-position")
105 {
106 _addProperty("child", stringify_node(child));
107
108 unsigned old_position = ( old_prev ? old_prev->position() : 0 );
109 unsigned position = ( new_prev ? new_prev->position() : 0 );
110 if ( position > old_position ) {
111 --position;
112 }
113
114 _addProperty("position", position);
115 }
116};
117
118class DebugSetContent : public DebugXMLNode
119{
120public:
121 DebugSetContent(Node const &node, Util::ptr_shared content)
122 : DebugXMLNode(node, "set-content")
123 {
124 _addProperty("content", content.pointer());
125 }
126};
127
128class DebugClearContent : public DebugXMLNode
129{
130public:
131 DebugClearContent(Node const &node)
132 : DebugXMLNode(node, "clear-content")
133 {}
134};
135
136class DebugSetAttribute : public DebugXMLNode
137{
138public:
139 DebugSetAttribute(Node const &node, GQuark name, Util::ptr_shared value)
140 : DebugXMLNode(node, "set-attribute")
141 {
142 _addProperty("name", g_quark_to_string(name));
143 _addProperty("value", value.pointer());
144 }
145};
146
147class DebugClearAttribute : public DebugXMLNode
148{
149public:
150 DebugClearAttribute(Node const &node, GQuark name)
151 : DebugXMLNode(node, "clear-attribute")
152 {
153 _addProperty("name", g_quark_to_string(name));
154 }
155};
156
157class DebugSetElementName : public DebugXMLNode
158{
159public:
160 DebugSetElementName(Node const &node, GQuark name)
161 : DebugXMLNode(node, "set-name")
162 {
163 _addProperty("name", g_quark_to_string(name));
164 }
165};
166
167} // namespace
168
169using Util::ptr_shared;
172
174 : _name(code)
175{
176 g_assert(document != nullptr);
177
178 this->_document = document;
179 this->_parent = this->_next = this->_prev = nullptr;
180 this->_first_child = this->_last_child = nullptr;
181
183}
184
186 : _cached_position(node._cached_position)
187 , _name(node._name)
188 , _content(node._content)
189 , _child_count(node._child_count)
190 , _cached_positions_valid(node._cached_positions_valid)
191{
192 g_assert(document != nullptr);
193
195 _parent = _next = _prev = nullptr;
196 _first_child = _last_child = nullptr;
197
198 for ( SimpleNode *child = node._first_child ;
199 child != nullptr ; child = child->_next )
200 {
201 SimpleNode *child_copy=dynamic_cast<SimpleNode *>(child->duplicate(document));
202
203 child_copy->_setParent(this);
204 if (_last_child) { // not the first iteration
205 _last_child->_next = child_copy;
206 child_copy->_prev = _last_child;
207 } else {
208 _first_child = child_copy;
209 }
210 _last_child = child_copy;
211
212 child_copy->release(); // release to avoid a leak
213 }
214
215 _attributes = node._attributes;
216
218}
219
220gchar const *SimpleNode::name() const {
221 return g_quark_to_string(_name);
222}
223
224gchar const *SimpleNode::content() const {
225 return this->_content;
226}
227
228gchar const *SimpleNode::attribute(gchar const *name) const {
229 g_return_val_if_fail(name != nullptr, NULL);
230
231 GQuark const key = g_quark_from_string(name);
232
233 for (const auto & iter : _attributes)
234 {
235 if ( iter.key == key ) {
236 return iter.value;
237 }
238 }
239
240 return nullptr;
241}
242
243unsigned SimpleNode::position() const {
244 g_return_val_if_fail(_parent != nullptr, 0);
245 return _parent->_childPosition(*this);
246}
247
250 unsigned position=0;
251 for ( SimpleNode *sibling = _first_child ;
252 sibling ; sibling = sibling->_next )
253 {
254 sibling->_cached_position = position;
255 position++;
256 }
258 }
259 return child._cached_position;
260}
261
264 for ( ; index > 0 && child ; child = child->_next ) {
265 index--;
266 }
267 return child;
268}
269
270bool SimpleNode::matchAttributeName(gchar const *partial_name) const {
271 g_return_val_if_fail(partial_name != nullptr, false);
272
273 for ( const auto & iter : _attributes )
274 {
275 gchar const *name = g_quark_to_string(iter.key);
276 if (std::strstr(name, partial_name)) {
277 return true;
278 }
279 }
280
281 return false;
282}
283
285 if (_parent) {
287 }
288 _parent = parent;
289 if (parent) {
290 _subtree_observers.add(parent->_subtree_observers);
291 }
292}
293
294void SimpleNode::setContent(gchar const *content) {
295 ptr_shared old_content=_content;
296 ptr_shared new_content = ( content ? share_string(content) : ptr_shared() );
297
298 Debug::EventTracker<> tracker;
299 if (new_content) {
300 tracker.set<DebugSetContent>(*this, new_content);
301 } else {
302 tracker.set<DebugClearContent>(*this);
303 }
304
305 _content = new_content;
306
307 if ( _content != old_content ) {
308 _document->logger()->notifyContentChanged(*this, old_content, _content);
309 _observers.notifyContentChanged(*this, old_content, _content);
310 }
311}
312
313void
314SimpleNode::setAttributeImpl(gchar const *name, gchar const *value)
315{
316 g_return_if_fail(name && *name);
317
318 // sanity check: `name` must not contain whitespace
319 g_assert(std::none_of(name, name + strlen(name), [](char c) { return g_ascii_isspace(c); }));
320
321 // Check usefulness of attributes on elements in the svg namespace, optionally don't add them to tree.
322 Glib::ustring element = g_quark_to_string(_name);
323 //g_message("setAttribute: %s: %s: %s", element.c_str(), name, value);
324 gchar* cleaned_value = g_strdup( value );
325
326 // Only check elements in SVG name space and don't block setting attribute to NULL.
327 // .raw() is only for performance reasons because Glib::ustring.== is slow
328 if (value != nullptr && element.raw().starts_with("svg:")) {
329
331 if( prefs->getBool("/options/svgoutput/check_on_editing") ) {
332
333 gchar const *id_char = attribute("id");
334 Glib::ustring id = (id_char == nullptr ? "" : id_char );
335 unsigned int flags = sp_attribute_clean_get_prefs();
336 bool attr_warn = flags & SP_ATTRCLEAN_ATTR_WARN;
337 bool attr_remove = flags & SP_ATTRCLEAN_ATTR_REMOVE;
338
339 // Check attributes
340 if( (attr_warn || attr_remove) && value != nullptr ) {
341 bool is_useful = sp_attribute_check_attribute( element, id, name, attr_warn );
342 if( !is_useful && attr_remove ) {
343 g_free( cleaned_value );
344 return; // Don't add to tree.
345 }
346 }
347
348 // Check style properties -- Note: if element is not yet inserted into
349 // tree (and thus has no parent), default values will not be tested.
350 if( !strcmp( name, "style" ) && (flags >= SP_ATTRCLEAN_STYLE_WARN) ) {
351 g_free( cleaned_value );
352 cleaned_value = g_strdup( sp_attribute_clean_style( this, value, flags ).c_str() );
353 // if( g_strcmp0( value, cleaned_value ) ) {
354 // g_warning( "SimpleNode::setAttribute: %s", id.c_str() );
355 // g_warning( " original: %s", value);
356 // g_warning( " cleaned: %s", cleaned_value);
357 // }
358 }
359 }
360 }
361
362 GQuark const key = g_quark_from_string(name);
363
364 AttributeRecord *ref = nullptr;
365 for ( auto & existing : _attributes ) {
366 if ( existing.key == key ) {
367 ref = &existing;
368 break;
369 }
370 }
371 Debug::EventTracker<> tracker;
372
373 ptr_shared old_value=( ref ? ref->value : ptr_shared() );
374
375 ptr_shared new_value=ptr_shared();
376 if (cleaned_value) { // set value of attribute
377 new_value = share_string(cleaned_value);
378 tracker.set<DebugSetAttribute>(*this, key, new_value);
379 if (!ref) {
380 _attributes.emplace_back(key, new_value);
381 } else {
382 ref->value = new_value;
383 }
384 } else { //clearing attribute
385 tracker.set<DebugClearAttribute>(*this, key);
386 if (ref) {
387 _attributes.erase(std::find(_attributes.begin(),_attributes.end(),(*ref)));
388 }
389 }
390
391 if ( new_value != old_value && (!old_value || !new_value || strcmp(old_value, new_value))) {
392 _document->logger()->notifyAttributeChanged(*this, key, old_value, new_value);
393 _observers.notifyAttributeChanged(*this, key, old_value, new_value);
394 //g_warning( "setAttribute notified: %s: %s: %s: %s", name, element.c_str(), old_value, new_value );
395 }
396 g_free( cleaned_value );
397}
398
400 GQuark old_code = static_cast<GQuark>(_name);
401 GQuark new_code = static_cast<GQuark>(code);
402
403 Debug::EventTracker<> tracker;
404 tracker.set<DebugSetElementName>(*this, new_code);
405
406 _name = static_cast<int>(new_code);
407
408 if (new_code != old_code) {
409 _document->logger()->notifyElementNameChanged(*this, old_code, new_code);
410 _observers.notifyElementNameChanged(*this, old_code, new_code);
411 }
412}
413
414void SimpleNode::addChild(Node *generic_child, Node *generic_ref) {
415 g_assert(generic_child);
416 g_assert(generic_child->document() == _document);
417 g_assert(!generic_ref || generic_ref->document() == _document);
418
419 SimpleNode *child=dynamic_cast<SimpleNode *>(generic_child);
420 SimpleNode *ref=dynamic_cast<SimpleNode *>(generic_ref);
421
422 g_assert(!ref || ref->_parent == this);
423 g_assert(!child->_parent);
424
426
428 if (ref) {
429 next = ref->_next;
430 ref->_next = child;
431
432 child->_prev = ref;
433 } else {
437 }
438
439 if (!next) { // appending?
441 // set cached position if possible when appending
442 if (!ref) {
443 // if !next && !ref, child is sole child
446 } else if (_cached_positions_valid) {
447 child->_cached_position = ref->_cached_position + 1;
448 }
449 } else {
450 next->_prev = child;
451 // invalidate cached positions otherwise
453 }
454
455 child->_setParent(this);
456 child->_next = next;
457 _child_count++;
458
461}
462
463void SimpleNode::removeChild(Node *generic_child) {
464 g_assert(generic_child);
465 g_assert(generic_child->document() == _document);
466
467 SimpleNode *child=dynamic_cast<SimpleNode *>(generic_child);
469 SimpleNode *next = child->_next;
470
471 g_assert(child->_parent == this);
472
474
475 if (ref) {
476 ref->_next = next;
477 } else {
479 }
480 if (next) { // removing the last child?
481 next->_prev = ref;
482 } else {
483 // removing any other child invalidates the cached positions
486 }
487
488 child->_next = nullptr;
489 child->_prev = nullptr;
490 child->_setParent(nullptr);
491 _child_count--;
492
495}
496
497void SimpleNode::changeOrder(Node *generic_child, Node *generic_ref) {
498 g_assert(generic_child);
499 g_assert(generic_child->document() == this->_document);
500 g_assert(!generic_ref || generic_ref->document() == this->_document);
501
502 SimpleNode *const child=dynamic_cast<SimpleNode *>(generic_child);
503 SimpleNode *const ref=dynamic_cast<SimpleNode *>(generic_ref);
504
505 g_return_if_fail(child->parent() == this);
506 g_return_if_fail(child != ref);
507 g_return_if_fail(!ref || ref->parent() == this);
508
509 SimpleNode *const prev= child->_prev;
510
512
513 if (prev == ref) { return; }
514
516
517 /* Remove from old position. */
518 next = child->_next;
519 if (prev) {
520 prev->_next = next;
521 } else {
523 }
524 if (next) {
525 next->_prev = prev;
526 } else {
528 }
529
530 /* Insert at new position. */
531 if (ref) {
532 next = ref->_next;
533 ref->_next = child;
534 } else {
537 }
538
539 child->_prev = ref;
540 child->_next = next;
541
542 if (next) {
543 next->_prev = child;
544 } else {
546 }
547
549
552}
553
555 g_return_if_fail(_parent != nullptr);
556
557 // a position beyond the end of the list means the end of the list;
558 // a negative position is the same as an infinitely large position
559
560 SimpleNode *ref=nullptr;
561 for ( SimpleNode *sibling = _parent->_first_child ;
562 sibling && pos ; sibling = sibling->_next )
563 {
564 if ( sibling != this ) {
565 ref = sibling;
566 pos--;
567 }
568 }
569
570 _parent->changeOrder(this, ref);
571}
572
574{
575 for (auto const &iter : _attributes) {
576 observer.notifyAttributeChanged(*this, iter.key, Util::ptr_shared(), iter.value);
577 }
578
579 SimpleNode *ref = nullptr;
580 for (auto child = this->_first_child; child; child = child->_next) {
581 observer.notifyChildAdded(*this, *child, ref);
582 ref = child;
583 }
584
585 observer.notifyContentChanged(*this, Util::ptr_shared(), this->_content);
586}
587
588void SimpleNode::recursivePrintTree(unsigned level) {
589
590 if (level == 0) {
591 std::cout << "XML Node Tree" << std::endl;
592 }
593 std::cout << "XML: ";
594 for (unsigned i = 0; i < level; ++i) {
595 std::cout << " ";
596 }
597 char const *id=attribute("id");
598 if (id) {
599 std::cout << id << std::endl;
600 } else {
601 std::cout << name() << std::endl;
602 }
603 for (SimpleNode *child = _first_child; child != nullptr; child = child->_next) {
604 child->recursivePrintTree( level+1 );
605 }
606}
607
609 Node *parent=this;
610 while (parent->parent()) {
611 parent = parent->parent();
612 }
613
614 if ( parent->type() == NodeType::DOCUMENT_NODE ) {
615 for ( Node *child = _document->firstChild() ;
616 child ; child = child->next() )
617 {
618 if ( child->type() == NodeType::ELEMENT_NODE ) {
619 return child;
620 }
621 }
622 return nullptr;
623 } else if ( parent->type() == NodeType::ELEMENT_NODE ) {
624 return parent;
625 } else {
626 return nullptr;
627 }
628}
629
630void SimpleNode::cleanOriginal(Node *src, gchar const *key){
631 std::vector<Node *> to_delete;
632 for ( Node *child = this->firstChild() ; child != nullptr ; child = child->next() )
633 {
634 gchar const *id = child->attribute(key);
635 if (id) {
636 Node *rch = sp_repr_lookup_child(src, key, id);
637 if (rch) {
638 child->cleanOriginal(rch, key);
639 } else {
640 to_delete.push_back(child);
641 }
642 } else {
643 to_delete.push_back(child);
644 }
645 }
646 for (auto & i : to_delete) {
647 removeChild(i);
648 }
649}
650bool string_equal(const gchar *a,const gchar *b) {
651 return g_strcmp0(a, b) == 0;
652}
653
654bool SimpleNode::equal(Node const *other, bool recursive, bool skip_ids) {
655 if (!other || !string_equal(name(), other->name())) {
656 return false;
657 }
658 if (!string_equal(content(), other->content())) {
659 return false;
660 }
661 const AttributeVector & orig_attrs = attributeList();
662 const AttributeVector & other_attrs = other->attributeList();
663 size_t sizeorig = orig_attrs.size();
664 size_t sizeother = other_attrs.size();
665 if (sizeother != sizeorig) {
666 return false;
667 }
668 for (size_t i = 0; i < sizeorig; i++) {
669 const gchar * key_orig = g_quark_to_string(orig_attrs[i].key);
670 if (skip_ids && string_equal(key_orig, "id")) {
671 continue;
672 }
673 const gchar * key_other = g_quark_to_string(other_attrs[i].key);
674 if (!string_equal(key_orig, key_other) ||
675 !string_equal(orig_attrs[i].value, other_attrs[i].value) != 0)
676 {
677 return false;
678 }
679 }
680 if (recursive) {
681 //NOTE: for faster the childs need to be in the same order
682 Node const *other_child = other->firstChild();
683 Node *child = firstChild();
684 while (child && other_child) {
685 if (!child->equal(other_child, recursive, skip_ids)) {
686 return false;
687 }
688 child = child->next();
689 other_child = other_child->next();
690 }
691 if ((!child && other_child) || (child && !other_child)) {
692 return false;
693 }
694 }
695 return true;
696}
697
698void SimpleNode::mergeFrom(Node const *src, gchar const *key, bool extension, bool clean) {
699 g_return_if_fail(src != nullptr);
700 g_return_if_fail(key != nullptr);
701 g_assert(src != this);
702
703 Node * srcp = const_cast<Node *>(src);
704 if (srcp->equal(this, true)) {
705 return;
706 }
707 setContent(src->content());
708 if(_parent) {
709 setPosition(src->position());
710 }
711
712 if (clean) {
713 cleanOriginal(srcp, key);
714 }
715
716 for ( Node const *child = src->firstChild() ; child != nullptr ; child = child->next() )
717 {
718 gchar const *id = child->attribute(key);
719 if (id) {
720 Node *rch=sp_repr_lookup_child(this, key, id);
721 if (rch && (!extension || rch->equal(child, false))) {
722 rch->mergeFrom(child, key, extension);
723 continue;
724 } else {
725 if(rch) {
726 removeChild(rch);
727 }
728 }
729 }
730 {
731 guint pos = child->position();
733 addChildAtPos(rch, pos);
734 rch->release();
735 }
736 }
737
738 for ( const auto & iter : src->attributeList() )
739 {
740 setAttribute(g_quark_to_string(iter.key), iter.value);
741 }
742}
743
744}
745
746}
747
748/*
749 Local Variables:
750 mode:c++
751 c-file-style:"stroustrup"
752 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
753 indent-tabs-mode:nil
754 fill-column:99
755 End:
756*/
757// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
unsigned int sp_attribute_clean_get_prefs()
Get preferences.
void sp_attribute_clean_style(Node *repr, unsigned int flags)
Clean CSS style 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.
Utility functions related to parsing and validation of XML attributes.
@ SP_ATTRCLEAN_STYLE_WARN
@ SP_ATTRCLEAN_ATTR_WARN
@ SP_ATTRCLEAN_ATTR_REMOVE
Cairo::RefPtr< Cairo::Region > clean
Definition canvas.cpp:183
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.
char const * pointer() const
Definition share.h:33
Key-value pair representing an attribute.
void add(NodeObserver &observer)
Add an observer to the list.
void remove(NodeObserver &observer)
Remove an observer from the list.
void notifyContentChanged(Node &node, Util::ptr_shared old_content, Util::ptr_shared new_content) override
Content change callback.
void notifyChildOrderChanged(Node &node, Node &child, Node *old_prev, Node *new_prev) override
Child order change callback.
void notifyElementNameChanged(Node &node, GQuark old_name, GQuark new_name) override
Element name change callback.
void notifyChildRemoved(Node &node, Node &child, Node *prev) override
Child removal callback.
void notifyChildAdded(Node &node, Node &child, Node *prev) override
Child addition callback.
void notifyAttributeChanged(Node &node, GQuark name, Util::ptr_shared old_value, Util::ptr_shared new_value) override
Attribute change callback.
Interface for XML node observers.
virtual void notifyElementNameChanged(Node &node, GQuark old_name, GQuark new_name)
Element name change callback.
virtual void notifyAttributeChanged(Node &node, GQuark name, Util::ptr_shared old_value, Util::ptr_shared new_value)
Attribute change callback.
virtual void notifyContentChanged(Node &node, Util::ptr_shared old_content, Util::ptr_shared new_content)
Content change callback.
virtual void notifyChildOrderChanged(Node &node, Node &child, Node *old_prev, Node *new_prev)
Child order change callback.
virtual void notifyChildRemoved(Node &node, Node &child, Node *prev)
Child removal callback.
virtual void notifyChildAdded(Node &node, Node &child, Node *prev)
Child addition callback.
Interface for refcounted XML nodes.
Definition node.h:80
virtual Node * parent()=0
Get the parent of this node.
virtual Node * next()=0
Get the next sibling of this node.
Inkscape::XML::Node * sp_repr_lookup_child(Inkscape::XML::Node *repr, gchar const *key, gchar const *value)
Find an element node using an unique attribute.
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 addChildAtPos(Node *child, unsigned pos)
Insert another node as a child of this node.
Definition node.h:430
void setAttribute(Util::const_char_ptr key, Util::const_char_ptr value)
Change an attribute of this node.
Definition node.cpp:25
virtual Node * duplicate(Document *doc) const =0
Create a duplicate of this node.
virtual Node * firstChild()=0
Get the first child of this node.
virtual unsigned position() const =0
Get the index of this node in parent's child order.
virtual bool equal(Node const *other, bool recursive, bool skip_ids=false)=0
Compare 2 nodes equality.
virtual void mergeFrom(Node const *src, char const *key, bool extension=false, bool clean=false)=0
Merge all children of another node with the current.
virtual char const * attribute(char const *key) const =0
Get the string representation of a node's attribute.
virtual char const * content() const =0
Get the content of a text or comment node.
virtual Document * document()=0
Get the node's associated document.
virtual NodeType type() const =0
Get the type of the node.
Default implementation of the XML node stored in memory.
Definition simple-node.h:37
void cleanOriginal(Node *src, gchar const *key) override
Node * next() override
Get the next sibling of this node.
Definition simple-node.h:56
Inkscape::Util::ptr_shared _content
bool matchAttributeName(char const *partial_name) const override
Check whether this node has any attribute that matches a string.
Node * prev() override
Definition simple-node.h:58
Node * firstChild() override
Get the first child of this node.
Definition simple-node.h:61
void recursivePrintTree(unsigned level=0) override
Node * nthChild(unsigned index) override
Get the child of this node with a given index.
void setCodeUnsafe(int code) override
Set the integer GQuark code for the name of the node.
void setPosition(int pos) override
Set the position of this node in parent's child order.
Node * parent() override
Get the parent of this node.
Definition simple-node.h:53
bool equal(Node const *other, bool recursive, bool skip_ids=false) override
Compare 2 nodes equality.
int code() const override
Get the integer code corresponding to the node's name.
Definition simple-node.h:40
const AttributeVector & attributeList() const override
Get a list of the node's attributes.
Definition simple-node.h:92
char const * content() const override
Get the content of a text or comment node.
void removeChild(Node *child) override
Remove a child of this node.
CompositeNodeObserver _subtree_observers
CompositeNodeObserver _observers
SimpleNode(int code, Document *document)
AttributeVector _attributes
char const * name() const override
Get the name of the element node.
unsigned _childPosition(SimpleNode const &child) const
void synthesizeEvents(NodeObserver &observer) override
Generate a sequence of events corresponding to the state of this node.
void setAttributeImpl(char const *key, char const *value) override
void mergeFrom(Node const *src, char const *key, bool extension=false, bool clean=false) override
Merge all children of another node with the current.
void addChild(Node *child, Node *ref) override
Insert another node as a child of this node.
unsigned position() const override
Get the index of this node in parent's child order.
char const * attribute(char const *key) const override
Get the string representation of a node's attribute.
Node * root() override
Get the root node of this node's document.
void setContent(char const *value) override
Set the content of a text or comment node.
Document * document() override
Get the node's associated document.
Definition simple-node.h:43
void _setParent(SimpleNode *parent)
void changeOrder(Node *child, Node *ref) override
Move a given node in this node's child order.
NodeObserver const * observer
Css & result
double c[8][4]
static char const *const parent
Definition dir-util.cpp:70
Inkscape::XML::Node * node
ptr_shared share_unsafe(char const *string)
Definition share.h:90
ptr_shared share_string(char const *string)
Definition share.cpp:20
bool string_equal(const gchar *a, const gchar *b)
@ DOCUMENT_NODE
Top-level document node. Do not confuse with the root node.
@ COMMENT_NODE
Comment node, e.g. <!– some comment –>.
@ ELEMENT_NODE
Regular element node, e.g. <group />.
@ TEXT_NODE
Text node, e.g. "Some text" in <group>Some text</group> is represented by a text node.
std::vector< AttributeRecord, Inkscape::GC::Alloc< AttributeRecord > > AttributeVector
Definition node.h:34
Helper class to stream background task notifications as a series of messages.
Helper functions for XML nodes.
static cairo_user_data_key_t key
Singleton class to access the preferences file in a convenient way.
Ocnode * child[8]
Definition quantize.cpp:33
Ocnode ** ref
Definition quantize.cpp:32
GC-managed XML node implementation.
guint32 GQuark
Interface for XML documents.
Definition document.h:43
virtual NodeObserver * logger()=0
Get the event logger for this document.
int index
Glib::ustring name
Definition toolbars.cpp:55
Interface for XML nodes.