diff --git a/docs/design/basic-design.png b/docs/design/basic-design.png index 881e1a8de..5acdccc54 100644 Binary files a/docs/design/basic-design.png and b/docs/design/basic-design.png differ diff --git a/docs/design/design-1.html b/docs/design/design-1.html new file mode 100644 index 000000000..604fbc873 --- /dev/null +++ b/docs/design/design-1.html @@ -0,0 +1,82 @@ + +
+
+The Design of FreeType 2
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. + +Before anything else, it is important to understand the purpose + of this library, i.e. why it has been written: + +
its design has also severely been influenced by the following + requirements: + +
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. + +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. + + |
+
+The Design of FreeType 2
It's better to describe FreeType 2 as a collection of + components. 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. + +A first brief description of this system of components could be: +
This is illustrated by the following graphics (note that component + entry points are represented as colored triangles): + +Now, a few additional things must be added to complete this picture: + +
Hence, a more complete picture would be: + +Please take note of the following important points: + +
|
+
+The Design of FreeType 2
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. + +1. Object Orientation in FreeType 2:+ +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: + +
Note that in the following sections of this chapter, we will refer + to "the FT_Foo class" to indicate the type of objects + handled through FT_Foo pointers, be they implemented as + "foo" or "foobar". + ++ + 2. The FT_Library class:+ +This type corresponds to a handle to a single instance of the + library. Note that the corresponding structure FT_LibraryRec + is not defined in public header files, making client applications + unable to access its internal fields. + +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). + +Typical client applications should call FT_Init_FreeType, + in order to create a new library object, ready to be used for + further action. + +Another alternative is to create a fresh new library instance + by calling the function FT_New_Library, defined in the + <freetype/ftmodule.h> 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 FT_Add_Module manually. + +Calling FT_Init_FreeType 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 ftinit component. This process is explained in + details later in this document. + +For now, one should consider that library objects are created + with FT_Init_FreeType, and destroyed along with all + children with FT_Done_FreeType. ++ + 3. The FT_Face class:+ +A face object corresponds to a single font face, i.e. + a specific typeface with a specific style. For example, "Arial" + and "Arial Italic" correspond to two distinct faces. + +A face object is normally created through FT_New_Face. + This function takes the following parameters: a FT_Library + 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 FT_Face handle. It returns + an error code: + ++ FT_Error FT_New_Face( FT_Library library, + const char* filepathname, + FT_Long face_index, + FT_Face *face ); ++ + 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. + +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 + FT_FaceRec definition in the FT2 API Reference. + ++ + 4. The FT_Size class:+ +Each FT_Face object has one or more FT_Size + objects. A size object 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 face->size. + +The content of a size object can be changed by calling either + FT_Set_Pixel_Sizes or FT_Set_Char_Size. + +A new size object can be created with FT_New_Size, and + destroyed manually with FT_Done_Size. Note that typical + applications don't need to do this normally: they tend to use + the default size object provided with each FT_Face. + +The public fields of FT_Size objects are defined in + a very small structure named FT_SizeRec. However, it is + important to understand that some font drivers define their own + derivatives of FT_Size to store important internal data + that is re-computed each time the character size changes. Most of + the time, these are size-specific font hints./p> + + For example, the TrueType driver stores the scaled CVT table that + results from the execution of the "cvt" program in a TT_Size, + while the Type 1 driver stores scaled global metrics (like blue zones) + in a T1_Size 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 :-) + ++ + 5. The FT_GlyphSlot class:+ +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). + +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. + +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. + +The base FT_GlyphSlotRec structure only presents glyph + metrics and images to client applications, while actual implementation + may contain more sophisticated data. + +As an example, the TrueType-specific TT_GlyphSlotRec + structure contains additional fields to hold glyph-specific bytecode, + transient outlines used during the hinting process, and a few other + things. + + the Type1-specific T1_GlyphSlotRec 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. + +Finally, each face object has a single glyph slot, that is directly + accessible as face->glyph. + ++ + 6. The FT_CharMap class:+ +Finally, the FT_CharMap 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 + font. + +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". + +Each FT_CharMap object contains a "platform" and an "encoding" + field used to identify precisely the character repertoire corresponding + to it. + +Each font format provides its own derivative of FT_CharMapRec + and thus needs to implement these objects. + ++ 7. Objects relationships:+ +The following diagram summarizes what we just said regarding the + public objects managed by the library, as well as explicitely + describes their relationships: + +Note that this picture will be updated at the end of the next + chapter, related to internal objects. + + |
+
+The Design of FreeType 2
Let's have a look now at the internal objects that FreeType 2 + uses, i.e. those not directly available to client applications, and + let's see how they fit in 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 to use. It contains a simple table of + alloc/realloc/free functions. A memory manager is created at + library initialisation time by FT_Init_FreeType by 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: + +
+ 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, 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 temorarily buffered adequately through typical + seek/read operations. + +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". + +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's 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 and public structure named FT_Module_Class, + defined in <freetype/ftmodule.h>, and is detailed + heavily later in this document: + +You need a pointer to a 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: + +
Note that this function doesn't return a FT_Module handle, + given that module objects are completely internal to the library + (and client applications shouldn't normally mess with them :-) + +Finally, it's 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'll list for now the + following types: + +
Note that every FT_Face object is owned by the + corresponding font driver (that depends 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 + FT_Remove_Module). + + +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:+ +And we now come back to our well-known FT_Library objects. + From what have been said here, we already know that a library + instance owns at least the following: + +
There is however another object owned by the library instance that + hasn't been described until now, and it's 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. 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 advantage of using a raster pool comes from the fact that it + allows us to completely avoid memory allocation during certain + memory-intensive though common transient operations (like + glyph bitmap generation), speeding up the overall process. + +The size of the raster pool is fixed at initialisation time + (it defaults to 16 Kb) and cannot be changed at run-time + (though we could fix this if there's 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: + + |