Commit 691a9571 authored by David Turner's avatar David Turner
Browse files

updating the FT2 design documentation

- note that the "modules.html" will soon disappear, it is now replaced
  by a more general and more detailed series of pages named "design-??.html"

- the images have been seriously reworked, more will come tomorrow
parent 7b028719

990 Bytes | W: | H:


2 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
<head><title>The Design of FreeType 2 - Introduction</title>
<basefont face="Georgia, Arial, Helvetica, Geneva">
<style content="text/css">
P { text-align=justify }
H1 { text-align=center }
H2 { text-align=center }
LI { text-align=justify }
<body text=#000000 bgcolor=#ffffff>
<center><table width="500"><tr><td>
<center><h1>The Design of FreeType 2</h1></center>
<table width="100%" cellpadding=5><tr bgcolor="#ccccee"><td>
<p>This document provides details on the design and implementation
of the FreeType 2 library. Its goal is to allow developers to
better understand the way FT2 is organized, in order to let them
extend, customize and debug it.</p>
<p>Before anything else, it is important to understand the <em>purpose</em>
of this library, i.e. why it has been written:</p>
<li><p>first of all, to allow client applications to <em>access font files
easily</em>, wherever they could be stored, and as independently
of font format as possible.</p></li>
<li><p>to allow easy <em>retrieval of global font data</em> most commonly
found in normal font formats (i.e. global metrics,
encoding/charmaps, etc..)</p></li>
<li><p>to allow easy <em>retrieval of individual glyph data</em>
(metrics, images, name, anything else)</p></li>
<li><p>to allow <em>access to font format-specific "features"</em>
whenever possible (e.g. SFNT tables, Multiple Masters,
OpenType Layout tables, etc..)</p></li>
<p>its design has also severely been influenced by the following
<li><p><b>high portability</b>, as the library must be able to run
on any kind of environment. this requirement introduces a few
drastic choices that are part of FreeType 2's low-level system
<li><p><b>extendibility</b>, as new features should be added with
the least modifications in the library's code base. this
requirements induces an extremely simple design where nearly
all operations are provided by modules.
<li><p><b>customization</b>, it should be easy to build a version
of the library that only contains the features needed by a
specific project. This really is important when you need to
integrate it in a font server for embedded graphics libraries.</p></li>
<li><p><b>compactness</b> and <b>efficiency</b>, given that the
primary target for this library is embedded systems with low
cpu and memory resources.</p></li>
<p>The rest of this document is divided in several sections. First, a
few chapters will present the library's basic design as well as the
objects/data managed internally by FreeType 2.</p>
<p>A later section is then dedicated to library customization, relating
such topics as system-specific interfaces, how to write your own
module and how to tailor library initialisation & compilation
to your needs.</p>
<head><title>The Design of FreeType 2 - Basic Design</title>
<basefont face="Georgia, Arial, Helvetica, Geneva">
<style content="text/css">
P { text-align=justify }
H1 { text-align=center }
H2 { text-align=center }
LI { text-align=justify }
<body text=#000000 bgcolor=#ffffff>
<center><table width="500"><tr><td>
<center><h1>The Design of FreeType 2</h1></center>
<table width="100%" cellpadding=5><tr bgcolor="#ccccee"><td>
<h1>I. Components and APIs</h1>
<p>It's better to describe FreeType 2 as a collection of
<em>components</em>. Each one of them is a more or less abstract
part of the library that is in charge of one specific task. We will
now explicit the connections and relationships between them.</p>
<p>A first brief description of this system of components could be:</p>
client applications typically call the FreeType 2 <b>high-level
API</b>, whose functions are implemented in a single component
called the <em>Base Layer</em>.
depending on the context or the task, the base
layer then calls one or more <em>module</em> components to
perform the work. In most cases, the client application doesn't
need to know what module was called.
the base layer also contains a set of routines that are
used for generic things like memory allocation, list
processing, i/o stream parsing, fixed point computation,
etc.. these functions can also be called by a module
at any time, and they form what is called the <b>low-level
base API</b>.
<p>This is illustrated by the following graphics (note that component
entry points are represented as colored triangles):</p>
<center><img src="basic-design.png" width="394" height="313"></center>
<p>Now, a few additional things must be added to complete this picture:</p>
<li><p>some parts of the base layer can be replaced for specific builds
of the library, and can thus be considered as components themselves.
this is the case for the <b>ftsystem</b> component, which is in
charge of implementing memory management & input stream access,
as well as the <b>ftinit</b>, which is in charge of library
initialisation (i.e. implementing <tt>FT_Init_FreeType</tt>).
FreeType 2 comes also with a set of <em>optional components</em>,
which can be used either as a convenience for client applications
(e.g. the <b>ftglyph</b> component, used to provide a simple API
to manage glyph images independently of their internal representation),
or to access format-specific features (e.g. the <b>ftmm</b> component
used to access and manage Multiple Masters data in Type 1 fonts)
Finally, a module is capable of calling functions provided by
another module. This is very useful to share code and tables
between several font driver modules (for example, the <tt>truetype</tt>
and <tt>cff</tt> both use the routines provided by the <tt>sfnt</tt>
<p>Hence, a more complete picture would be:</p>
<center><img src="detailed-design.png" width="390" height="429"></center>
<p>Please take note of the following important points:</p>
an optional component can use either the high-level or base
API. This is the case of <b>ftglyph</b> in the above picture.
some optional component can use module-specific interfaces
ignored by the base layer. In the above example, <b>ftmm</b>
directly accesses the Type 1 module to set/query data
a replacable component can provide a function of the high-level
API. For example, <b>ftinit</b> provides <tt>FT_Init_FreeType</tt>
to client applications.
<head><title>The Design of FreeType 2 - Public Objects</title>
<basefont face="Georgia, Arial, Helvetica, Geneva">
<style content="text/css">
P { text-align=justify }
H1 { text-align=center }
H2 { text-align=center }
LI { text-align=justify }
<body text=#000000 bgcolor=#ffffff>
<center><table width="500"><tr><td>
<center><h1>The Design of FreeType 2</h1></center>
<table width="100%" cellpadding=5><tr bgcolor="#ccccee"><td>
<h1>II. Public Objects and Classes</h1>
<p>We will now detail the abstractions provided by FreeType 2 to
client applications to manage font files and data. As you would
normally expect, these are implemented through objects/classes.</p>
<h2>1. Object Orientation in FreeType 2:</h2>
<p>Though written in ANSI C, the library employs a few
techniques, inherited from object-oriented programming, to make
it easy to extend. Hence, the following conventions apply in
the FT2 source code:</p>
each object type/class has a corresponding <em>structure type</em> <b>and</b>
a corresponding <em>structure pointer type</em>. the latter is called the
<em>handle type</em> for the type/class.</p>
<p>Consider that we need to manage objects of type "foo" in FT2.
We would define the following structure and handle types as
<pre><font color="blue">
typedef struct FT_FooRec_* FT_Foo;
typedef struct FT_FooRec_
// fields for the "foo" class
} FT_FooRec;
<p>As a convention, handle types use simple but meaningful identifiers
beginning with "FT_", as in "FT_Foo", while structures use the same
name with a "Rec" suffix appended to it ('Rec' is short for "record").
<em>Note that each class type has a corresponding handle type</em>.
class derivation is achieved internally by wrapping base class
structures into new ones. As an example, let's define a "foobar"
class that is derived from "foo". We would do something like:</p>
<pre><font color="blue">
typedef struct FT_FooBarRec_* FT_FooBar;
typedef struct FT_FooBarRec_
// the base "foo" class fields
FT_FooRec root;
// fields proper to the "foobar" class
} FT_FooBarRec;
<p>As you can see, we ensure that a "foobar" object is also a "foo"
object by placing a <tt>FT_FooRec</tt> at the start of the
<tt>FT_FooBarRec</tt> definition. It is called <b>root</b>
by convention.</p>
<p>Note that a <tt>FT_FooBar</tt> handle also points to a "foo" object
and can be typecasted to <tt>FT_Foo</tt>. Similarly, when the
library handles a <tt>FT_Foo</tt> handle to client applications,
the object can be really implemented as a <tt>FT_FooBar</tt> or any
derived class from "foo".</p>
<p>Note that in the following sections of this chapter, we will refer
to "the <tt>FT_Foo</tt> class" to indicate the type of objects
handled through <tt>FT_Foo</tt> pointers, be they implemented as
"foo" or "foobar".</p>
<h2>2. The <em><b>FT_Library</b></em> class:</h2>
<p>This type corresponds to a handle to a single instance of the
library. Note that the corresponding structure <tt>FT_LibraryRec</tt>
is not defined in public header files, making client applications
unable to access its internal fields.</p>
<p>The library object is the "parent" of all other objects in FreeType 2.
You need to create a new library instance before doing anything else
with the library. Similarly, destroying it will automatically
destroy all its children (i.e. faces and modules).</p>
<p>Typical client applications should call <tt>FT_Init_FreeType</tt>,
in order to create a new library object, ready to be used for
further action.</p>
<p>Another alternative is to create a fresh new library instance
by calling the function <tt>FT_New_Library</tt>, defined in the
<tt>&lt;freetype/ftmodule.h&gt;</tt> public header file. This
function will however return an "empty" library instance with
no module registered in it. You can "install" modules in the
instance by calling <tt>FT_Add_Module</tt> manually.</p>
<p>Calling <tt>FT_Init_FreeType</tt> is a lot more convenient, because
this function basically registers a set of default modules into
each new library instance. The way this list is accessed and/or
computed is determined at build time, and depends on the content
of the <b>ftinit</b> component. This process is explained in
details later in this document.</p>
<p>For now, one should consider that library objects are created
with <tt>FT_Init_FreeType</tt>, and destroyed along with all
children with <tt>FT_Done_FreeType</tt>.</p>
<h2>3. The <em><b>FT_Face</b></em> class:</h2>
<p>A face object corresponds to a single <em>font face</em>, i.e.
a specific typeface with a specific style. For example, "Arial"
and "Arial Italic" correspond to two distinct faces.</p>
<p>A face object is normally created through <tt>FT_New_Face</tt>.
This function takes the following parameters: a <tt>FT_Library</tt>
handle, a C file pathname used to indicate which font file to
open, an index used to decide which face to load from the file
(a single file may contain several faces in certain cases),
as well as the address of a <tt>FT_Face</tt> handle. It returns
an error code:</p>
<pre><font color="blue">
FT_Error FT_New_Face( FT_Library library,
const char* filepathname,
FT_Long face_index,
FT_Face *face );
<p>in case of success, the function will return 0, and the handle
pointed to by the "face" parameter will be set to a non-NULL value.</p>
<p>Note that the face object contains several fields used to
describe global font data that can be accessed directly by
client applications. For example, the total number of glyphs
in the face, the face's family name, style name, the EM size
for scalable formats, etc.. For more details, look at the
<tt>FT_FaceRec</tt> definition in the FT2 API Reference.</p>
<h2>4. The <em><b>FT_Size</b></em> class:</h2>
<p>Each <tt>FT_Face</tt> object <em>has</em> one or more <tt>FT_Size</tt>
objects. A <em>size object</em> is used to store data specific to a
given character width and height. Each newly created face object
has one size, which is directly accessible as <tt>face-&gt;size</tt>.</p>
<p>The content of a size object can be changed by calling either
<tt>FT_Set_Pixel_Sizes</tt> or <tt>FT_Set_Char_Size</tt>.</p>
<p>A new size object can be created with <tt>FT_New_Size</tt>, and
destroyed manually with </tt>FT_Done_Size</tt>. Note that typical
applications don't need to do this normally: they tend to use
the default size object provided with each <tt>FT_Face</tt>.</p>
<p>The public fields of <tt>FT_Size</tt> objects are defined in
a very small structure named <tt>FT_SizeRec</tt>. However, it is
important to understand that some font drivers define their own
derivatives of <tt>FT_Size</tt> to store important internal data
that is re-computed each time the character size changes. Most of
the time, these are size-specific <em>font hints</em>./p>
<p>For example, the TrueType driver stores the scaled CVT table that
results from the execution of the "cvt" program in a <tt>TT_Size</tt>,
while the Type 1 driver stores scaled global metrics (like blue zones)
in a <tt>T1_Size</tt> object. Don't worry if you don't understand
the current paragraph, most of this stuff is highly font format
specific and doesn't need to be explained to client developers :-)</p>
<h2>5. The <em><b>FT_GlyphSlot</b></em> class:</h2>
<p>The purpose of a glyph slot is to provide a place where glyph
images can be loaded one by one easily, independently of the
glyph image format (bitmap, vector outline, or anything else).</p>
<p>Ideally, once a glyph slot is created, any glyph image can
be loaded into it without additional memory allocation. In practice,
this is only possible with certain formats like TrueType which
explicitely provide data to compute a slot's maximum size.</p>
<p>Another reason for glyph slots is that they're also used to hold
format-specific hints for a given glyphs has well as all other
data necessary to correctly load the glyph.</p>
<p>The base <tt>FT_GlyphSlotRec</tt> structure only presents glyph
metrics and images to client applications, while actual implementation
may contain more sophisticated data.</p>
<p>As an example, the TrueType-specific <tt>TT_GlyphSlotRec</tt>
structure contains additional fields to hold glyph-specific bytecode,
transient outlines used during the hinting process, and a few other
the Type1-specific <tt>T1_GlyphSlotRec</tt> structure holds
glyph hints during glyph loading, as well as additional logic used
to properly hint the glyphs when a native T1 hinter is used.</p>
<p>Finally, each face object has a single glyph slot, that is directly
accessible as <tt>face-&gt;glyph</tt>.</p>
<h2>6. The <em><b>FT_CharMap</b></em> class:</h2>
<p>Finally, the <tt>FT_CharMap</tt> type is used as a handle to
character map objects, or "charmaps" to be brief. A charmap is
simply some sort of table or dictionary which is used to translate
character codes in a given encoding into glyph indices for the
<p>A single face may contain several charmaps. Each one of them
corresponds to a given character repertoire, like Unicode, Apple Roman,
Windows codepages, and other ugly "standards".</p>
<p>Each <tt>FT_CharMap</tt> object contains a "platform" and an "encoding"
field used to identify precisely the character repertoire corresponding
to it.</p>
<p>Each font format provides its own derivative of <tt>FT_CharMapRec</tt>
and thus needs to implement these objects.</p>
<h2>7. Objects relationships:</h2>
<p>The following diagram summarizes what we just said regarding the
public objects managed by the library, as well as explicitely
describes their relationships:</p>
<p>Note that this picture will be updated at the end of the next
chapter, related to <em>internal objects</em>.</p>
<head><title>The Design of FreeType 2 - Internal Objects</title>
<basefont face="Georgia, Arial, Helvetica, Geneva">
<style content="text/css">
P { text-align=justify }
H1 { text-align=center }
H2 { text-align=center }
LI { text-align=justify }
<body text=#000000 bgcolor=#ffffff>
<center><table width="500"><tr><td>
<center><h1>The Design of FreeType 2</h1></center>
<table width="100%" cellpadding=5><tr bgcolor="#ccccee"><td>
<h1>III. Internal Objects and Classes</h1>
<p>Let's have a look now at the <em>internal</em> objects that FreeType 2
uses, i.e. those not directly available to client applications, and
let's see how they fit in the picture.</p>
<h2>1. Memory management:</h2>
<p>All memory management operations are performed through three specific
routines of the base layer, namely: <tt>FT_Alloc</tt>, <tt>FT_Realloc</tt>,
and <tt>FT_Free</tt>. Each one of these functions expects a
<tt>FT_Memory</tt> handle as its first parameter.</p>
<p>The latter is a pointer to a simple object used to describe the current
memory pool/manager to use. It contains a simple table of
alloc/realloc/free functions. A memory manager is created at
library initialisation time by <tt>FT_Init_FreeType</tt> by calling
the function <tt>FT_New_Memory</tt> provided by the <b>ftsystem</b>
<p>By default, this manager uses the ANSI <tt>malloc</tt>, <tt>realloc</tt>
and <tt>free</tt> functions. However, as <b>ftsystem</b> is a replaceable
part of the base layer, a specific build of the library could provide
a different default memory manager.</p>
<p>Even with a default build, client applications are still able to provide
their own memory manager by not calling <tt>FT_Init_FreeType</tt> but
follow these simple steps:</p>
create a new <tt>FT_Memory</tt> object by hand. The definition of
<tt>FT_MemoryRec</tt> is located in the public file
call <tt>FT_New_Library</tt> to create a new library instance using
your custom memory manager. This new library is "virgin" and doesn't
contain any registered modules.
Register the set of default modules by calling the function
<tt>FT_Add_Default_Modules</tt> provided by the <b>ftinit</b>
component, or manually register your drivers by repeatedly
calling <tt>FT_Add_Module</tt>.
<h2>2. Input streams:</h2>
<p>Font files are always read through <tt>FT_Stream</tt> objects. The
definition of <tt>FT_StreamRec</tt> is located in the public file
<tt>&lt;freetype/ftsystem.h&gt;</tt>, which allows client developers
to provide their own implementation of streams if they wish so.</p>
<p>The function <tt>FT_New_Face</tt> will always automatically create a
new stream object from the C pathname given as its second argument.
This is achieved by calling the function <tt>FT_New_Stream</tt> provided
by the <b>ftsystem</b> component. As the latter is replaceable,
the implementation of streams may vary greatly between platforms.</p>
<p>As an example, the default implementation of streams is located in
the file "<tt>src/base/ftsystem.c</tt>" and uses the ANSI <tt>fopen</tt>,
<tt>fseek</tt>, <tt>fread</tt> calls. However, the Unix build of
FreeType 2 provides an alternative implementation that uses
memory-mapped files, when available on the host platform, resulting
in a significant access speed-up.</p>
<p>FreeType distinguishes between memory-based and disk-based
streams. In the first case, all data is directly accessed in memory
(e.g. ROM-based, write-only static data and memory-mapped files),
while in the second, portions of the font files are read in chunks
called "frames", and temorarily buffered adequately through typical
seek/read operations.</p>
<p>The FreeType stream sub-system also implements extremely efficient
algorithms to very quickly load structures from font files while
ensure complete safety in the case of "broken file".</p>
<p>The function <tt>FT_New_Memory_Face</tt> can be used
to directly create/open a <tt>FT_Face</tt> object from data that is
readily available in memory (including ROM-based fonts).</p>
<p>Finally, in the case where a custom input stream is needed, client
applications can use the function <tt>FT_Open_Face</tt>, which can
accept custom input streams.. This may be useful in the case of
compressed or remote font files, or even embedded font files that
need to be extracted from certain documents.</p>
<p>Note that each face owns a single stream, which is also destroyed
by <tt>FT_Done_Face</tt>. Generally speaking, it's certainly
<em>not a good idea</em> to keep numerous <tt>FT_Face</tt> objects
<h2>3. Modules:</h2>
<p>A FreeType 2 module is itself a piece of code. However, the library
creates a single <tt>FT_Module</tt> object for each module that is
registered when <tt>FT_Add_Module</tt> is called.</p>
<p>The definition of <tt>FT_ModuleRec</tt> is not publicly available
to client applications. However, each <em>module type</em> is described
by a simple and public structure named <tt>FT_Module_Class</tt>,
defined in <tt>&lt;freetype/ftmodule.h&gt;</tt>, and is detailed
heavily later in this document:</p>
<p>You need a pointer to a <tt>FT_Module_Class</tt> structure when
calling <tt>FT_Add_Module</tt>, whose declaration is:</p>
<pre><font color="blue">
FT_Error FT_Add_Module( FT_Library library,
const FT_Module_Class* clazz );
<p>Calling this function will do the following:</p>
it will check if the library already holds a module object corresponding
to the same module name as the one found in the <tt>FT_Module_Class</tt>.
it this is the case, it will compare the module version number to see
if it is possible to <em>upgrade</em> the module to a new version. If
the module class's version number is smaller than the already
installed one, the function returns immediately. Similarly, it checks
that the version of FreeType 2 that is running is correct compared
to the one required by the module.
it creates a new <tt>FT_Module</tt> object, using data and flags
of the module class to determine its byte size and how to properly
initialize it.
when a module initializer is present in the module class, it will
be called to complete the module object's initialisation.
the new module is added to the library's list of "registered"
modules. In case of an upgrade, the previous module object is
simply destroyed.