See doc/architecture.txt for a (outdated but still useful) overview of the Inkscape code.
The header files in src/xml contain additional information.
The most basic SVG (XML) document backbone is implemented as an in-memory tree of Inkscape::XML::Node objects (previously SPRepr objects). Each object corresponding to a single node in the XML file. The abstract node class is Inkscape::XML::Node. There are five derived class:
- DOCUMENT_NODE: Top-level document node. Do not confuse with the root node.
- ELEMENT_NODE: Regular element node, e.g. <rect/>.
- TEXT_NODE:Text node, e.g. "Some text" in <object>Some text</object> is represented by a text node.
- COMMENT_NODE: Comment node, e.g. <!-- some comment -->
- PI_NODE: Processing instruction node, e.g. <?xml version="1.0" encoding="utf-8" standalone="no"?>
Nodes are tied to a particular document. New nodes are created using the methods of the Inkscape::XML::Document class. Nodes are removed by unparenting them. Note that nodes cannot be moved between documents; they must be duplicated.
Observer objects can be registered with XML nodes. They will receive notifications when changes are made to a node. This is how the object tree is kept in sync with the XML tree. The five possible changes are:
- Child Added
- Child Removed
- Child Order Changed
- Content Changed
- Attribute Changed
The SPObject base class registers all five to its corresponding XML node (see src/sp-object.cpp). The defined behavior is:
- Child Added: Creates new object, inserts in object tree, and calls invoke_build on child.
- Child Removed: Detaches child from object tree.
- Child Order Changed: Noves the child in the object tree. Emits _position_changed_signal.
- Content Changed: Call object->read_content().
- Attribute Changed: Call object->readAttr(key).
Some widgets/toolbars add listeners for their special needs. For example, the Rectangle Toolbar adds a listener that keeps its entry widgets up-to-date regardless of the source of the change (e.g. using the XML editor to change the width).
These are notes from my attempt to understand Inkscape's undo system. Please help correct errors!
Inkscape tracks in a log changes to a document's XML. Five types of changes are tracked:
Each change is stored as an "Event". For example, a change in an attribute is stored in an instance of the Inkscape::XML::EventChgAttr class where the old value and new values of the attribute are recorded (see src/xml/event.h). Three private functions allow one to optimize the change (merge with a previous change), undo the change, or replay the change.
The log is built using calls to the LogBuilder class (src/xml/log-builder.h) which create a new instance of an event and then attempts to optimize the event (merge with previous event).
Each creation/undo/replay of an event causes the CompositeNodeObserver to notify object nodes that have registered their interest in tracking the corresponding XML node of the change to the XML node. The SPObject::invoke_build() function calls sp_repr_add_lister() which registers callbacks for each of the five change types listed above. Derived classes such as SPRect may add their own special callbacks.
Manipulation of the log is done through the Inkscape::DocumentUndo class (src/document-undo.h). The basic technique is to first make the desired changes to the XML tree and then call either Inkscape::DocumentUndo::done() or Inkcape::DocumentUndo::maybeDone(). The latter call includes a "key" that allows changes of the same type (i.e. "kern:left") to be merged.