Author: David Turner

# The design of FreeType 2

### Copyright 1998-2000 David Turner (david@freetype.org)
Copyright 2000 The FreeType Development Team (devel@freetype.org)

Previous | Contents | Next
# III. Internal Objects and Classes
Let us have a look now at the internal objects that FreeType 2 uses, i.e., those not directly available to client applications, and see how they fit into the picture. ## 1. Memory management All memory management operations are performed through three specific routines of the base layer, namely: `FT_Alloc()`, `FT_Realloc()`, and `FT_Free()`. Each one of these functions expects a `FT_Memory` handle as its first parameter. The latter is a pointer to a simple object used to describe the current memory pool/manager. It contains a simple table of alloc/realloc/free functions. A memory manager is created at library initialization time by `FT_Init_FreeType()`, calling the function `FT_New_Memory()` provided by the `ftsystem` component. By default, this manager uses the ANSI `malloc()`, `realloc()`, and `free()` functions. However, as `ftsystem` is a replaceable part of the base layer, a specific build of the library could provide a different default memory manager. Even with a default build, client applications are still able to provide their own memory manager by not calling `FT_Init_FreeType()` but follow these simple steps: Create a new `FT_Memory` object by hand. The definition of `FT_MemoryRec` is located in the public file `<freetype/ftsystem.h>`. Call `FT_New_Library()` to create a new library instance using your custom memory manager. This new library doesn't yet contain any registered modules. Register the set of default modules by calling the function `FT_Add_Default_Modules()` provided by the `ftinit` component, or manually register your drivers by repeatedly calling `FT_Add_Module()`. ## 2. Input streams Font files are always read through `FT_Stream` objects. The definition of `FT_StreamRec` is located in the public file `<freetype/ftsystem.h>`, which allows client developers to provide their own implementation of streams if they wish so. The function `FT_New_Face()` will always automatically create a new stream object from the C pathname given as its second argument. This is achieved by calling the function `FT_New_Stream()` provided by the `ftsystem` component. As the latter is replaceable, the implementation of streams may vary greatly between platforms. As an example, the default implementation of streams is located in the file `src/base/ftsystem.c` and uses the ANSI `fopen()`, `fseek()`, and `fread()` 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. 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 temporarily buffered similarly through typical seek/read operations. The FreeType stream sub-system also implements extremely efficient algorithms to very quickly load structures from font files while ensuring complete safety in the case of a "broken file". The function `FT_New_Memory_Face()` can be used to directly create/open a `FT_Face` object from data that is readily available in memory (including ROM-based fonts). Finally, in the case where a custom input stream is needed, client applications can use the function `FT_Open_Face()`, 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. Note that each face owns a single stream, which is also destroyed by `FT_Done_Face()`. Generally speaking, it is certainly not a good idea to keep numerous `FT_Face` objects opened. ## 3. Modules A FreeType 2 module is itself a piece of code. However, the library creates a single `FT_Module` object for each module that is registered when `FT_Add_Module()` is called. The definition of `FT_ModuleRec` is not publicly available to client applications. However, each module type is described by a simple public structure named `FT_Module_Class`, defined in `<freetype/ftmodule.h>`, and is described later in this document: You need a pointer to an `FT_Module_Class` structure when calling `FT_Add_Module()`, whose declaration is:
        FT_Error  FT_Add_Module( FT_Library              library,
                                 const FT_Module_Class*  clazz );
Calling this function will do the following: It will check whether the library already holds a module object corresponding to the same module name as the one found in `FT_Module_Class`. If this is the case, it will compare the module version number to see whether it is possible to upgrade 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 `FT_Module` object, using data and flags of the module class to determine its byte size and how to properly initialize it. If a module initializer is present in the module class, it will be called to complete the module object's initialization. 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. Note that this function doesn't return an `FT_Module` handle, given that module objects are completely internal to the library (and client applications shouldn't normally mess with them :-) Finally, it is important to understand that FreeType 2 recognizes and manages several kinds of modules. These will be explained in more details later in this document, but we will list for now the following types: Renderer modules are used to convert native glyph images to bitmaps/pixmaps. FreeType 2 comes with two renderer modules by default: one to generate monochrome bitmaps, the other to generate high-quality anti-aliased pixmaps. Font driver modules are used to support one or more font formats. Typically, each font driver provides a specific implementation/derivative of `FT_Face`, `FT_Size`, `FT_GlyphSlot`, as well as `FT_CharMap`. Helper modules are shared by several font drivers. For example, the `sfnt` module parses and manages tables found in SFNT-based font formats; it is then used by both the TrueType and OpenType font drivers. Finally, the auto-hinter module has a specific place in the library's design, as its role is to process vectorial glyph outlines, independently of their native font format, to produce optimal results at small pixel sizes. Note that every `FT_Face` object is owned by the corresponding font driver, depending on the original font file's format. This means that all face objects are destroyed when a module is removed/unregistered from a library instance (typically by calling the `FT_Remove_Module()` function). Because of this, you should always take care that no `FT_Face` object is opened when you upgrade or remove a module from a library, as this could cause unexpected object deletion! ## 4. Libraries We now come back to our well-known `FT_Library` object. From what have been said before, we already know that a library instance owns at least the following: A memory manager object (`FT_Memory`), used for all allocation/releases within the instance. A list of `FT_Module` objects, corresponding to the "installed" or "registered" modules of the instance. This list can be changed at any time through `FT_Add_Module()` and `FT_Remove_Module()`. Remember that face objects are owned by font drivers that are themselves modules owned by the library. There is however another object owned by the library instance that hasn't been described yet: the raster pool. The raster pool is simply a block of memory of fixed size that is used internally as a "scratch area" for various memory-hungry transient operations, avoiding memory allocation. For example, it is used by each renderer when converting a vectorial glyph outline into a bitmap (actually, that's where its name comes from :-). The size of the raster pool is fixed at initialisation time (it defaults to 16kByte) and cannot be changed at run-time (though we could fix this if there is a real need for that). When a transient operation needs more memory than the pool's size, it can decide to either allocate a heap block as an exceptional condition, or sub-divide recursively the task to perform in order to never exceed the pool's threshold. This extremely memory-conservative behaviour is certainly one of the keys to FreeType's performance in certain areas (most importantly in glyph rendering/scanline-conversion). ## 5. Summary Finally, the following picture illustrates what has been said in this section, as well as the previous, by presenting the complete object graph of FreeType 2's base design:
Previous | Contents | Next