The FreeType Engine Core Library User Guide or How to use the engine in your applications and font servers by David Turner --------------------------------------------------- Introduction I. Basic Concepts: 1. Concepts 2. Handles 3. Conventions of use 4. Object classes II. Extensions: 1. What is an extension? 2. Where to find them 3. Writing your own extension Conclusion ---------------------------- Introduction: This file has been written to present the FreeType core library to would-be writers of applications and font servers. It first describes the concepts on which the engine is based, then how to use it to obtain glyph metrics, outlines and bitmaps. The last part discusses the ability to add and use extensions to the core library to get access to supplemental TrueType tables which are not currently provided by the core engine. If you would like to write your own extensions, read also the FreeType developer's guide. I. Basic Concepts: 1. Concepts: FreeType defines several kinds of structures, called "objects", that are used to manage the various abstractions required to access and display fonts. In a care of good encapsulation, these objects are not directly accessible from a client application. Rather, the user receives a 'handle' for each object it queries and wants to use. This handle is a stand-alone reference, it cannot be used like a pointer to access directly the object's data. 2. Properties: It is however possible to obtain and set object properties through several functions of the API. For example, it is possible to query a face object's properties with only a handle for it, using the function TT_Get_Face_Properties(). Note that the data will be returned in a user-allocated structure, but will also contain pointers addressing directly some data found within the object. A client application should never modify the data through these pointers! In order to set new properties' values, the user must always call a specific API to do so, as a certain number of other related data might not appear in the returned structure and imply various non-visible coherency and coercion rules. 3. Conventions of use: o All API functions have their label prefixed by 'TT_', as well as all external (i.e. client-side) types. o To allow the use of FreeType's core engine in threaded environments, nearly all API functions return an error code, which is always set to 0 in case of success. The error codes' type is TT_Error, and a listing of them is given in the API reference (see "apiref.txt"). Some functions do not return an error code. Their result is usually a value that becomes negative in case of error. (this is used for functions where only one kind of error can be reported, like an invalid glyph index). An important note is that the engine should not leak memory when returning an error, e.g. querying the creation of an object will allocate several internal tables that will be freed if a disk error occurs during a load. o A handle is acquired through API functions labelled along the names: TT_Open_xxxx(), TT_New_xxxx() where xxxx is the object's class (Face, Instance, etc.) examples: TT_Open_Face(), TT_Open_Collection(), TT_New_Instance(), TT_New_Glyph() o A handle is closed through an API labelled TT_Close_xxxx() or TT_Done_xxxx() where xxxx is the object's class (Face, Instance, etc.) examples: TT_Close_Face(), TT_Done_Instance(), TT_Done_Glyph() o Properties are obtained through an API labelled TT_Get_xxxx_yyyy() where xxxx is the object's class, and yyyy its property examples: TT_Get_Face_Properties(), TT_Get_Instance_Metrics() TT_Get_Glyph_Outline(), TT_Get_Glyph_Bitmap() o Properties are set through an API labelled TT_Set_xxxx_yyyy() where xxxx is the object's class, and yyyy its property examples: TT_Set_Instance_Resolutions(), TT_Set_Instance_CharSize() 4. Object Classes: The following object classes are defined in this release of the engine: * The Engine objects: RELEASE NOTE : FreeType 1.0 doesn't support threads yet. However, the following notes will still be valid when it will. The FreeType library can be built to be completely re-entrant, even though its default build doesn't support threads (more on this in the developer's guide). As a consequence, it is possible to open several instances of the library, called 'engines'. Each engine has its own set of current objects ( faces, instances, etc.. ), and there is no sharing between them. The idea is that the library could be compiled into a shared DLL, and then be able to provide several distinct engines to independent client applications. In this case, each client program must create its own engine with TT_Init_FreeType, to hold its data. Closing an engine will destroy _all_ objects that were allocated since its opening, releasing all resources.., with the exception of user-allocated outline objects. * The Face objects: A face contains the data that is specific to a single TrueType font file. It presents information common to all glyphs and all point sizes like font-specific metrics and properties. You can open a face object by simply giving a pathname to the TrueType file. You can later close (i.e. discard) the face object. You can also open a single face embedded in a TrueType collection. See also: TT_Open_Face(), TT_Open_Collection(), TT_Close_Face(), TT_Get_face_Properties() * The Instance objects: An instance is also called a 'pointsize' or a 'fontsize' in some windowing systems. An instance holds the information used to render glyphs on a specific device at a given point size; it is always related to an opened face object. For instance, if you want to generate glyphs for text from the same typeface at 'sizes' of 10 and 12 points, all you need is one face object, from which you'll create two distinct instances. A device is defined by its horizontal and vertical resolution, usually specified in dots per inch (dpi). A point size is a scaling number, given as _absolute_ values in points, where 1 point = 1/72 inch. The 'pixel' size, also known as the 'ppem' value (for Points Per EM square) is computed from both the device resolution and the point size. It determines the size of the resulting glyph bitmaps on your screen or sheet of paper. The default device resolution for any new instance is 96dpi in both directions, which corresponds to VGA screens. The default point size is 10pt. The high-level API allows you to change this whenever you want for any given instance object. Note that closing a face object will automatically destroy all its child instances (even though you can release them yourself to free memory). See also: TT_New_Instance(), TT_Done_Instance(), TT_Get_Instance_Metrics(), TT_Set_Instance_Resolutions(), TT_Set_Instance_Pointsize() * The Glyph objects: A Glyph object is a _container_ for the data that describes any glyph of a given font. This means that it typically holds: - glyph metrics information, like bounding box or advance width. - outline arrays sized large enough to hold any glyph from the face. This size is extracted from the face's internal 'maxProfile' table to optimize memory costs. - other important parameters related to the 'fine' rendering of the glyphs. This includes things like the dropout-control mode used at low sizes. - and it doesn't contain a bitmap or a pixmap! A glyph object is used to load, hint and rasterize a single glyph, as taken from the font file. See also: TT_New_Glyph(), TT_Done_Glyph(), TT_Get_Glyph_Metrics(), TT_Get_Glyph_Outline(), TT_Get_Glyph_Bitmap(), TT_Get_Glyph_Pixmap() * The Character Map (CharMap) handle: Glyphs can be indexed in a TrueType file in any order, independent of any standard character encoding, like ASCII or Unicode. For this reason, each file comes with one or more character mapping tables, used to translate from one specific encoding's charcodes to font glyph indexes. There are many encoding formats, and each one can be distinguished by two values: - its platform ID - its platform-specific encoding ID Their values are defined in the TrueType specification and won't be commented there. The FAQ lists the most commonly used paris of (platform:encoding) pairs. It is possible to enumerate the charmaps provided by a TrueType font and to use any of these to perform translations. The charmaps are loaded in memory only on demand to save the space taken by the maps that are not needed on your system. They are part of the face object, however. This means that even though a charmap can be accessed through a handle (obtained through the TT_Get_CharMap() function), it isn't a stand-alone object. For example, you never need to de-allocate it; this is done automatically by the engine when its face object expires. See also: TT_Get_CharMap_Count(), TT_Get_CharMap_ID(), TT_Get_CharMap(), TT_Char_Index(). * The Outline Objects : An outline is a vector representation of a glyph. It is made of several control points joined by line segments and bezier arcs, themselves gathered in closed paths called "contours". The outline have also several flags, or attributes, which are used by the scan-line converter to select the best rendering algorithms to convert the glyph's bitmap. Unlike other objects in FreeType, outlines aren't managed through handles, but directly with the structure TT_Outline, defined for client applications. Each glyph container contains an outline sized large enough to hold any glyph from its parent face. Client applications can access it with the TT_Get_Glyph_Outline. However, one can also create its own outlines if he needs to with TT_New_Outline and TT_Clone_Outline. Note that user-created outlines are NOT tracked by the library. Hence, the client must release them itself with one or more calls to TT_Done_Outline. A various number of methods/operations are defined for the outline class to simplify its management. IMPORTANT NOTE : ***************************************** The definition of TT_Outline may change in the future. Developers are thus advised to always use the outline methods provided by the API rather than reading or setting data themselves. ********************************************************** See also: TT_New_Outline, TT_Clone_Outline, TT_Copy_Outline, TT_Done_Outline, TT_Get_Outline_BBox, TT_Get_Outline_Bitmap, TT_Get_Outline_Pixmap, TT_Translate_Outline, TT_Transform_Outline * Bitmaps and Pixmaps : One very important aspect of FreeType is that it is unable to create bitmaps on its own. Rather, it is to the client application to do it, and pass a reference, in the form of a TT_raster_Map, to the scan-line converter (the component in charge of generating bitmaps from outlines). Hence, the importance of the TT_Raster_Map structure, which layout is : struct { int rows; /* number of rows */ int cols; /* number of columns (bytes) per row */ int width; /* number of pixels per line */ int flow; /* bitmap orientation */ void* bitmap; /* bit/pixmap buffer */ long size; /* bit/pixmap size in bytes */ } TT_Raster_Map; And where : - The 'rows' field contains the total number of rows in the bitmap - The 'width' field gives the number of pixels per row (a bit or a byte, depending on the map's nature). - The 'cols' field gives the number of columns, i.e. bytes, taken by each row in the map buffer. ** IMPORTANT **: the 'cols' field must be a multiple of 4 for pixmaps! Typically, its value should be '(width+7)/8' for bitmaps, and '(width+3) & -4' for pixmaps. - The 'flow' field gives the map's vertical orientation. For example, if the first bytes of the bitmap buffer pertain to its upper row, the flow is said to be going 'down', and the field should take the value 'TT_Flow_Down'. If these bytes pertain to its lowest row, the flow is going 'up', and the value is 'TT_Flow_Up'. As an example, the PC video modes use a 'down' flow, where the first VRAM byte corresponds to the upper and leftmost corner of the screen. - The 'bitmap' field is a typeless pointer to the map's buffer. - The 'size' field contains the buffer's size in bytes. It is usually computed as follows: size = rows * cols; NOTE: For bitmaps, the leftmost-pixel is related to the highest (i.e. most significant) bit of its byte. There is currently no support for the opposite convention found in some systems. (It can be easily added if you really need it, just ask the development team.) II. Step-by-step Example: Here is an example to show, step by step, how one client application can open a font file, set one or several instances, load any glyph, then render it to a bitmap. a. Initialize the engine: This is the first thing to do. You need to initialize an engine through a call to TT_Init_FreeType(). This function will set up a various number of structures needed by the library. This allocates about 68kByte, of which 64kByte are dedicated to the scan-line converter's "render pool", a workspace used for bitmap generation. Note that even though this space is bounded, the raster is able to render a glyph to any size or bitmap, even horribly huge ones. NOTE: You can reduce the size of this pool by modifying the constant RASTER_RENDER_POOL in the file 'ttraster.c'. A slower pool will result in slower rendering at large sizes. Take care of never assigning a value smaller than 4kByte however, as bug may start to lurk in !. Example: TT_Engine engine; error = TT_Init_FreeType( &engine ); if (error) { printf( "could not create engine instance\n"); .... } b. Init the extensions you need : FreeType provides several extensions, which are optional separately compilable components which add some rare features to the engine and its API. You need to explicitly init the extensions you want to use. Each extension must provide an initialisation function, following the naming convention : TT_Init_xxxxx_Extension( engine ); where 'xxxxxx' is the extension's "kind". For example : error = TT_Init_Kerning_Extension( engine ); if (error) ... c. Open the font file: There are two ways to open a font face, depending on its file format: - If it's a TrueType file (ttf), you can simply use the API named TT_Open_Face(), which takes the file's pathname as argument, as well as the address of the returned face handle. Check the returned error code to see if the file could be opened and accessed successfully. TT_Face face; /* face handle */ error = TT_Open_Face( engine, "c:\work\ttf\wingding.ttf", &face ); if ( error ) { printf( "could not open the file\n" ); ... } - If the font is embedded in a TrueType collection (ttc), you can use the API named TT_Open_Collection(), which takes also the font's index within the collection's directory. TT_Face face; /* face handle */ /* Load the collection's second face (index=1) */ error = TT_Open_Collection( engine, "c:\work\ttf\whatever.ttc", 1, &face ); if ( error ) { printf( "could not open the file\n" ); ... } - Finally, when you do not know the number of faces embedded in a TrueType collection, the following technique can be used: o call TT_Open_Face() with the collection file's pathname. This API recognizes collections automatically and always return a handle for its first embedded font. o get the face's properties through TT_Get_Face_Properties. These contain, among other things, the total number of fonts emebdded in the collection, in its field 'num_Faces'. TT_Face face; /* face handle */ TT_Face_Properties props; /* face properties */ /* open the first collection font */ error = TT_Open_Face( engine, "c:\work\ttf\collection.ttc", &face ); if ( error ) { printf( "could not open the file\n" ); ... } /* Get the face properties */ TT_Get_Face_Properties( face, &props ); /* Now print the number of faces */ printf( "there are %d faces in this collection file\n", props->num_Faces ); d. Create an instance from the face object: You must create an instance (a.k.a a pointsize) which contains information relative to the target output device's resolutions and a given point size. o The instance object is created through TT_New_Instance(): TT_Instance instance; error = TT_New_Instance( face, &instance ); if ( error ) { printf( "could not create instance\n" ); ... } TECHNICAL NOTE: Creating a new instance executes its font program. This can fail if the font is broken. Never assume that the error code returned here is always 0. o You must set the instance's properties to suit your needs. They are simply its device resolutions, set through TT_Set_Instance_Resolutions(), and its point size, set through TT_Set_Instance_CharSize(): /* set the target horizontal and vertical resolution to */ /* 300dpi in each direction (typically for a printer) */ /* A fresh instance's default resolutions are 96dpi in */ /* both directions. */ error = TT_Set_Instance_Resolutions( instance, 300, 300 ); if ( error ) { printf( "could not set resolution" ); ... } /* Now set the point size to 12 pts. Default is 10pt. */ /* Don't forget that the size is expressed in 26.6 fixed */ /* float format, so multiply by 64.. */ error = TT_Set_Instance_CharSize( instance, 12*64 ); if ( error ) { printf( "could not set point size" ); ... } TECH NOTE: These calls may execute the font's prep program, which can fail when the font is broken. Never assume that the error codes returned there are always successful. o You can also set the instance's transformation flags to tell the glyph loading function that you're going to perform a transformation (like rotation or slanting) on the glyph. Note that the glyph loader doesn't perform the transformation. It only informs the glyphs' hinting instruction streams about these flags which may use it to disable or enable various features (grid-fitting, drop-out control etc). TT_Set_Instance_Transforms( FALSE, TRUE ); to indicate that you're going to stretch, but not rotate, this instance's glyphs. Default is, of course, both FALSE. ************************************************************* RELEASE NOTE : With FreeType 1.0, setting this flags doesn't work and produces errors during glyph loading, you should not use them until a later release that fixes this. e. Create a glyph container: You need a glyph object to serve as a container for the glyphs you want to load from the face. This is done simply by TT_Glyph glyph; /* glyph object handle */ error = TT_New_Glyph( face, &glyph ); if ( error ) { printf( "could not create glyph\n" ); ... } f. Find your platform's character mappings: Each font file can come with one or more character mapping tables, used to convert char. codes to glyph indexs. You must know the values of the "platformId" and "encodingID" defined in the TrueType specification for your platform's charcode/codepage. For example, Windows Unicode encoding is (platform:3,encoding:1), while Apple Unicode is (platform:0,encoding:0).. Both formats differ in internal storage layout and can be used transparently with the same inputs with FreeType. The function TT_Get_CharMap_Count returns the number of character mappings present in a face. You can then enumerate these with the function TT_Get_CharMap_ID. Once you've found the mapping that masp your platform, use TT_Get_CharMap to return a TT_CharMap handle that will be used later to get glyph indexs. g. Load the glyph: The glyph loader is easily queried through TT_Load_Glyph(). This API function takes several arguments: o an instance handle, to specify at which point size and resolution the loaded glyph should be scaled and grid-fitted. o a glyph container, used to hold the glyph's data in memory. Note that the instance and the glyph must relate to the _same_ font file. An error would be produced immediately otherwise. o a glyph index, used to reference the glyph within the font file. This index is not a platform specific character code, and a character's glyph index may vary from one font to another. To compute glyph indexs from character codes, use the TT_CharMap handle created in f. with TT_Char_Index. We strongly recommend using the Unicode charmap whenever possible. o a load mode, indicating what kind of operations you need. There are only two defined for the moment: TTLOAD_SCALE_GLYPH: When set, this flag indicates that the loaded glyph will be scaled according to the instance specified as argument to fractional pixel coordinates (26.6). If not, the coordinates will remain integer FUnits. Please refer to the TrueType specification and the FreeType header files for more details on the 26.6 format and other data types. TTLOAD_HINT_GLYPH: This flag is only in effect when the TTLOAD_SCALE_GLYPH flag is set. It indicates that the glyph must also be 'hinted', or 'grid-fitted' for better display results. Note that this also means that the glyph metrics will be grid-fitted, including the bounding box.. You can 'or' the flags simply. As most applications will require both flags to be set, the constant TTLOAD_DEFAULT is defined as: #define TTLOAD_DEFAULT (TTLOAD_SCALE_GLYPH | \ TTLOAD_HINT_GLYPH ) example: error = TT_Load_Glyph( instance, glyph, 36, TTLOAD_DEFAULT ); if ( error ) { printf("could not load the glyph\n"); ... } g. Query glyph properties: You're then able to query various glyph properties: o The glyph metrics can be obtained through TT_Get_Glyph_Metrics(). The data returned in the metrics structure is: - the glyph's left side bearing (bearingX) - the glyph's top side bearing (bearingY) - the glyph's advance width (advance) - the glyph's bounding box (bbox) These values are expressed in 26.6 pixel units when the glyph was loaded with scaling, or in FUnits if not. o The glyph outline can be queried through TT_Get_Glyph_Outline(). This can be useful to process the points coordinates (e.g. applying stretching or rotation) with functions like TT_Apply_Outline_Matrix() or TT_Apply_Outline_Translation(). Note that these functions do not recompute a glyph's metrics after the transformation! The outline's structure is described in the reference "apiref.txt". A bitmap or pixmap for the glyph can be queried with the APIs TT_Get_Glyph_Bitmap() and TT_Get_Glyph_Pixmap(). These functions take a glyph handle as an argument, as well as a bitmap/pixmap description block and two offsets. The target map is described through a TT_Raster_Map object, which structure is defined in the reference (see "apiref.txt"). The offsets are given in the same units as the points coordinates and glyph metrics: 26.6 pixel units for a scaled glyph, and FUnits for an unscaled one. IMPORTANT TECH NOTE: ** *********************** When the glyph has been scaled and hinted, the offsets _must_ be multiples of 64 (i.e. integer pixel offsets). Otherwise, you would simply ruin the grid fitting (which usually results in ugly glyphs). examples: TT_Glyph_Metrics metrics; TT_Glyph_Outline outline; TT_Raster_Map bitmap; TT_Get_Glyph_Metrics( glyph, &metrics ); TT_Get_Glyph_Outline( glyph, &outline ); /* set up the bitmap */ ... TT_Get_Glyph_Bitmap( glyph, &bitmap, 0, 0 ); h. When you're done: o You can close any font face object with TT_Close_Face(). This call will automatically discard its child instances,glyphs and charmaps. o You can also close the engine with a single call to TT_Done_FreeType(). This will simply release _all_ objects that were previously allocated (with the exception of user-created outlines), and close all font files, as well as extensions that were inited for it. III. Extensions: 1. What is an extension? FreeType allows you to access a various number of TrueType tables, as well as to render individual glyphs. However: 1 - it doesn't perform some high-level operations, like generating a string text from many individual glyphs. 2 - it doesn't perform kerning (which can be needed by topic 1). 3 - it doesn't give access to all the defined TrueType tables, especially the optional ones. While point 1 is a feature that will never go into FreeType's core engine, which goal is to provide easy access to font data and rendering _individual_ glyphs, point 2 and 3 can be added to the engine's features through extensions. An extension is simply a small piece of code that extends the engine's abilities and APIs. It is possible to extend the engine without touching the core's source code, this is described in chapter 3 below. 2. The two kinds of extensions: There are basically two kinds of extensions, which require different implementations. a. API extensions: An API extension is a set of functions that extend the FreeType core API to give access to tables that are already loaded by the engine, but not provided for now. An example of such data can be: - the horizontal metrics table (HMTX) - the gasp table This kind of extension is made of: o an API extension header file, following the usage convention introduced here (all labels prefixed with 'TT_'), and which will be included by the clients which want to use the extension. By convention, such header names begin with 'ftx' (for FreeType eXtension). examples: ftxgasp.h, ftxhtmx.h o One or more functions used to give access to the tables that are already loaded and managed by the engine. They usually only copy pointers to the target structure given by the client application since these structures are not accessible through the 'normal' API. An API extension doesn't need to be inited before being used. b. engine extensions: It can be sometimes useful to load and manage several tables that are not considered by the core engine. These extensions need to provide additional functions to fit into FreeType's internal object management model, and are more sophisticated than API extensions. An example is given in this distribution to provide kerning support (or more technically spoken, access to the kerning tables found within the TrueType files). It is made of: o An API extension providing new interfaces to the client applications that need it. See the file "ftxkern.h". o A specific implementation, providing services to create, load and manage kerning tables as additional parts of a face object. In the case of kerning, the directory of tables is loaded when the face is opened, and tables themselves are fetched from the file on demand. This implies several 'hooks' in the core engine. See the files "ttkern.h" and "ttkern.c". These are called 'engine extensions'. o A specific extension initialisation function, namely TT_Init_Kerning_Extension, that must be called after an engine's creation, and before any face object allocation. This function will "register" the extension within the engine and make its API workable. 3. Writing your own extensions: As it was suggested earlier, writing an engine extensions is a delicate process, as the additional code must follow a certain number of design rules, presented in the FreeType developer guide. There is also an extension writer's guide in the file "extend.txt". **************************************************************** RELEASE NOTE : FreeType 1.0 doesn't provide the file "extend.txt" yet.. By writing your own extensions, it will be possible to support more advanced TrueType formats like TrueType GX or OpenType in a near future, without having to torture the engine core source at each iteration. If you encounter some difficulties when trying to create your own extension, please read the core source file carefully, and in the event that you may need changes that are not fitted to the current extension mechanism, do not hesitate to contact the authors at 'freetype-devel@lists.lrz-muenchen.de' Conclusion: This is the second version of this document, updated for the FreeType 1.0 release. The engine source code has become rather stable since the beta, and its quality compares very favorably to Windows and the Macintosh. Its internals will continue to change, though very slowly, even if the API isn't expected to grow much in a near future. There is still work to do however, as the need for a simple and effective way to deal with internationalisation in applications calls for the support of non-roman text layouts and metrics (e.g. vertical and right-to-left), or even embedded bitmaps (present in some faces for some glyphs which turn to complex to hint correctly). These features will most probably be supported through extensions, and won't need major changes and re-design of the engine. Then, the engine is really a glyph-oriented TrueType driver. Its purpose is to open and manage font files in order to load single glyphs and render them as cleanly as possible. A number of features, important to developers, like text string rendering, font mapping and underlining/stroking, to name a few, aren't provided there even though they'd be highly appreciated. We hope you success and fun using this engine. Much time has been taken to make it one of the best in its genre. Remember that it is not intended to be a complete font server or text rendering library, but a pretty solid base for these kinds of applications, as well as others. We would like you to report the bugs you find, _after_ reading the current bug report at our web page: http://www.physiol.med.tu-muenchen.de/~robert/freetype.html We thank you for your time and consideration. David Turner, Robert Wilhelm, Werner Lemberg, and all the FreeType enthusiasts... --- End of user.txt ---