259 lines
10 KiB
XML
259 lines
10 KiB
XML
<?xml version="1.0"?>
|
||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
||
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
|
||
<!ENTITY version SYSTEM "version.xml">
|
||
]>
|
||
<chapter id="object-model">
|
||
<title>The HarfBuzz object model</title>
|
||
<section id="object-model-intro">
|
||
<title>An overview of data types in HarfBuzz</title>
|
||
<para>
|
||
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.
|
||
</para>
|
||
<para>
|
||
<emphasis>Value types:</emphasis> 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.
|
||
</para>
|
||
<para>
|
||
In HarfBuzz, several structs, like <literal>hb_glyph_info_t</literal> and
|
||
<literal>hb_glyph_position_t</literal>, fall into that efficiency-sensitive
|
||
category and are non-opaque.
|
||
</para>
|
||
<para>
|
||
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
|
||
<function>equal()</function>, and <function>hash()</function>
|
||
methods for such structs, allowing users of the API do
|
||
effectively deal with the type without having to
|
||
adapt their code to future changes.
|
||
</para>
|
||
<para>
|
||
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.
|
||
</para>
|
||
</section>
|
||
|
||
<section id="object-model-object-types">
|
||
<title>Objects in HarfBuzz</title>
|
||
<para>
|
||
<emphasis>Object types:</emphasis> 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.
|
||
</para>
|
||
<para>
|
||
In HarfBuzz, all object types provide certain
|
||
lifecycle-management APIs. Objects are reference-counted, and
|
||
constructed with various <function>create()</function> methods, referenced via
|
||
<function>reference()</function> and dereferenced using
|
||
<function>destroy()</function>.
|
||
</para>
|
||
<para>
|
||
For example,
|
||
the <literal>hb_buffer_t</literal> object has
|
||
<function>hb_buffer_create()</function> as its constructor,
|
||
<function>hb_buffer_reference()</function> to reference, and
|
||
<function>hb_buffer_destroy()</function> to dereference.
|
||
</para>
|
||
<para>
|
||
After construction, each object's properties are accessible only
|
||
through the setter and getter functions described in the API
|
||
Reference manual.
|
||
</para>
|
||
<para>
|
||
Key object types provided by HarfBuzz include:
|
||
</para>
|
||
<itemizedlist spacing="compact">
|
||
<listitem>
|
||
<para>
|
||
<emphasis>blobs</emphasis>, which act as low-level wrappers around binary
|
||
data. Blobs are typically used to hold the contents of a
|
||
binary font file.
|
||
</para>
|
||
</listitem>
|
||
<listitem>
|
||
<para>
|
||
<emphasis>faces</emphasis>, which represent typefaces from a
|
||
font file, but without specific parameters (such as size) set.
|
||
</para>
|
||
</listitem>
|
||
<listitem>
|
||
<para>
|
||
<emphasis>fonts</emphasis>, which represent instances of a
|
||
face with all of their parameters specified.
|
||
</para>
|
||
</listitem>
|
||
<listitem>
|
||
<para>
|
||
<emphasis>buffers</emphasis>, which hold Unicode code points
|
||
for characters (before shaping) and the shaped glyph output
|
||
(after shaping).
|
||
</para>
|
||
</listitem>
|
||
<listitem>
|
||
<para>
|
||
<emphasis>shape plans</emphasis>, which store the settings
|
||
that HarfBuzz will use when shaping a particular text
|
||
segment. Shape plans are not generally used by client
|
||
programs directly, but as we will see in a later chapter,
|
||
they are still valuable to understand.
|
||
</para>
|
||
</listitem>
|
||
</itemizedlist>
|
||
|
||
</section>
|
||
|
||
|
||
|
||
<section id="object-model-lifecycle">
|
||
<title>Object lifecycle management</title>
|
||
<para>
|
||
Each object type in HarfBuzz provides a
|
||
<function>create()</function> method. Some object types provide
|
||
additional variants of <function>create()</function> to handle
|
||
special cases or to speed up common tasks; those variants are
|
||
documented in the API reference. For example,
|
||
<function>hb_blob_create_from_file()</function> constructs a new
|
||
blob directly from the contents of a file.
|
||
</para>
|
||
<para>
|
||
All objects are created with an initial reference count of
|
||
<literal>1</literal>. Client programs can increase the reference
|
||
count on an object by calling its
|
||
<function>reference()</function> method. Whenever a client
|
||
program is finished with an object, it should call its
|
||
corresponding <function>destroy()</function> 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.
|
||
</para>
|
||
<para>
|
||
All of HarfBuzz's object-lifecycle-management APIs are
|
||
thread-safe (unless you compiled HarfBuzz from source with the
|
||
<literal>HB_NO_MT</literal> configuration flag), even when the
|
||
object as a whole is not thread-safe.
|
||
It is also permissible to <function>reference()</function> or to
|
||
<function>destroy()</function> the <literal>NULL</literal>
|
||
value.
|
||
</para>
|
||
<para>
|
||
Some objects are thread-safe after they have been constructed
|
||
and set up. The general pattern is to
|
||
<function>create()</function> the object, make a few
|
||
<function>set_*()</function> calls to set up the
|
||
object, and then use it without further modification.
|
||
</para>
|
||
<para>
|
||
To ensure that such an object is not modified, client programs
|
||
can explicitly mark an object as immutable. HarfBuzz provides
|
||
<function>make_immutable()</function> methods to mark an object
|
||
as immutable and <function>is_immutable()</function> methods to
|
||
test whether or not an object is immutable. Attempts to use
|
||
setter functions on immutable objects will fail silently; see the API
|
||
Reference manual for specifics.
|
||
</para>
|
||
<para>
|
||
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.
|
||
</para>
|
||
<para>
|
||
Finally, object constructors (and, indeed, as much of the
|
||
shaping API as possible) will never return
|
||
<literal>NULL</literal>. Instead, if there is an allocation
|
||
error, each constructor will return an “empty” object
|
||
singleton.
|
||
</para>
|
||
<para>
|
||
These empty-object singletons are inert and safe (although
|
||
typically useless) to pass around. This design choice avoids
|
||
having to check for <literal>NULL</literal> pointers all
|
||
throughout the code.
|
||
</para>
|
||
<para>
|
||
In addition, this “empty” object singleton can also be accessed
|
||
using the <function>get_empty()</function> method of the object
|
||
type in question.
|
||
</para>
|
||
</section>
|
||
|
||
|
||
<section id="object-model-user-data">
|
||
<title>User data</title>
|
||
<para>
|
||
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.
|
||
</para>
|
||
<para>
|
||
Each object type has a <function>set_user_data()</function>
|
||
method and a <function>get_user_data()</function> method. The
|
||
<function>set_user_data()</function> methods take a client-provided
|
||
<literal>key</literal> and a pointer,
|
||
<literal>user_data</literal>, pointing to the data itself. Once
|
||
the key-data pair has been attached to the object, the
|
||
<function>get_user_data()</function> method can be called with
|
||
the key, returning the <function>user_data</function> pointer.
|
||
</para>
|
||
<para>
|
||
The <function>set_user_data()</function> methods also support an
|
||
optional <function>destroy</function> callback. Client programs
|
||
can set the <function>destroy</function> callback and receive
|
||
notification from HarfBuzz whenever the object is destructed.
|
||
</para>
|
||
<para>
|
||
Finally, each <function>set_user_data()</function> method allows
|
||
the client program to set a <literal>replace</literal> Boolean
|
||
indicating whether or not the function call should replace any
|
||
existing <literal>user_data</literal>
|
||
associated with the specified key.
|
||
</para>
|
||
</section>
|
||
|
||
|
||
|
||
<section id="object-model-blobs">
|
||
<title>Blobs</title>
|
||
<para>
|
||
While most of HarfBuzz's object types are specific to the
|
||
shaping process, <emphasis>blobs</emphasis> are somewhat
|
||
different.
|
||
</para>
|
||
<para>
|
||
Blobs are an abstraction designed 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 <literal>hb_blob_t</literal> wrapper.
|
||
</para>
|
||
<para>
|
||
This allows you to take advantage of HarfBuzz's
|
||
reference-counting and <function>destroy</function>
|
||
callbacks. If you allocated the memory for the data using
|
||
<function>malloc()</function>, you would create the blob using
|
||
</para>
|
||
<programlisting language="C">
|
||
hb_blob_create (data, length, HB_MEMORY_MODE_WRITABLE, data, free)
|
||
</programlisting>
|
||
<para>
|
||
That way, HarfBuzz will call <function>free()</function> 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.
|
||
</para>
|
||
</section>
|
||
|
||
</chapter>
|