From 98c54cdef8b0615a95382bdba4ecd008789f8c9e Mon Sep 17 00:00:00 2001 From: Nathan Willis Date: Tue, 23 Apr 2019 17:48:42 +0100 Subject: [PATCH] Usermanual: add chapter on object model. --- docs/harfbuzz-docs.xml | 1 + docs/usermanual-object-model.xml | 249 +++++++++++++++++++++++++++++++ 2 files changed, 250 insertions(+) create mode 100644 docs/usermanual-object-model.xml diff --git a/docs/harfbuzz-docs.xml b/docs/harfbuzz-docs.xml index f4ad134ea..63863350e 100644 --- a/docs/harfbuzz-docs.xml +++ b/docs/harfbuzz-docs.xml @@ -37,6 +37,7 @@ + diff --git a/docs/usermanual-object-model.xml b/docs/usermanual-object-model.xml new file mode 100644 index 000000000..f0b76ce91 --- /dev/null +++ b/docs/usermanual-object-model.xml @@ -0,0 +1,249 @@ + + + +]> + + The HarfBuzz object model +
+ An overview of data types in HarfBuzz + + HarfBuzz features two kinds of data types: non-opaque, + pass-by-value types and opaque, heap-allocated types. This kind + of separation is common in C libraries that have to provide + API/ABI compatibility (almost) indefinitely. + + + Value types: The non-opaque, pass-by-value + types include integer types, enums, and small structs. Exposing + a struct in the public API makes it impossible to expand the + struct in the future. As such, exposing structs is reserved for + cases where it’s extremely inefficient to do otherwise. + + + In HarfBuzz, several structs, like hb_glyph_info_t and + hb_glyph_position_t, fall into that efficiency-sensitive + category and are non-opaque. + + + For all non-opaque structs where future extensibility may be + necessary, reserved members are included to hold space for + possible future members. As such, it’s important to provide + equal(), and hash() + methods for such structs, allowing users of the API do + effectively deal with the type without having to + adapt their code to future changes. + + + Important value types provided by HarfBuzz include the structs + for working with Unicode code points, glyphs, and tags for font + tables and features, as well as the enums for many Unicode and + OpenType properties. + +
+ +
+ Objects in HarfBuzz + + Object types: Opaque struct types are used + for what HarfBuzz loosely calls "objects." This doesn’t have + much to do with the terminology from object-oriented programming + (OOP), although some of the concepts are similar. + + + In HarfBuzz, all object types provide certain + lifecycle-management APIs. Objects are reference-counted, and + constructed with various create() methods, referenced via + reference() and dereferenced using + destroy(). + + + For example, + the hb_buffer_t object has + hb_buffer_create() as its constructor, + hb_buffer_reference() to reference, and + hb_buffer_destroy() to dereference. + + + After construction, each object's properties are accessible only + through the setter and getter functions described in the API + Reference manual. + + + Key object types provided by HarfBuzz include: + + + + + blobs, which act as low-level wrappers around binary + data. Blobs are typically used to hold the contents of a + binary font file. + + + + + faces, which represent typefaces from a + font file, but without specific parameters (such as size) set. + + + + + fonts, which represent instances of a + face will all of their parameters specified. + + + + + buffers, which hold Unicode code points + for characters (before shaping) and the shaped glyph output + (after shaping). + + + + + shape plans, which store the settings + that HarfBuzz will use when shaping a particular text segment. + + + + +
+ + + +
+ Object lifecycle management + + Each object type in HarfBuzz provides a + create() method. Some object types provide + additional variants of create() to handle + special cases or to speed up common tasks; those variants are + documented in the API reference. For example, + hb_blob_create_from_file() constructs a new + blob directly from the contents of a file. + + + Client programs can increase the reference count on an object by + calling its reference() method. Whenever a + client program is finished with an object, it should call its + corresponding destroy() method. The destroy + method will decrease the reference count on the object and, + whenever the reference count reaches zero, it will also destroy + the object and free all of the associated memory. + + + All of HarfBuzz's object-lifecycle-management APIs are + thread-safe, even when the object as a whole is not thread-safe . + It is also permissible to reference() or to + destroy() the NULL + value. + + + Some objects are thread-safe after they have been constructed + and set up. The general pattern is to + create() the object, make a few + set_*() calls to set up the + object, and then use it without further modification. + + + To ensure that such an object is not modified, client programs + can explicitly mark an object as immutable. HarfBuzz provides + make_immutable() methods to mark an object + as immutable and is_immutable() methods to + test whether or not an object is immutable. Attempts to use + setter functions on immutable objects will fail; see the API + Reference manual for specifics. + + + Note also that there are no "make mutable" methods. If client + programs need to alter an object previously marked as immutable, + they will need to make a duplicate of the original. + + + Finally, object constructors (and, indeed, as much of the API as + possible) will never return NULL. Instead, + if there is an allocation error, each constructor will + return an “empty” object singleton. + + + These empty-object singletons are inert and safe (although + typically useless) to pass around. This design choice avoids + having to check for NULL pointers all + throughout the code. + + + In addition, this “empty” object singleton can also be accessed + using the get_empty() method of the object + type in question. + +
+ + +
+ User data + + To better integrate with client programs, HarfBuzz's objects + offer a "user data" mechanism that can be used to attach + arbitrary data to the object. User-data attachment can be + useful for tying the lifecycles of various pieces of data + together, or for creating language bindings. + + + Each object type has a set_user_data() + method and a get_user_data() method. The + set_user_data() methods take a client-provided + key and a pointer, + user_data, pointing to the data itself. Once + the key-data pair has been attached to the object, the + get_user_data() method can be called with + the key, returning the user_data pointer. + + + The set_user_data() methods also support an + optional destroy callback. Client programs + can set the destroy callback and receive + notification from HarfBuzz whenever the object is destructed. + + + Finally, each set_user_data() method allows + the client program to set a replace Boolean + indicating whether or not the user_data + associated with a key ought to be replaceable. + +
+ + + +
+ Blobs + + While most of HarfBuzz's object types are specific to the + shaping process, blobs are somewhat + different. + + + Blobs are an abstraction desgined to negotiate lifecycle and + permissions for raw pieces of data. For example, when you load + the raw font data into memory and want to pass it to HarfBuzz, + you do so in a hb_blob_t wrapper. + + + This allows you to take advantage of HarffBuzz's + reference-counting and destroy + callbacks. If you allocated the memory for the data using + malloc(), you would create the blob using + + + hb_blob_create (data, length, HB_MEMORY_MODE_WRITABLE, NULL, free) + + + That way, HarfBuzz will call free() on the + allocated memory whenever the blob drops its last reference and + is deconstructed. Consequently, the user code can stop worrying + about freeing memory and let the reference-counting machinery + take care of that. + +
+ +