adding cache manager documentation (draft)
This commit is contained in:
parent
de01c5d9cb
commit
0fc54d0078
267
docs/cache/cache.txt
vendored
Normal file
267
docs/cache/cache.txt
vendored
Normal file
@ -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
Block a user