summaryrefslogtreecommitdiff
path: root/Build/source/libs/freetype/freetype-1.5/docs/porting.txt
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/libs/freetype/freetype-1.5/docs/porting.txt')
-rw-r--r--Build/source/libs/freetype/freetype-1.5/docs/porting.txt1078
1 files changed, 1078 insertions, 0 deletions
diff --git a/Build/source/libs/freetype/freetype-1.5/docs/porting.txt b/Build/source/libs/freetype/freetype-1.5/docs/porting.txt
new file mode 100644
index 00000000000..f5dd737e8dc
--- /dev/null
+++ b/Build/source/libs/freetype/freetype-1.5/docs/porting.txt
@@ -0,0 +1,1078 @@
+
+
+ The FreeType Porting Guide
+
+ or
+
+ Everything you need to know to make FreeType
+ run on the weirdest system
+
+
+--------------------------------------------------------------------
+
+ Table of Contents
+
+
+ Introduction
+
+ I. General design and system modules
+
+ II. Memory component API
+
+ 1. The alloction function: TT_Alloc()
+ 2. The release function: TT_Free()
+ 3. The ALLOC() and ALLOC_ARRAY() macros
+ 4. The MEM_xxxx() macros
+
+ III. File component API
+
+ 1. Streams and their functions
+ 2. Frames and file access
+ 3. Differences in thread support levels
+
+ IV. Mutex component API
+
+ V. Summary & Advanced concepts
+
+ 1. Porting summary
+ 2. Exotic filesystems
+
+ VI. Troubleshooting
+
+ Conclusion
+
+
+--------------------------------------------------------------------
+
+Introduction
+============
+
+The FreeType engine is portable in many ways:
+
+- First, it can be compiled by any ANSI C compliant compiler, which
+ guarantees the widest possible uses.
+
+- Its default build uses a tiny fraction of the ANSI libc, mainly
+ for memory management and I/O access, which should be available on
+ most systems (i.e., malloc(), free(), fopen(), fread(), etc).
+
+- Its design is modular, and allows an implementer to remove all
+ dependencies on a particular runtime environment, to adapt the
+ engine to its specific needs. For example, it is possible to use
+ memory-mapped files on systems which support them.
+
+This document explains the engine's design, presenting the `system'
+modules that need to be changed by porters of the library, as well
+as how to do it.
+
+Note that this documentation is _very_ detailed, and you may
+DIRECTLY JUMP to SECTION V (Summary and advanced concepts) which
+gives you a QUICK STEP-BY-STEP GUIDE TO PORTING each component,
+without the need to understand all the guts of the TrueType engine.
+
+Several issues are discussed, including the use of exotic font
+storage conventions.
+
+
+--------------------------------------------------------------------
+
+
+I. General design, and system modules
+=====================================
+
+ The engine's design is intentionally highly modular. It is made
+ of several `components', each with its own specific goals. Three
+ of these play an important role with regards to portability. They
+ are:
+
+ - the memory component:
+
+ Found in the files `ttmemory.h' and `ttmemory.c'. It defines
+ several macros and a few functions used by _all_ other modules
+ to allocate, release, copy, and move memory blocks.
+
+ - the file component:
+
+ Found in the files `ttfile.h' and `ttfile.c'. It defines
+ several types and abstractions (streams, frames), that are used
+ by _all_ other modules to access font files.
+
+ - the mutex component:
+
+ This component compiles to a null object if the engine is built
+ in single-thread mode. Otherwise, for thread-safe and reentrant
+ builds, the macros and functions it defines are used by the rest
+ of the engine to protect shared variables.
+
+ NOTE:
+
+ Because the ANSI libc does not provide synchronisation
+ primitives (synchronisation isn't portable accross platforms),
+ the default implementation, found in `ttmutex.c', is made of
+ dummy functions which always return a successful error
+ condition.
+
+ You _need_ to re-define this component for your system if you
+ decide to make a thread-safe or reentrant build, even if you
+ use the ANSI libc.
+
+
+ When specializing a component, i.e., rewriting it for your
+ platform, you should respect a few conventions which are explained
+ in the following sections. Note also that the system-specific
+ implementations are usually placed in the
+ `freetype/lib/arch/<system>' directory. For example:
+
+ freetype/lib/arch/unix/ttmmap.c
+
+ A Unix-only implementation of ttfile which uses the
+ memory-mapped file API (this greatly improves the engine's
+ performance, due to the random access pattern typicals of
+ glyph data retrieval).
+
+ freetype/lib/arch/os2/os2file.c
+
+ This is an implementation of ttfile specific to OS/2, which
+ directly calls the system functions DosOpen(), DosRead(), etc.
+
+ The FreeType/2 DLL (a free TrueType font driver for OS/2) also
+ uses its own memory component which calls a special allocation
+ routine required in its runtime environment, and also provides
+ additional statistics that can be displayed by an auxiliary
+ tool while the driver is running in the system.
+
+We ask you to respect this directory convention. This really needs
+a minor Makefile change, and still having the ability to compile the
+`default' ttfile and ttmemory will help you debug your specific
+ports by easy comparisons.
+
+
+--------------------------------------------------------------------
+
+
+II. Memory component API
+========================
+
+ This section presents the macros and functions defined in
+ ttmemory.h, and how they should be implemented, if you decide to
+ rewrite the source file ttmemory.c from scratch. An easier
+ solution would be to replace the calls to malloc() and free() with
+ your own functions, though.
+
+
+1. Allocation routine : TT_Alloc()
+----------------------------------
+
+ This function is used to allocate blocks of memory, just like
+ malloc(), but defines a very different interface. Its prototype
+ is:
+
+ TT_Error TT_Alloc( long size, void** p );
+
+ [The FreeType source files use abstract data types like `Long' for
+ all internal functions and `TT_Long' for externally visible
+ structures. See tttypes.h and freetype.h, respectively.]
+
+ We can see that:
+
+ - The function returns an error code, and _not_ a pointer. The
+ reason for this is that your own implementation may perfectly
+ fail for more than one good reason. For example, it could
+ detect a corrupted heap, a memory exhaustion or an unusually
+ large block, and have a different error code for each of these
+ cases.
+
+ If a memory allocation error occurs in a FreeType function, it
+ is always taken into account (of course, for safety reasons),
+ but its code is directly sent to the caller. This means that
+ your own applications and font servers will be able to interpret
+ these errors and let you handle them appropriately.
+
+ - Its second argument is the _address_ of a typeless pointer.
+ This means the need to typecast it before calling this function.
+
+ The macro MEM_Alloc() is defined in ttmemory.h to do it for you,
+ as well as the `memory extraction' performed by the `&'
+ operator, so that you can write:
+
+ char* buffer;
+
+
+ MEM_Alloc( size, buffer );
+
+ instead of
+
+ TT_Alloc( size, (void**)&buffer );
+
+ Note that the engine _never_ uses this macro directly, but
+ ALLOC() instead (see below) in order to _always_ test the error
+ code.
+
+ *****************
+ *** IMPORTANT ***
+ *****************
+
+ - A newly allocated block should _always_ be filled with zeroes!
+ This is a _very_ strong convention used within all the engine.
+ It helps greatly to reduce code size, in general. If your
+ implementation of TT_Alloc() does not respect it, you are pretty
+ certain to build an unrunnable (at best) or (worse) instable
+ engine! Beware.
+
+
+2. Release routine: TT_Free()
+-----------------------------
+
+ This routine is naturally used to release any block created
+ through TT_Alloc(). Its prototype is:
+
+ TT_Error TT_Free( void** P );
+
+ We can see that:
+
+ - It also returns an error code. Note, however, that the error is
+ ignored in most, if not all, parts of the engine. This is
+ because freeing memory usually happens when all necessary work
+ has been finished, or when something already wrong happened.
+
+ - It takes the address of a typeless-pointer, and _not_ the
+ pointer's value itself. This is used to set the pointer's value
+ to NULL just after the block was released, which avoids dangling
+ references in objects. Of course, there is a macro defined to
+ simplify source writing. One can use FREE() like:
+
+ char* buffer;
+
+
+ MEM_Alloc( size, buffer );
+
+ .... work ....
+
+ FREE( buffer );
+
+ /* now `buffer' is set to NULL; the following line will */
+ /* seg-fault */
+
+ a = buffer[0];
+
+
+ *****************
+ *** IMPORTANT ***
+ *****************
+
+ - The function TT_Free() (and thus the macro FREE()) will accept a
+ NULL pointer successfully! This means more precisely that the
+ address of a pointer may have the value NULL; in this case it
+ will return with a successful error code (TT_Err_Ok == 0).
+
+ This convention is also _very_ strong in the engine, and
+ simplifies both code size and style. One of its primary origin
+ is the engine's object management which requires the ability to
+ release an object, be it normal or `partial', with the same
+ code.
+
+
+3. The ALLOC() and ALLOC_ARRAY() macros
+---------------------------------------
+
+ Two macros are also defined to make the FreeType source code
+ easier to read and understand. Their role is to perform an
+ allocation, while saving the error condition in an _implicit_
+ local variable called `error', and returning a boolean which is
+ set to true in case of error. Their definition is
+
+ #define ALLOC( pointer, size ) \
+ ( ( error = MEM_Alloc( pointer, size ) ) != TT_Err_Ok )
+
+ and
+
+ #define ALLOC_ARRAY( pointer, count, type ) \
+ ( ( error = MEM_Alloc( pointer, \
+ (count) * sizeof ( type ) ) ) \
+ != TT_Err_Ok )
+
+ They are always used in `if' statements, and can be chained
+ together. Here is some example code:
+
+ char* buffer1 = 0; /* temporary buffer 1 */
+ char* buffer2 = 0; /* temporary buffer 2 */
+ TT_Error error;
+
+
+ ...
+
+ if ( ALLOC_ARRAY( buffer1, n, TT_F26Dot6 ) ||
+ ALLOC_ARRAY( buffer2, n, short ) )
+ goto Fail;
+
+ ... work ...
+
+ Fail:
+ FREE( buffer2 );
+ FREE( buffer1 );
+ return error;
+
+
+ Notes:
+
+ - If an error occurs during the first allocation, execution will
+ jump immediately to the `Fail' label.
+
+ - The failure code, which releases the buffers, does not need to
+ differentiate whether the first allocation succeeded or not
+ (simply because FREE() accepts null pointers with no
+ problems).
+
+ The equivalent code, without macros, would be:
+
+ char* buffer1;
+ char* buffer2;
+ TT_Error error;
+
+
+ error = TT_Alloc( n * sizeof ( TT_F26Dot6 ),
+ (void**)&buffer1 );
+ if ( error ) goto Fail_Buffer1;
+
+ error = TT_Alloc( n * sizeof ( short ),
+ (void**)&buffer2 );
+ if ( error ) goto Fail_Buffer2;
+
+ .... work ....
+
+ Fail_Buffer2:
+ TT_Free( (void**)&buffer2 );
+
+ Fail_Buffer1:
+ TT_Free( (void**)&buffer1 );
+
+
+ Which is a lot less clear about its intents, and uses more special
+ cases.
+
+
+4. The MEM_xxxx() macros
+------------------------
+
+ Finally, three macros are defined to perform some common memory
+ block operations. Their names are rather explicative:
+
+ - MEM_Copy()
+
+ Used by the engine to copy one block of data in memory to
+ another one.
+
+ - MEM_Set()
+
+ Used to set all bytes of a block of memory to a given value.
+
+ - MEM_Move()
+
+ Well, guess what ;-)
+
+
+ These operations could have been embedded in functions like
+ TT_Mem_Copy(), TT_Mem_Set(), and TT_Mem_Move(), but a lot of
+ compilers are able to inline directly calls to such `intrinsic'
+ functions as memcpy() and memmove(). Hence, macros make sense
+ here.
+
+
+--------------------------------------------------------------------
+
+
+III. File Component API
+=======================
+
+ This section describes the file component's API, and the things
+ that are needed to port it to a specific system. Note that only a
+ fraction of the source code in `ttfile.c' needs to be rewritten
+ during a port.
+
+
+1. Streams and their functions
+------------------------------
+
+ A stream in FreeType (version 1.x) encapsulates both the
+ location/naming of a file, and its access. This is due to the
+ fact that they were originally designed to embed a simple ANSI
+ `FILE*' file pointer.
+
+ This means several things:
+
+ - A stream is created and opened via the TT_Open_Stream()
+ function. It takes, in the default build, a font pathname of
+ type `char*' that it uses when calling fopen().
+
+ - It can be released/closed via the function TT_Close_Stream().
+
+ - It embeds a `current file position', just like an ordinary file
+ descriptor. It is thus seekable, through the function
+ TT_Seek_File().
+
+ - Raw data can be extracted from a stream through TT_Read_File()
+ and TT_Read_At_File().
+
+ However, it has certain properties that differ from a libc `FILE*'
+ data type:
+
+ - Because each face object has its own stream, and because most
+ operating systems limit the number of opened system resources in
+ each process, it is more than helpful to be able to `flush' a
+ stream.
+
+ A stream is said to be flushed if the system resource it
+ contains (like a file descriptor) has been closed. However,
+ this resource is re-opened automatically when needed.
+
+ The function TT_Flush_Stream() is used to flush a stream. If a
+ stream has been flushed, it is also said to be `asleep'.
+
+ - The engine calls TT_Use_Stream() before each new stream access.
+ With it, the file component is able to awake (or `activate')
+ streams that are flushed, if needed.
+
+ - Consequently, the engine calls TT_Done_Stream() when it has
+ performed all I/O access. These two APIs (TT_Use_Stream() and
+ TT_Done_Stream()) let the file component track and manage the
+ engine's access patterns, and allows it to cache opened streams
+ more cleverly.
+
+ For example, one could implement an LRU list used to track the
+ `oldest' streams, and only activate the 10 `freshest' ones, thus
+ limiting the total number of system stream resources used by the
+ library, independently of the total number of opened faces in
+ the engine.
+
+
+2. Frames and file access
+-------------------------
+
+ In order to resolve endianess and alignment issues, the engine
+ uses the concept of `frames' to extract data from a TrueType
+ table.
+
+ - A frame is simply a sequence of successive bytes, taken from a
+ stream from its current position. A frame can only exist within
+ a stream.
+
+ - The function TT_Access_Frame() (ideally) reads its data and
+ places it into an intermediate buffer, which is later used for
+ parsing. This function also checks that the whole frame fits
+ into the original file. For example, it will return an error if
+ detecting `over-reads' in the file (which can happen if the font
+ file is broken).
+
+ Note that the intermediate buffer disappears in the case of
+ memory-mapped files.
+
+ - Each frame has an internal cursor, which is set to its buffer's
+ base by the previous function. Note, however, that it differs
+ from the stream's current position, which has been advanced once
+ TT_Acess_Frame() is completed.
+
+ - Data is extracted from the frame through calls to functions of
+ the form:
+
+ TT_Get_<IntegerType>();
+
+ where <IntegerType> can be any of: Byte (unsigned char), Char
+ (signed char), Short, UShort, Long, or ULong.
+
+ Each function returns the integer below the current frame
+ cursor, and advances the latter in the buffer.
+
+ - Finally, when the frame access ends, the engine calls the
+ TT_Forget_Frame() function, which will release the intermediate
+ buffer and set the cursor to NULL.
+
+ Here is a typical frame read sequence:
+
+ /* first - read the next 12-bytes frame in memory */
+ error = TT_Access_Frame( 12 );
+ if ( error )
+ return error;
+
+ /* now, extract all data */
+ object->field1 = TT_Get_Short();
+ object->field2 = TT_Get_Long();
+ object->field3 = TT_Get_Char();
+ object->filed4 = TT_Get_Long();
+ object->field5 = TT_Get_Byte();
+
+ /* done - now release the frame */
+ TT_Forget_Frame();
+
+ /* now perform some checks */
+ if ( object->field1 == -1 )
+ return Error_1;
+
+ if ( object->field2 > object->field4 )
+ return Error_2;
+
+
+ *****************
+ *** IMPORTANT ***
+ *****************
+
+ A few things need to be noticed by porters when they implement
+ frame loading (i.e. the TT_Access_Frame() function):
+
+ - The functions that need to be ported are TT_Access_Frame() and
+ TT_Forget_Frame(). The TT_Get_XXXX() functions should be left
+ as is.
+
+ - A frame has a state, and must _always_ be released through
+ TT_Forget_Frame() in case of an error. This means that the
+ engine will _never_ use code like the following:
+
+ error = TT_Access_Frame( 12 );
+ if ( error )
+ goto Fail;
+
+ object->field1 = TT_Get_Short();
+
+ /* now check error and return immediately -- */
+ /* WITHOUT RELEASING FRAME! ERROR! */
+ if ( object->field1 == -1 )
+ goto Fail;
+
+ object->field2 = TT_Get_Long();
+ object->field3 = TT_Get_Char();
+ object->field4 = TT_Get_Long();
+
+ /* check for error, return immediately -- */
+ /* WITHOUT RELEASING FRAME! ERROR! */
+ if ( object->field2 > object->field4 )
+ goto Fail;
+
+ /* now release frame */
+ TT_Forget_Frame();
+
+ This means more simply that EACH successful call to
+ TT_Access_Frame() will ALWAYS be followed by a call to
+ TT_Forget_Frame()!
+
+ - As a consequence of the first rule, and also in order to keep
+ things simple, NESTING FRAME ACCESSES are not allowed. For
+ example, the following code will produce an error:
+
+ /* First frame access */
+ error = TT_Access_Frame( 8 );
+ if ( error )
+ goto Fail;
+
+ /* read a file offset */
+ offset = TT_Get_Long();
+
+ /* seek and load another frame */
+ error = TT_File_Seek( stream, offset );
+ if ( error )
+ goto Fail;
+
+ error = TT_Access_Frame( 4 );
+ /* The function TT_Access_Frame detects nested calls */
+ /* and ALWAYS returns TT_Err_Nested_Frame_Access! */
+ if ( error )
+ goto Fail;
+
+ data1 = TT_Get_Long();
+
+ /* release second frame */
+ TT_Forget_Frame();
+
+ /* read next integer from the first frame */
+ data2 = TT_Get_Long();
+
+ /* release first frame */
+ TT_Forget_Frame();
+
+ This simplifies the work that needs to be done wen porting the
+ TT_Access_Frame() and TT_Forget_Frame() functions.
+
+
+3. Differences in thread support levels
+---------------------------------------
+
+ The FreeType library can be built to three distinct thread-support
+ levels. This section will present each other, and show how this
+ translates within the ttfile.c source code.
+
+ a. Levels
+
+ The three levels are
+
+ - single thread
+
+ No synchronization primitive is used to protect the data in
+ the file component. Hence, there is only one `current' stream
+ at any one time. Note, however, that in some cases, more than
+ one stream may be `active' (or `awakened'); e.g., when using
+ memory-mapped files, each opened face needs a valid mapping
+ before it can be used/parsed by the engine.
+
+ - thread-safe
+
+ The thread safe mode synchronizes concurrent accesses to the
+ renderer's component through mutexes. For the file component,
+ this means a single mutex which is `locked' by a call to
+ TT_Use_Stream(), and `released' by TT_Done_Stream().
+
+ As a consequence, there is only one possible `current' stream
+ when the engine reads files, like in the single thread case.
+
+ - re-entrant
+
+ In this mode, concurrent accesses are possible on many
+ components, including ttfile. This means that each
+ TT_Use_Stream() must _really_ create its own system/ANSI
+ stream for a single file, and that the file component _cannot_
+ have any state (only stream objects have!), like a `current
+ stream' and `current frame'.
+
+ This mode must use mutexes to protect all shared variables and
+ lists from concurrent changes/reads. The only component which
+ is still serialized in this mode is the scan-line converter
+ (a.k.a. ttraster).
+
+ b. Implementation differences
+
+ Because the TrueType engine serves more as a `font format
+ driver' than a general and high-level text-rendering library, it
+ has been decided to keep its code as simple and compact as
+ possible.
+
+ This implies some implementation differences between the three
+ thread modes, which are briefly explained below:
+
+ - Single-thread and thread-safe mode can have a state, which
+ means for ttfile.c, a `current stream' and `current frame'.
+
+ - In the reentrant mode, the `state' must be stored in a
+ thread-local place, which means the stack (or more simply
+ local function variables).
+
+ What follows is that some `ttfile' functions will not take the
+ same number of arguments depending on the thread-support mode.
+ Let us take the example of frame access and parsing:
+
+ In single-thread and thread-safe mode, the current frame is
+ automatically set by the TT_Access_Frame() function, which only
+ takes a `size' argument to determine the run of bytes to extract
+ from the _current_stream_ within ttfile's state.
+
+ Moreover, the TT_Get_XXXX() functions extract data from the
+ current frame, and need no arguments. A simple frame access
+ then looks like this:
+
+ /* read the next 12-bytes frame from the _current_stream_ */
+ error = TT_Access_Frame( 12 );
+ if ( error )
+ return error;
+
+ /* now, extract all data from the _current_frame_ */
+ object->field1 = TT_Get_Short();
+ object->field2 = TT_Get_Long();
+ object->field3 = TT_Get_Char();
+ object->filed4 = TT_Get_Long();
+ object->field5 = TT_Get_Byte();
+
+ /* done - now release the current frame */
+ TT_Forget_Frame();
+
+ In reentrant mode, things are a bit different. The current
+ stream and current frame must be passed as parameters, and the
+ code looks like this (notice the new function parameters!):
+
+
+ TT_Frame frame; /* define a local variable to handle */
+ /* the current frame */
+
+ .... /* we suppose we already have a stream variable */
+ .... /* named `stream' (how surprising ;-) */
+
+ /* read the next 12-bytes frame from a given stream */
+ error = TT_Access_Frame( stream, 12, &frame );
+ if ( error )
+ return error;
+
+ /* now, extract all data from the given frame */
+ object->field1 = TT_Get_Short( frame );
+ object->field2 = TT_Get_Long ( frame );
+ object->field3 = TT_Get_Char ( frame );
+ object->filed4 = TT_Get_Long ( frame );
+ object->field5 = TT_Get_Byte ( frame );
+
+ /* done - now release the current frame */
+ TT_Forget_Frame( frame );
+
+
+ The differences between these two schemes are striking. Though
+ an `easy' solution would have been to only write the engine in
+ reentrant-mode, it would have resulted in larger and slightly
+ slower code, as well as the source a bit more obscure about its
+ intents and thus harder to maintain. Also, the reentrant
+ version is only needed in rare cases and environments, and it
+ was not thought as a good idea to complexify _source_ code in
+ order to comply with rare uses.
+
+ The problem is solved within the engine by the use of a set of
+ carefully selected macros, which help generate both versions
+ from a _single_ source file.
+
+ Moreover, as the macros imitate the non-reentrant syntax (i.e.,
+ the use of the `stream' and `frame' parameters is implicit to
+ the macros), the source is kept clear and easy to understand,
+ even if compiled in re-entrant mode.
+
+ The code looks then like the following in the engine:
+
+ /* read the next 12-bytes frame from the current stream */
+ /* assignment of the error code in the local `error' */
+ /* variable is also implicit to the ACCESS_Frame macro, */
+ /* and its result is always a boolean (no ANSI warnings) */
+
+ if ( ACCESS_Frame( 12 ) )
+ goto Fail;
+
+ /* Now, extract all data from the current frame. */
+ /* The macros GET_xxxxx use an implicit local `frame' */
+ /* variable in reentrant mode. */
+
+ object->field1 = GET_Short();
+ object->field2 = GET_Long();
+ object->field3 = GET_Char();
+ object->filed4 = GET_Long();
+ object->field5 = GET_Byte();
+
+ /* done - now release the current frame */
+
+ FORGET_Frame();
+
+ Another advantage of the above code is its `expressiveness' in
+ the sense that it really describes what is happening during the
+ frame load, hiding the boring but necessary details required by
+ error checking and reentrancy. And if the error checks are
+ within the macros, we are sure we won't forget them because they
+ are `too boring to code' (one of the reason why `exceptions'
+ caught so quickly in C++ and Java).
+
+ c. Consequences on ttfile
+
+ Of course, the macros only hide real differences in
+ implementation which must be reflected in ttfile.h and ttfile.c.
+ In order to ease this task, some other macros are used, which
+ use is reserved for these two files. There are:
+
+ STREAM_ARG
+ STREAM_ARGS
+ FRAME_ARG
+ FRAME_ARGS in ttfile.h
+
+ CUR_Stream
+ STREAM_VAR
+ STREAM_VARS
+ FRAME_VAR
+ FRAME_VARS in ttfile.c
+
+ All of these macros (with the exception of CUR_Stream) default
+ to nothing (i.e. a void macro) in single-thread and re-entrant
+ mode, which only differ from the use of a mutex lock and release
+ in the functions TT_Use_Stream() and TT_Done_Stream().
+ CUR_Stream defaults to the file component's current stream,
+ found in its internal state (as you can guess, it designates the
+ `current stream').
+
+ On the opposite, the macros are used to define additional
+ function parameters (if a function is called) and arguments (if
+ calling in a function). For example, the following (fictional)
+ code:
+
+ /* return the size of a given stream */
+ long Stream_Size( STREAM_ARG )
+ {
+ return CUR_Stream.size;
+ }
+
+ expands to:
+
+ long Stream_Size()
+ {
+ return file_component.current_stream.size;
+ }
+
+ in non-reentrant mode, and to:
+
+ long Stream_Size( TT_Stream stream )
+ {
+ return (*stream).size;
+ }
+
+ otherwise.
+
+ Thus, we can see the following reentrant expansions:
+
+ STREAM_ARG --> TT_Stream stream
+ STREAM_ARGS --> TT_Stream stream, (note the comma)
+
+ FRAME_ARG --> TT_Frame frame
+ FRAME_ARGS --> TT_Frame frame, (note the comma)
+
+ STREAM_VAR --> stream
+ STREAM_VARS --> stream,
+
+ FRAME_VAR --> frame
+ FRAME_VARS --> frame,
+
+ They follow these simple rules:
+
+ - An XXXX_ARG is used to define a single optional parameter in
+ a function _prototype_. The parameter is said to be single
+ if it is not followed by anything, e.g.
+
+ long Stream_Size( STREAM_ARG )
+
+ - An XXXX_ARGS is the same, followed by a comma, in order to
+ place other (non-optional) parameters behind, e.g.
+
+ TT_Error Stream_Seek( STREAM_ARGS long pos )
+
+ - An XXXX_VAR is used, _only_ within ttfile.c, to _call_ a
+ function having an XXXX_ARG or XXXX_ARGS in its prototype
+ resp. declaration.
+
+ long Stream_Left( STREAM_ARG )
+ {
+ return ( Stream_Size( STREAM_VAR ) -
+ Stream_Pos( STREAM_VAR ) );
+ }
+
+ - An XXXX_VARS is the same, but can be followed by non-optional
+ parameters.
+
+ The macros allow you to write some code independently of the
+ thread level within ttfile.c.
+
+ *****************
+ *** IMPORTANT ***
+ *****************
+
+ In general, porters should not be concerned about the use of
+ these macros. One easy way to port is to take the ANSI code in
+ ttfile.c and modify only the parts that really access the system
+ (like fopen(), fread(), fseek(), etc).
+
+ These details are explained here to make you understand how the
+ code works, in case you are interested in more elaborate ports.
+
+
+--------------------------------------------------------------------
+
+
+IV. Mutex Component API
+=======================
+
+ As said before, the default library source code uses the ANSI libc
+ only, and the source code in ttmutex.c only contains dummy
+ functions which return a successful error condition in all cases.
+
+ You thus NEED to specialize it in order to successfully use a
+ thread-safe or reentrant build. Here is explained what is really
+ important:
+
+
+1. The TMutex type
+------------------
+
+ The engine uses the `TMutex' type defined in ttmutex.h to handle
+ mutexes. It is only a typedef of a `void*' and should be kept
+ that way for the fastest porting.
+
+ Your job will most probably be to store a system mutex/semaphore
+ handle or pointer in it.
+
+
+2. The mutex macros and functions
+---------------------------------
+
+ The interface file ttmutex.h defines several macros that are used
+ within the engine to protect all shared variables (like lists)
+ from concurrent accesses. All macros default to `void' (nothing)
+ in single thread mode, and to calls to the TT_Mutex_XXXX()
+ functions in multi-threaded modes.
+
+ These functions are:
+
+ o TT_Mutex_Create()
+
+ Takes a TMutex address as an argument. It should place a NULL
+ pointer in this output variable in case of failure.
+
+ o TT_Mutex_Lock()
+
+ It also takes the address of a TMutex as an argument. Used to
+ lock the mutex/semaphore, of course.
+
+ o TT_Mutex_Release()
+
+ Guess what ;-) Same interface.
+
+ o TT_Mutex_Delete()
+
+ Destroys a mutex/semaphore.
+
+
+3. Redefining the TMutex type
+-----------------------------
+
+ You can also get rid of the TT_Mutex_xxxx() functions if you want
+ to use your system's synchronization API. This can be done in two
+ simple steps:
+
+ a. Redefine the TMutex type to suit your system's handle types.
+
+ b. Redefine the MUTEX_xxxx() macros in order to call directly your
+ API in the case of multi-threaded builds.
+
+ Both methods (specializing the TT_Mutex_xxx() functions or
+ redefining the macros) are possible.
+
+
+--------------------------------------------------------------------------
+
+
+V. Summary and Advanced Concepts
+================================
+
+1. Quick step-by-step guide to porting the system components
+------------------------------------------------------------
+
+ a. Port the memory component
+
+ o Look at the `ttmemory.h' file and change the macros
+ MEM_Copy(), MEM_Move(), and MEM_Set() to reflect your system's
+ API providing the equivalent functionality. The reason that
+ macros instead of functions are used there is that many
+ compilers are able to inline directly these functions within
+ your code.
+
+ o Look at the `ttmemory.c' file. Replace the single malloc()
+ call with your own allocation routine, and the single free()
+ with your own release routine. If your allocator uses more
+ sophisticated functions, you will probably have to rewrite
+ more parts of this file. See section I above.
+
+ b. Port the mutex component
+
+ o Look at the file `ttmutex.c' and specialize each routine to
+ have it use your system's synchronization API.
+
+ o For a more advanced port, you can also directly redefine the
+ definition of the TMutex type in ttmutex.h, as well as the
+ macro definitions (like MUTEX_Create(), MUTEX_Lock(), etc.) to
+ use directly your system's API. The TT_Mutex_xxxx() will not
+ be necessary then.
+
+ c. Port the file component
+
+ o For a quick port, look at the following functions and replace
+ the ANSI libc calls (like fopen(), fclose(), fread(), etc.):
+
+ Stream_Activate(), Stream_Deactivate(), TT_Open_Stream(),
+ TT_Done_Stream(), TT_Seek_File(), TT_Skip_File(),
+ TT_Read_File(), TT_File_Pos()
+
+ o If you plan to use memory-mapped files, you can have a look at
+ the Unix file component found in
+ `freetype/lib/arch/unix/ttmmap.c'. It should give you an
+ indication of what to do.
+
+
+2. Exotic file systems and font resources
+-----------------------------------------
+
+ a. Other file naming conventions
+
+ The high-level library uses the `TT_Text*' type to define the
+ type of characters used for a font file's pathname. By default,
+ it equals to the `char*' type, which allow you to open a face
+ object with the following call:
+
+ error = TT_Open_Face( engine, "c:\fonts\times.ttf", &face );
+
+ The implementation of TT_Open_Face() passes directly the
+ pathname pointer to the internal TT_Open_Stream() function,
+ located in the file component, which really opens the file.
+
+ Some filesystems use different naming conventions, like UTF-16
+ code, where each character is coded in 16 bits. In order to
+ help them to use FreeType, all you need to do is the following:
+
+ - Define the macro HAVE_TT_TEXT.
+
+ - Define the type `TT_Text' to the character type you need, like
+ 'wchar_t' for Unicode.
+
+ Note that this should apply when compiling the FreeType library,
+ as well as WHEN INCLUDING THE FILE `freetype.h' IN YOUR
+ APPLICATIONS.
+
+ If the configuration macro HAVE_TT_TEXT is not defined, the file
+ `freetype.h' defines TT_Text as `char*'. You can read its
+ source code to see it more explicitly (look at the very first
+ lines of the code).
+
+ You can also use TT_Text as a pointer to more specific files,
+ like a simple memory address when the font is located in ROM,
+ etc.
+
+ Just synchronize the definition of TT_Text with the
+ implementation in ttfile.c!
+
+ b. Font Resources
+
+ FreeType 2.0 will feature many architectural changes that will
+ help make porting easier, especially with regards of the file
+ component.
+
+ To do this, it will separate the concepts of a `font resource',
+ i.e. a file seen as a storage, from a `font stream', i.e. a
+ file seen as a stream of data. Only the resource related code
+ will be visible to porters, and it will be much easier to port
+ (for example, nearly all thread-support levels issues will be
+ treated internally in the rest of the engine, and will be
+ invisible to the resource component).
+
+ We are sorry for the current design and state, but TT_Stream
+ started as a simple encapsulation of an ANSI FILE* variable,
+ before font-specific access patterns made them become what they
+ now are.
+
+ FreeType 2.0 will be a good reason to re-design I/O access more
+ clearly, and fortunately with more power and flexibility (like
+ using easily files of different type, ROM-based, memory-mapped,
+ disk-based, in a single engine).
+
+ However, all of this does not mean than the current design
+ does not work. It does, so do not hesitate to use it :-)
+
+
+--------------------------------------------------------------------
+
+
+VI. Troubleshooting
+===================
+
+ To be written.
+
+
+--------------------------------------------------------------------
+
+
+Conclusion
+==========
+
+ To be written.
+
+
+--- end of porting.txt ---