Like the rest of VRR source code, the kernel is written in pure C according to the C99 standard. Nevertheless, the kernel emulates an object hierarchy for basic kernel objects. The hierarchy looks as follows:
struct o
– the root of the hierarchy
struct obj
– a non-graphic object
struct obj_doc
– a document
struct obj_tlo
– a page
struct go
– a graphic object
struct go_point
– a point
struct go_segment
– a segment
To enable typecasts, the derived object structure always begins with the contents of the ancestor structure. These are the contents of the root object type whose meaning is then described in more detail:
struct o { u8 kind; u8 type; u8 subtype; u8 _dummy; uns ref_count; struct slist prop; uns flags; };
In the following image, you can see an example of the hierarchy of user objects
hierarchy. The root of the user object hierarchy is a special object
obj_universe
.
The object kind specifies if the object is a non-graphic object (T_OBJ
)
or a graphic one (T_GO
). The graphic and non-graphic objects have very little
in common. Non-graphic objects do not have any graphic nor geometric meaning, their
purpose is to represent documents and pages in the object structure, and some internal
special entities, too.
For graphic objects, the type specifies the basic object type, like point, segment, intersection, etc. Different object types have different data structures and a completely different geometric behaviour. Objects with the same type have the same hangers.
Non-graphic objects have no subtypes and are distinguished by their type only. The possible values are:
OT_UNIVERSE
– a special type used only for the root object
of the whole user object hierarchy
OT_DOCUMENT
for documents
OT_TLO
for pages
OT_TEMP
for a special internal object used for storing objects temporarily
during a transaction
OT_ZOMBIE
for a special internal object used for storing objects which
no longer exist (were deleted from the universe) but cannot be deleted yet
The graphic object subtype determines the geometric behaviour of an object more precisely. Objects with the same type have the same set of hangers (the “geometric output”), but they differ in anchors (the “geometric input”). For example, an elliptic arc can be determined by two foci and a point, or by three points on its perimeter plus rotation and eccentricity; that is specified by the subtype.
To minimize the efforts needed for correct data deallocation, we have implemented reference counting of objects. If any data structure needs to store a pointer to an object, it should increment its reference count and decrement again to release the pointer. When the reference count of an object becomes zero, the object is destroyed.
Objects with non-zero reference count which are not linked in the universe are stored in the zombie and can be resurrected again (for example, by linking them via undo).
The objects store various data of various types and various meaning:
All these data can be accessed using an uniform kernel interface. Some of the properties are just regular data structure members, while the others are virtual with read and write callbacks which can cause complex recomputations.