diff options
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.txt | 1078 |
1 files changed, 0 insertions, 1078 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 deleted file mode 100644 index f5dd737e8dc..00000000000 --- a/Build/source/libs/freetype/freetype-1.5/docs/porting.txt +++ /dev/null @@ -1,1078 +0,0 @@ - - - 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 --- |