Joomla TemplatesWeb HostingFree Joomla Templates
Home Blogs FreeType 2 Caching Sub-System

FreeType 2 Caching Sub-System

Recently I had a chance to use FreeType 2 caching sub-system. Now I am going to share that experience and show you how can we utilize FreeType 2 caching sub-system.

Before I begin let me tell you that I am going to explain only about the caching glyph rendering, for any further information please check http://freetype.sourceforge.net/freetype2/docs/reference/ft2-cache_subsystem.html.

In any text/font rendering engine that uses FreeType 2, the following are the major steps involved to render a text/string

    * Load corresponding face
    * Set the required size
    * For each character in text/string
        * Find corresponding glyph index for this character
        * Render the glyph into bitmap
        * Render the bitmap into the canvas considering font metrics, alignment and etc

of all above one of time consuming task in rendering a text is rendering the glyph into bitmap. If the glyph itself is a bitmap then probably it will take less time comparing to outlined glyph. But still it has scale the bitmap if there is no corresponding bitmap for required size. So still rendering a glyph into bitmap is a length task.

Usually the rendering engine will have its own caching system to hold the rendered bitmap. So next time when we want to render same character we don't have to render glyph into bitmap again. This really saves lot of time.

But now with the help of the caching sub-system, we can not only cache the rendered bitmap but also other time consuming tasks like finding the glyph index for given character and etc.

FTC_Manager

This is the main component in the caching sub-system that is responsible for managing all kind of caches. We have to create a FTC_Manager before doing anything with cache sub-system. The function for creating a new FTC_Manager is

FTC_Manager_New(FT_Library library, FT_UInt max_faces,
                FT_UInt max_sizes, FT_ULong max_bytes,
                FTC_Face_Requester requester, FT_Pointer req_data,
                FTC_Manager *amanager);

here "max_faces", "max_sizes" determines the max no. of faces and sizes to cache. The "max_bytes" is the max amount of memory that can be used for caching. The "requester" and "req_data" is callback mechanism for converting face id into face. When we use the caching functions we don't pass FT_Face directly, instead we pass a face id which will be mapped into corresponding FT_Face by this callback function. The face id is typedef-ed as FT_Pointer, so you can use any integer or pointer value as face id. If you are going to use only one face then you can simply return the FT_Face for any face id. If you are going to use more than one faces then probably you can pass the filename via "req_data" then load and return FT_Face inside "requester" callback. Note, the "requester" callback function will be called only once for the first lookup of object to be cached(Face, Size, CMap, Image, SBit). When the "requester" callback returns a FT_Face for given face id the FTC_Manager stores the pair for future lookups. So don't expect the callback to be called for every lookup.

Once we done with caching we can call FTC_Manager_Done which will free the memory used for caching.

FTC_Node

All objects(Face, Size, CMap, SBit and Image) in caching sub-system associated with FTC_Node. FTC_Manager manipulates all type of objects in the form of FTC_Node and each FTC_Node is reference counted. We have to manually de-reference(FTC_Node_Unref) the node when we no longer use it. All the caching lookup functions accept address of a FTC_Node pointer, if we provide a one then the associated FTC_Node of the lookup result will be returned in that pointer variable. The returned FTC_Node will have reference count incremented by one. So its our responsibility to de-referencing the FTC_Node when we no longer need it. We can also pass NULL as the address of FTC_Node pointer if we don't want to manually manage the FTC_Node, in that case the lookup result which we get will be freed in the next lookup.

FTC_SBitCache

A rendered glyph can be cached using FTC_SBitCache(SBit stands for Small Bitmap). First we need to create the SBitCache using FTC_SBitCacheNew, then use the returned FTC_SBitCache for any SBit lookup. The create FTC_SBitCache is valid as long as the corresponding FTC_Manager is alive. The FTC_SBitCache will be destroyed when we call FTC_Manager_Done.

A SBit lookup can be done using the below function

FTC_SBitCache_Lookup(FTC_SBitCache cache, FTC_ImageType type,
                     FT_UInt gindex, FTC_SBit *sbit,
                     FTC_Node *anode);

here the parameter "type" holds the face id, width, height and rendering flags(i.e. FT_LOAD_RENDER). "gindex" is the glyph index we want to render as a bitmap and the resultant FTC_SBit is stored in "sbit". A FTC_SBit holds all the necessary information to paint the bitmap on a surface/canvas. The "buffer" field of FTC_SBit nothing but the "buffer" field of FT_Bitmap which holds the raw bitmap data.

Example

The following code snippet shows the typical usage of FreeType 2 caching sub-system. I didn't do any error handling to make the code readable, but don't do that in your real code.

FT_Error FtcFaceRequester(FTC_FaceID faceID, FT_Library lib,
                          FT_Pointer reqData, FT_Face *face);

int main(int argc, char **argv)
{
    FT_Library lib;
    FTC_Manager ftcManager;
    FTC_SBitCache ftcSBitCache;
    FTC_SBit ftcSBit;
    int ret;

    ret = FT_Init_FreeType(&lib);
    assert(ret == 0);

    ret = FTC_Manager_New(lib, 1, 1, 1024 * 1024,
                          ftcFaceRequester,
                          fontFilename, &ftcManager);
    assert(ret == 0);
    
    ret = FTC_CMapCache_New(ftcManager, &ftcCMapCache);
    assert(ret == 0);
    
    ret = FTC_SBitCache_New(ftcManager, &ftcSBitCache);
    assert(ret == 0);

    ftcImageType.face_id = 0;
    ftcImageType.width = 16;
    ftcImageType.height = 16;
    ftcImageType.flags = FT_LOAD_DEFAULT | FT_LOAD_RENDER;

    glyphIndex = FTC_CMapCache_Lookup(ftcCMapCache, 0, 0, 'a');
    assert(glyphIndex > 0);
    ret = FTC_SBitCache_Lookup(ftcSBitCache, &ftcImageType,
                               glyphIndex, &ftcSBit, &ftcNode);
    assert(ret == 0);

    /* render the glyph */
    
    FTC_Node_Unref(ftcNode, ftcManager);
    FTC_Manager_Done(ftcManager);
}

FT_Error FtcFaceRequester(FTC_FaceID faceID, FT_Library lib,
                          FT_Pointer reqData, FT_Face *face)
{
    int ret = FT_New_Face(lib, (char *)reqData, 0, face);
    assert(ret == 0);
    return 0;
}

Comments

Name *
Email (For verification & Replies)
URL
Code   
ChronoComments by Joomla Professional Solutions
Submit Comment

Last Updated (Saturday, 04 July 2009 15:03)