parent
de01c5d9cb
commit
0fc54d0078
1 changed files with 267 additions and 0 deletions
@ -0,0 +1,267 @@ |
||||
The FreeType 2 cache sub-system explained |
||||
(c) 2000 David Turner |
||||
|
||||
----------------------------------------------- |
||||
|
||||
Introduction : |
||||
-------------- |
||||
|
||||
this document describes the caching sub-system that comes |
||||
with the FreeType library, version 2.0. Note that unlike |
||||
the rest of the library, this code is still in beta stage |
||||
and might still suffer slight changes in the future. |
||||
|
||||
Its basic design shouldn't evolve though and is explained |
||||
in this paper. |
||||
|
||||
|
||||
I. Requirements and Design Goals: |
||||
--------------------------------- |
||||
|
||||
The FT2 cache sub-system was designed to implement caching |
||||
of glyph images. However, it is extremely flexible and can |
||||
be easily extended to cache other kind of data like metrics, |
||||
character maps, coverage tables, etc.. |
||||
|
||||
|
||||
II. Base Concepts: |
||||
------------------ |
||||
|
||||
1. The cache manager object: |
||||
|
||||
at the heart of the caching sub-system is a single object |
||||
called the "cache manager". It is used to deal with FT_Face |
||||
and FT_Size objects, as well as to manager a LRU list of |
||||
abstract "cache nodes". |
||||
|
||||
a. caching FT_Face and FT_Size objects: |
||||
|
||||
each FT_Face object created by FreeType 2 can take from |
||||
a few hundred bytes to several tens of kilobytes, depending |
||||
on the original font's file format as well as its content. |
||||
|
||||
there is no easy way to compute the size of a given FT_Face |
||||
object, so it's always a good idea to assume that it is |
||||
large and to want to limit the number of live face objects |
||||
as much as possible. |
||||
|
||||
similarly, each FT_Face can have one or more FT_Size childs, |
||||
whose byte size depends heavily on the font format. |
||||
|
||||
the first purpose of the cache manager is to provide a |
||||
small cache for FT_Face and FT_Size objects. Basically, |
||||
an application can use it as follows: |
||||
|
||||
- each font face is described to the cache manager |
||||
through a typeless pointer, called a FTC_FaceID. |
||||
|
||||
the cache manager itself doesn't interpret or use |
||||
the value of FTC_FaceIDs directly. Rather, it passes |
||||
them to a user-provided function called a |
||||
"face requester". see the defintion of the |
||||
FTC_Face_Requester type in <freetype/ftcache.h> |
||||
for details.. |
||||
|
||||
the face requester is in charge of translating a given |
||||
face into into a real new FT_Face object that is |
||||
returned to the cache manager. The latter will keep |
||||
the face object alive as long as it needs to. |
||||
|
||||
the face requester is unique and must be passed |
||||
to the function named FTC_Manager_New used to |
||||
create/initialise a new cache manager. |
||||
|
||||
|
||||
- to lookup a given FT_Face, call the function |
||||
FTC_Manager_Lookup_Face as in the following code: |
||||
|
||||
FTC_Manager_Lookup_Face( manager, |
||||
face_id, |
||||
&face ); |
||||
|
||||
if the corresponding FT_Face object is kept in |
||||
the cache manager's list, it will be returned |
||||
directly. Otherwise, this function will call |
||||
the user-provided face requester to create |
||||
a new FT_Face object, add it to the manager's |
||||
list to finally return it. |
||||
|
||||
FT_Face objects are always destroyed by the cache |
||||
manager. An application that uses the cache |
||||
sub-system should never call FT_Done_Face !! |
||||
|
||||
- to lookup a given FT_Size and FT_Face, call the |
||||
function FTC_Manager_Lookup_Size, as in: |
||||
|
||||
FTC_Manager_Lookup_Size( manager, |
||||
ftc_font, |
||||
&face, |
||||
&size ); |
||||
|
||||
where "ftc_font" is a pointer to a FTC_Font descriptor |
||||
(a structure containing a FTC_FaceIDs and character |
||||
dimensions corresponding to the desired FT_Size). |
||||
|
||||
note that the function returns both a FT_Face and |
||||
a FT_Size object. You don't need to call |
||||
FTC_Manager_Lookup_Face before it !! |
||||
|
||||
also note that returned FT_Size objects are always |
||||
destroyed by the cache manager. A client application |
||||
that uses it should never call FT_Done_Size !! |
||||
|
||||
|
||||
the big advantage of using FTC_FaceIDs is that is |
||||
makes the caching sub-system completely independent |
||||
of the way font files are installed / listed / managed |
||||
in your application. In most implementations, a FTC_FaceID |
||||
is really a pointer to an application-specific structure |
||||
that describe the source font file + face index. |
||||
|
||||
|
||||
b - manage a MRU list of abstract "cache nodes": |
||||
|
||||
the second role of the cache manager is to hold and manager |
||||
a list of abstract "cache nodes". The list is always sorted |
||||
in most-recently-used order. The manager always ensure that |
||||
the total size of nodes in memory doesn't over-reach a |
||||
certain threshold, by eliminating "old" nodes when |
||||
necessary. |
||||
|
||||
the cache manager doesn't know much about the cache nodes: |
||||
|
||||
- it knows how to move them in its list |
||||
- it knows how to destroy them when they're too old |
||||
- it knows how to "size" them (i.e. compute their byte |
||||
size in memory) |
||||
|
||||
|
||||
2. Cache objects: |
||||
|
||||
the cache manager doesn't create new cache nodes however, this |
||||
is the charge of what are called "cache objects". |
||||
|
||||
Basically, each cache object is in charge of managing cache |
||||
nodes of a certain type. Its role is to: |
||||
|
||||
- provide a simple description of its cache nodes to the |
||||
manager (i.e. through a FTC_CacheNode_Class structure) |
||||
|
||||
- provide a high-level API that can be called by client |
||||
applications to lookup cache nodes of the corresponding |
||||
type. |
||||
|
||||
this function usually creates new nodes when they're not |
||||
available yet. |
||||
|
||||
- also, and even though this is completely transparent to |
||||
the applications and the cache manager, each cache object |
||||
manages "node sets", where each set contains cache nodes |
||||
usually correspond to the same font face + font size. |
||||
|
||||
|
||||
For example, the cache sub-system currently comes with two |
||||
distinct cache classes: |
||||
|
||||
- a FTC_Image_Cache, which is used to cache FT_Glyph images |
||||
(with one FT_Glyph per cache node). |
||||
|
||||
|
||||
- a FTC_SBit_Cache, which is used to cache small glyph bitmaps |
||||
("sbit" means "embedded bitmaps" in digital typography). |
||||
|
||||
|
||||
the small bitmaps glyph is useful because storing one glyph |
||||
image per cache node isn't memory efficient when the data |
||||
associated to each node is very small. Indeed, each cache |
||||
node has a minimal size of 20 bytes, which is huge when |
||||
your data is an 8x8 monochrome bitmap :-) |
||||
|
||||
Hence, a FTC_SBit_Cache is capable of storing several |
||||
contiguous sbits in a single cache node, resulting in much |
||||
higher cached glyphs / total cache size. |
||||
|
||||
an application can lookup a FT_Glyph image with a FTC_Image_Cache |
||||
by calling: |
||||
|
||||
error = FTC_Image_Cache_Lookup( image_cache, |
||||
ftc_font, |
||||
glyph_index, |
||||
&ft_glyph ); |
||||
|
||||
or a FTC_SBit (small bitmap descriptor) by calling: |
||||
|
||||
error = FTC_SBit_Cache_Lookup( sbit_cache, |
||||
ftc_font, |
||||
glyph_index, |
||||
&ftc_sbit ); |
||||
|
||||
III. Extending the cache sub-system: |
||||
|
||||
It is possible to extend the current cache sub-system by |
||||
providing your own cache class and register it in the cache |
||||
manager. That might be useful to cache other kind of data |
||||
in the sub-system, like glyph metrics (without images), |
||||
|
||||
To do it, you'll need to read the cache sub-system public |
||||
header files rather heavily :-) Fortunately, they're pretty |
||||
well commented and should guide you to your goal. |
||||
|
||||
Note that the cache sub-system already provides two "abstract |
||||
cache" classes that can be re-used by your own implementation: |
||||
|
||||
|
||||
1. The abstract "FTC_GlyphCache" class: |
||||
|
||||
this code is used to implement an abstract "glyph cache", |
||||
i.e. one that simply maps one glyph data per cache node. |
||||
|
||||
it is sub-classed by FTC_Image_Cache, whose implementation |
||||
only consists in simple code to store a FT_Glyph in each |
||||
cache node. |
||||
|
||||
you could sub-class it in your application to store glyph |
||||
images in a different format, for example. |
||||
|
||||
see the files <freetype/cache/ftcglyph.h> and |
||||
"src/cache/ftcglyph.h" for details. |
||||
|
||||
|
||||
2. The abstract "FTC_ChunkCache" class: |
||||
|
||||
this code is used to implement an abstract "glyph chunk cache". |
||||
it's very similar to a FTC_GlyphCache, except that it is capable |
||||
of storing several glyph-specific elements per cache node. |
||||
|
||||
it is sub-classed by FTC_SBit_Cache, whose implementation |
||||
only consists in code to store a FTC_SBitRec record in each |
||||
node element. |
||||
|
||||
you could sub-class it in your application to store small |
||||
glyph data, like metrics, glyph names, wathever. |
||||
|
||||
see the files <freetype/cache/ftcchunk.h> and |
||||
"src/cache/ftcchunk.h" for details.. |
||||
|
||||
|
||||
Note that the two abstract caches are rather complex because |
||||
they use "glyph sets". Each glyph set corresponds to a single |
||||
font face + font size combination. both caches are also |
||||
glyph-specific, though it is perfectly possible to use |
||||
broader selection criterion, here are a few examples: |
||||
|
||||
- caching language coverage maps corresponding to |
||||
a given font face + language combination |
||||
|
||||
- caching charmaps, layout tables, and other global |
||||
data.. |
||||
|
||||
- caching (font_face + font_size) specific "latin1" |
||||
ascender + descender |
||||
|
||||
|
||||
as you can see, a lot is possible with this design :-) |
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in new issue