TTCACHE.C 、、、、、、、、、、、、、、、、、、、、、、、、、、、、
/*******************************************************************
*
* ttcache.c 1.1
*
* Generic object cache
*
* Copyright 1996-1999 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used
* modified and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
* Changes between 1.1 and 1.0:
*
* - introduced the refresher and finalizer in the cache class
* definition/implementation.
*
******************************************************************/
#include "ttengine.h"
#include "ttmemory.h"
#include "ttcache.h"
#include "ttobjs.h"
#include "ttdebug.h"
/* required by the tracing mode */
#undef TT_COMPONENT
#define TT_COMPONENT trace_cache
#define ZERO_List( list ) list = NULL
/* The macro FREE_Elements aliases the current engine instance's */
/* free list_elements recycle list. */
#define FREE_Elements ( engine->list_free_elements )
/* Redefinition of LOCK and UNLOCK macros for New_Element and Done_Element */
/* Note: The macros are redefined below for the cache functions */
#undef LOCK
#define LOCK() MUTEX_Lock ( engine->lock )
#undef UNLOCK
#define UNLOCK() MUTEX_Release( engine->lock )
/*******************************************************************
*
* Function : Element_New
*
* Description : Gets a new (either fresh or recycled) list
* element. The element is unlisted.
*
* Input : None
*
* Output : List element address. NULL if out of memory.
*
******************************************************************/
static
PList_Element Element_New( PEngine_Instance engine )
{
PList_Element element;
LOCK();
if ( FREE_Elements )
{
element = (PList_Element)FREE_Elements;
FREE_Elements = element->next;
}
else
{
if ( !MEM_Alloc( element, sizeof ( TList_Element ) ) )
{
element->next = NULL;
element->data = NULL;
}
}
/* Note: in case of failure, Alloc sets the pointer to NULL */
UNLOCK();
return element;
}
/*******************************************************************
*
* Function : Element_Done
*
* Description : Recycles an unlinked list element.
*
* Input : The list element to recycle. It _must_ be unlisted.
*
* Output : none.
*
* Note : This function doesn't check the element.
*
******************************************************************/
static
void Element_Done( PEngine_Instance engine,
PList_Element element )
{
LOCK();
/* Simply add the list element to the recycle list */
element->next = (PList_Element)FREE_Elements;
FREE_Elements = element;
UNLOCK();
}
/* Redefinition of LOCK and UNLOCK macros for the cache functions */
/* Note: The macros are defined above for the list element functions */
#undef LOCK
#define LOCK() MUTEX_Lock( *cache->lock )
#undef UNLOCK
#define UNLOCK() MUTEX_Release( *cache->lock )
/*******************************************************************
*
* Function : Cache_Create
*
* Description : Creates a new cache that will be used to list
* and recycle several objects of the same class.
*
* Input : clazz a pointer to the cache's class. This is
* a simple structure that describes the
* the cache's object types and recycling
* limits.
*
* cache address of cache to create
*
* lock address of the mutex to use for this
* cache. The mutex will be used to protect
* the cache's lists. Use NULL for unprotected
* cache.
*
* Output : Error code.
*
******************************************************************/
LOCAL_FUNC
TT_Error Cache_Create( PEngine_Instance engine,
PCache_Class clazz,
TCache* cache,
TMutex* lock )
{
cache->engine = engine;
cache->clazz = clazz;
cache->lock = lock;
cache->idle_count = 0;
ZERO_List( cache->active );
ZERO_List( cache->idle );
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : Cache_Destroy
*
* Description : Destroys a cache and all its idle and active
* objects. This will call each object's destructor
* before freeing it.
*
* Input : cache address of cache to destroy
*
* Output : error code.
*
* Note: This function is not MT-Safe, as we assume that a client
* isn't stupid enough to use an object while destroying it.
*
******************************************************************/
LOCAL_FUNC
TT_Error Cache_Destroy( TCache* cache )
{
PDestructor destroy;
PList_Element current;
PList_Element next;
/* now destroy all active and idle listed objects */
/* get the destructor function */
destroy = cache->clazz->done;
/* destroy all elements in active list */
current = cache->active;
while ( current )
{
next = current->next;
destroy( current->data );
FREE( current->data );
Element_Done( cache->engine, current );
current = next;
}
ZERO_List(cache->active);
/* destroy all elements in idle list */
current = cache->idle;
while ( current )
{
next = current->next;
destroy( current->data );
FREE( current->data );
Element_Done( cache->engine, current );
current = next;
}
ZERO_List(cache->idle);
cache->clazz = NULL;
cache->idle_count = 0;
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : Cache_New
*
* Description : Extracts a new object from a cache. This will
* try to recycle an idle object, if any is found.
* Otherwise, a new object will be allocated and
* built (by calling its constructor).
*
* Input : cache address of cache to use
* new_object address of target pointer to the 'new'
* object
* parent_object this pointer is passed to a new object
* constructor (unused if object is
* recycled)
*
* Output : Error code.
*
* Notes: This function is thread-safe, each cache list is protected
* through the cache's mutex, if there is one...
*
* *new_object will be set to NULL in case of failure.
*
******************************************************************/
LOCAL_FUNC
TT_Error Cache_New( TCache* cache,
void** new_object,
void* parent_object )
{
TT_Error error;
PList_Element current;
PConstructor build;
PRefresher reset;
void* object;
LOCK();
current = cache->idle;
if ( current )
{
cache->idle = current->next;
cache->idle_count--;
}
UNLOCK();
if ( current )
{
object = current->data;
reset = cache->clazz->reset;
if ( reset )
{
error = reset( object, parent_object );
if ( error )
{
LOCK();
current->next = cache->idle;
cache->idle = current;
cache->idle_count++;
UNLOCK();
goto Exit;
}
}
}
else
{
/* if no object was found in the cache, create a new one */
build = cache->clazz->init;
if ( MEM_Alloc( object, cache->clazz->object_size ) )
goto Memory_Fail;
current = Element_New( cache->engine );
if ( !current )
goto Memory_Fail;
current->data = object;
error = build( object, parent_object );
if ( error )
{
Element_Done( cache->engine, current );
goto Fail;
}
}
LOCK();
current->next = cache->active;
cache->active = current;
UNLOCK();
*new_object = current->data;
return TT_Err_Ok;
Exit:
*new_object = NULL;
return error;
Memory_Fail:
error = TT_Err_Out_Of_Memory;
Fail:
FREE( object );
goto Exit;
}
/*******************************************************************
*
* Function : Cache_Done
*
* Description : Releases an object to the cache. This will either
* recycle or destroy the object, based on the cache's
* class and state.
*
* Input : cache the cache to use
* data the object to recycle/discard
*
* Output : error code.
*
* Notes : The object's destructor is called only when
* the objectwill be effectively destroyed by this
* function. This will not happen during recycling.
*
******************************************************************/
LOCAL_FUNC
TT_Error Cache_Done( TCache* cache, void* data )
{
TT_Error error;
PList_Element element;
PList_Element prev;
PFinalizer finalize;
Long limit;
Bool destroy;
/* Look for object in active list */
LOCK();
element = cache->active;
prev = NULL;
while ( element )
{
if ( element->data == data )
{
if ( prev )
prev->next = element->next;
else
cache->active = element->next;
goto Suite;
}
prev = element;
element = element->next;
}
UNLOCK();
return TT_Err_Unlisted_Object;
Suite:
limit = cache->clazz->idle_limit;
destroy = (cache->idle_count >= limit);
UNLOCK();
if ( destroy )
{
/* destroy the object when the cache is full */
cache->clazz->done( element->data );
FREE( element->data );
Element_Done( cache->engine, element );
}
else
{
/* Finalize the object before adding it to the */
/* idle list. Return the error if any is found. */
finalize = cache->clazz->finalize;
if ( finalize )
{
error = finalize( element->data );
if ( error )
goto Exit;
/* Note: a failure at finalize time is a severe bug in */
/* the engine, which is why we allow ourselves to */
/* lose the object in this case. A finalizer should */
/* have its own error codes to spot this kind of */
/* problems easily. */
}
LOCK();
element->next = cache->idle;
cache->idle = element;
cache->idle_count++;
UNLOCK();
}
error = TT_Err_Ok;
Exit:
return error;
}
LOCAL_FUNC
TT_Error TTCache_Init( PEngine_Instance engine )
{
/* Create list elements mutex */
FREE_Elements = NULL;
return TT_Err_Ok;
}
LOCAL_FUNC
TT_Error TTCache_Done( PEngine_Instance engine )
{
/* We don't protect this function, as this is the end of the engine's */
/* execution.. */
PList_Element element, next;
/* frees the recycled list elements */
element = FREE_Elements;
while ( element )
{
next = element->next;
FREE( element );
element = next;
}
return TT_Err_Ok;
}
/* END */
TTCACHE.H 、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
/*******************************************************************
*
* ttcache.h 1.1
*
* Generic object cache
*
* Copyright 1996-1999 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used
* modified and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*
* This component defines and implements object caches.
*
* An object class is a structure layout that encapsulate one
* given type of data used by the FreeType engine. Each object
* class is completely described by:
*
* - a 'root' or 'leading' structure containing the first
* important fields of the class. The root structure is
* always of fixed size.
*
* It is implemented as a simple C structure, and may
* contain several pointers to sub-tables that can be
* sized and allocated dynamically.
*
* Examples: TFace, TInstance, TGlyph & TExecution_Context
* (defined in 'ttobjs.h')
*
* - we make a difference between 'child' pointers and 'peer'
* pointers. A 'child' pointer points to a sub-table that is
* owned by the object, while a 'peer' pointer points to any
* other kind of data the object isn't responsible for.
*
* An object class is thus usually a 'tree' of 'child' tables.
*
* - each object class needs a constructor and a destructor.
*
* A constructor is a function which receives the address of
* freshly allocated and zeroed object root structure and
* 'builds' all the valid child data that must be associated
* to the object before it becomes 'valid'.
*
* A destructor does the inverse job: given the address of
* a valid object, it must discard all its child data and
* zero its main fields (essentially the pointers and array
* sizes found in the root fields).
*
*
* Important notes:
*
* When the constructor fails to allocate an object, it must
* return immediately with an error code, and not try to release
* what it has previously allocated before the error. The cache
* manager detects the error and calls the destructor on the
* partial object, before returning the error to the caller (along
* with a NULL pointer for the "new" object).
*
* The destructor must thus be able to deal with "partial objects",
* i.e., objects where only part of the child tables are allocated,
* and only release these ones. As the TT_Free() function accepts
* a NULL parameter (and returns successfuly in this case), no check
* is really necessary when using the macro 'FREE()'.
*
* Currently, there is no check in the cache manager to see if a
* destructor fails (double error state!).
*
* This scheme is more compact and more maintanable than the one
* where de-allocation code is duplicated in the constructor
* _and_ the destructor.
*
*
*
* Changes between 1.1 and 1.0:
*
* - introduced the refreshed and finalizer class definition/implementation
* - inserted an engine instance pointer in the cache structure
*
******************************************************************/
#ifndef TTCACHE_H
#define TTCACHE_H
#include "tttypes.h"
#include "ttconfig.h"
#include "ttmutex.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef TT_Error TConstructor( void* object,
void* parent );
typedef TT_Error TDestructor ( void* object );
typedef TConstructor TRefresher;
typedef TDestructor TFinalizer;
typedef TConstructor* PConstructor;
typedef TDestructor* PDestructor;
typedef TRefresher* PRefresher;
typedef TFinalizer* PFinalizer;
/* A Cache class record holds the data necessary to define */
/* a cache kind. */
struct TCache_Class_
{
ULong object_size;
Long idle_limit;
PConstructor init;
PDestructor done;
PRefresher reset;
PFinalizer finalize;
};
typedef struct TCache_Class_ TCache_Class;
typedef TCache_Class* PCache_Class;
/* Simple list node record. A list element is said to be 'unlinked' */
/* when it doesn't belong to any list. */
struct TList_Element_;
typedef struct TList_Element_ TList_Element;
typedef TList_Element* PList_Element;
struct TList_Element_
{
PList_Element next;
void* data;
};
/* Simple singly-linked list record - LIFO style, no tail field */
typedef PList_Element TSingle_List;
struct TCache_
{
PEngine_Instance engine;
PCache_Class clazz; /* 'class' is a reserved word in C++ */
TMutex* lock;
TSingle_List active;
TSingle_List idle;
Long idle_count;
};
typedef struct TCache_ TCache;
typedef TCache* PCache;
/* Returns a new list element, either fresh or recycled. */
/* Note: the returned element is unlinked. */
/* An object cache holds two lists tracking the active and */
/* idle objects that are currently created and used by the */
/* engine. It can also be 'protected' by a mutex. */
/* Initializes a new cache, of class 'clazz', pointed by 'cache', */
/* protected by the 'lock' mutex. Set 'lock' to NULL if the cache */
/* doesn't need protection */
LOCAL_DEF
TT_Error Cache_Create( PEngine_Instance engine,
PCache_Class clazz,
TCache* cache,
TMutex* lock );
/* Destroys a cache and all its listed objects */
LOCAL_DEF
TT_Error Cache_Destroy( TCache* cache );
/* Extracts a new object from the cache */
LOCAL_DEF
TT_Error Cache_New( TCache* cache,
void** new_object,
void* parent_object );
/* Returns an object to the cache, or discards it depending */
/* on the cache class' 'idle_limit' field */
LOCAL_DEF
TT_Error Cache_Done( TCache* cache, void* data );
#define CACHE_New( _cache, _newobj, _parent ) \
Cache_New( (TCache*)_cache, (void**)&_newobj, (void*)_parent )
#define CACHE_Done( _cache, _obj ) \
Cache_Done( (TCache*)_cache, (void*)_obj )
LOCAL_DEF
TT_Error TTCache_Init( PEngine_Instance engine );
LOCAL_DEF
TT_Error TTCache_Done( PEngine_Instance engine );
#ifdef __cplusplus
}
#endif
#endif /* TTCACHE_H */
/* END */
TTCALC.C 、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
/*******************************************************************
*
* ttcalc.c
*
* Arithmetic Computations (body).
*
* Copyright 1996-1999 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used
* modified and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
******************************************************************/
#include "ttcalc.h"
#include "ttdebug.h"
#include "tttables.h"
/* required by the tracing mode */
#undef TT_COMPONENT
#define TT_COMPONENT trace_calc
/* Support for 1-complement arithmetic has been totally dropped in this */
/* release. You can still write your own code if you need it... */
static const Long Roots[63] =
{
1, 1, 2, 3, 4, 5, 8, 11,
16, 22, 32, 45, 64, 90, 128, 181,
256, 362, 512, 724, 1024, 1448, 2048, 2896,
4096, 5892, 8192, 11585, 16384, 23170, 32768, 46340,
65536, 92681, 131072, 185363, 262144, 370727,
524288, 741455, 1048576, 1482910, 2097152, 2965820,
4194304, 5931641, 8388608, 11863283, 16777216, 23726566,
33554432, 47453132, 67108864, 94906265,
134217728, 189812531, 268435456, 379625062,
536870912, 759250125, 1073741824, 1518500250,
2147483647
};
#ifdef LONG64
EXPORT_FUNC
TT_Long TT_MulDiv( TT_Long a, TT_Long b, TT_Long c )
{
Long s;
s = a; a = ABS( a );
s ^= b; b = ABS( b );
s ^= c; c = ABS( c );
a = ((TT_Int64)a * b + c/2) / c;
return ( s < 0 ) ? -a : a;
}
EXPORT_FUNC
TT_Long TT_MulFix( TT_Long a, TT_Long b )
{
Long s;
s = a; a = ABS( a );
s ^= b; b = ABS( b );
a = ((TT_Int64)a * b + 0x8000) / 0x10000;
return ( s < 0 ) ? -a : a;
}
LOCAL_FUNC
Int Order64( TT_Int64 z )
{
Int j = 0;
while ( z )
{
z = (unsigned INT64)z >> 1;
j++;
}
return j - 1;
}
LOCAL_FUNC
TT_Int32 Sqrt64( TT_Int64 l )
{
TT_Int64 r, s;
if ( l <= 0 ) return 0;
if ( l == 1 ) return 1;
r = Roots[Order64( l )];
do
{
s = r;
r = ( r + l/r ) >> 1;
}
while ( r > s || r*r > l );
return r;
}
#else /* LONG64 */
/* The TT_MulDiv function has been optimized thanks to ideas from */
/* Graham Asher. The trick is to optimize computation when everything */
/* fits within 32-bits (a rather common case). */
/* */
/* we compute 'a*b+c/2', then divide it by 'c'. (positive values) */
/* */
/* 46340 is FLOOR(SQRT(2^31-1)). */
/* */
/* if ( a <= 46340 && b <= 46340 ) then ( a*b <= 0x7FFEA810 ) */
/* */
/* 0x7FFFFFFF - 0x7FFEA810 = 0x157F0 */
/* */
/* if ( c < 0x157F0*2 ) then ( a*b+c/2 <= 0x7FFFFFFF ) */
/* */
/* and 2*0x157F0 = 176096 */
/* */
EXPORT_FUNC
TT_Long TT_MulDiv( TT_Long a, TT_Long b, TT_Long c )
{
long s;
if ( a == 0 || b == c )
return a;
s = a; a = ABS( a );
s ^= b; b = ABS( b );
s ^= c; c = ABS( c );
if ( a <= 46340 && b <= 46340 && c <= 176095 )
{
a = ( a*b + c/2 )/c;
}
else
{
TT_Int64 temp, temp2;
MulTo64( a, b, &temp );
temp2.hi = (TT_Int32)(c >> 31);
temp2.lo = (TT_Word32)(c / 2);
Add64( &temp, &temp2, &temp );
a = Div64by32( &temp, c );
}
return ( s < 0 ) ? -a : a;
}
/* The optimization for TT_MulFix is different. We could simply be */
/* happy by applying the same principles than with TT_MulDiv, because */
/* */
/* c = 0x10000 < 176096 */
/* */
/* however, in most cases, we have a 'b' with a value around 0x10000 */
/* which is greater than 46340. */
/* */
/* According to Graham's testing, most cases have 'a' < 100, so a good */
/* idea is to use bounds like 1024 and 2097151 (= floor(2^31-1)/1024 ) */
/* for 'a' and 'b' respectively.. */
/* */
EXPORT_FUNC
TT_Long TT_MulFix( TT_Long a, TT_Long b )
{
long s;
if ( a == 0 || b == 0x10000 )
return a;
s = a; a = ABS( a );
s ^= b; b = ABS( b );
if ( a <= 1024 && b <= 2097151 )
{
a = ( a*b + 0x8000 ) >> 16;
}
else
{
TT_Int64 temp, temp2;
MulTo64( a, b, &temp );
temp2.hi = 0;
temp2.lo = 0x8000;
Add64( &temp, &temp2, &temp );
a = Div64by32( &temp, 0x10000 );
}
return ( s < 0 ) ? -a : a;
}
LOCAL_FUNC
void Neg64( TT_Int64* x )
{
/* Remember that -(0x80000000) == 0x80000000 with 2-complement! */
/* We take care of that here. */
x->hi ^= 0xFFFFFFFFUL;
x->lo ^= 0xFFFFFFFFUL;
x->lo++;
if ( !x->lo )
{
x->hi++;
if ( x->hi == 0x80000000UL ) /* Check -MaxInt32 - 1 */
{
x->lo--;
x->hi--; /* We return 0x7FFFFFFF! */
}
}
}
LOCAL_FUNC
void Add64( TT_Int64* x, TT_Int64* y, TT_Int64* z )
{
register TT_Word32 lo, hi;
lo = x->lo + y->lo;
hi = x->hi + y->hi + ( lo < x->lo );
z->lo = lo;
z->hi = hi;
}
LOCAL_FUNC
void Sub64( TT_Int64* x, TT_Int64* y, TT_Int64* z )
{
register TT_Word32 lo, hi;
lo = x->lo - y->lo;
hi = x->hi - y->hi - ( (TT_Int32)lo < 0 );
z->lo = lo;
z->hi = hi;
}
LOCAL_FUNC
void MulTo64( TT_Int32 x, TT_Int32 y, TT_Int64* z )
{
TT_Int32 s;
TT_Word32 lo1, hi1, lo2, hi2, lo, hi, i1, i2;
s = x; x = ABS( x );
s ^= y; y = ABS( y );
lo1 = x & 0x0000FFFF; hi1 = x >> 16;
lo2 = y & 0x0000FFFF; hi2 = y >> 16;
lo = lo1*lo2;
i1 = lo1*hi2;
i2 = lo2*hi1;
hi = hi1*hi2;
/* Check carry overflow of i1 + i2 */
if ( i2 )
{
if ( i1 >= (TT_Word32)-(TT_Int32)i2 ) hi += 1L << 16;
i1 += i2;
}
i2 = i1 >> 16;
i1 = i1 << 16;
/* Check carry overflow of i1 + lo */
if ( i1 )
{
if ( lo >= (TT_Word32)-(TT_Int32)i1 ) hi++;
lo += i1;
}
hi += i2;
z->lo = lo;
z->hi = hi;
if ( s < 0 ) Neg64( z );
}
LOCAL_FUNC
TT_Int32 Div64by32( TT_Int64* x, TT_Int32 y )
{
TT_Int32 s;
TT_Word32 q, r, i, lo;
s = x->hi; if ( s < 0 ) Neg64( x );
s ^= y; y = ABS( y );
/* Shortcut */
if ( x->hi == 0 )
{
q = x->lo / y;
return ( s < 0 ) ? -(TT_Int32)q : (TT_Int32)q;
}
r = x->hi;
lo = x->lo;
if ( r >= (TT_Word32)y ) /* we know y is to be treated as unsigned here */
return ( s < 0 ) ? 0x80000001UL : 0x7FFFFFFFUL;
/* Return Max/Min Int32 if divide overflow */
/* This includes division by zero! */
q = 0;
for ( i = 0; i < 32; i++ )
{
r <<= 1;
q <<= 1;
r |= lo >> 31;
if ( r >= (TT_Word32)y )
{
r -= y;
q |= 1;
}
lo <<= 1;
}
return ( s < 0 ) ? -(TT_Int32)q : (TT_Int32)q;
}
LOCAL_FUNC
Int Order64( TT_Int64* z )
{
TT_Word32 i;
Int j;
if ( z->hi )
{
i = z->hi;
j = 32;
}
else
{
i = z->lo;
j = 0;
}
while ( i > 0 )
{
i >>= 1;
j++;
}
return j-1;
}
LOCAL_FUNC
TT_Int32 Sqrt64( TT_Int64* l )
{
TT_Int64 l2;
TT_Int32 r, s;
if ( (TT_Int32)l->hi < 0 ||
(l->hi == 0 && l->lo == 0) ) return 0;
s = Order64( l );
if ( s == 0 ) return 1;
r = Roots[s];
do
{
s = r;
r = ( r + Div64by32(l,r) ) >> 1;
MulTo64( r, r, &l2 );
Sub64 ( l, &l2, &l2 );
}
while ( r > s || (TT_Int32)l2.hi < 0 );
return r;
}
#endif /* LONG64 */
/* END */
TTCALC.H 、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
/*******************************************************************
*
* ttcalc.h
*
* Arithmetic Computations (specification).
*
* Copyright 1996-1999 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used
* modified and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
******************************************************************/
#ifndef TTCALC_H
#define TTCALC_H
#include "ttconfig.h"
#include "freetype.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef LONG64
typedef INT64 TT_Int64;
#define ADD_64( x, y, z ) z = x + y
#define SUB_64( x, y, z ) z = x - y
#define MUL_64( x, y, z ) z = (TT_Int64)(x) * (y)
#define DIV_64( x, y ) ( (x) / (y) )
#define SQRT_64( x ) Sqrt64( x )
#define SQRT_32( x ) Sqrt32( x )
LOCAL_DEF TT_Int32 Sqrt64( TT_Int64 l );
#else /* LONG64 */
struct TT_Int64_
{
TT_Word32 lo;
TT_Word32 hi;
};
typedef struct TT_Int64_ TT_Int64;
#define ADD_64( x, y, z ) Add64( &x, &y, &z )
#define SUB_64( x, y, z ) Sub64( &x, &y, &z )
#define MUL_64( x, y, z ) MulTo64( x, y, &z )
#define DIV_64( x, y ) Div64by32( &x, y )
#define SQRT_64( x ) Sqrt64( &x )
#define SQRT_32( x ) Sqrt32( x )
LOCAL_DEF void Add64( TT_Int64* x, TT_Int64* y, TT_Int64* z );
LOCAL_DEF void Sub64( TT_Int64* x, TT_Int64* y, TT_Int64* z );
LOCAL_DEF void MulTo64( TT_Int32 x, TT_Int32 y, TT_Int64* z );
LOCAL_DEF TT_Int32 Div64by32( TT_Int64* x, TT_Int32 y );
LOCAL_DEF int Order64( TT_Int64* z );
LOCAL_DEF TT_Int32 Sqrt64( TT_Int64* l );
#endif /* LONG64 */
/* The two following functions are now part of the API! */
/* TT_Long TT_MulDiv( TT_Long a, TT_Long b, TT_Long c ); */
/* TT_Long TT_MulFix( TT_Long a, TT_Long b ); */
#define INT_TO_F26DOT6( x ) ( (Long)(x) << 6 )
#define INT_TO_F2DOT14( x ) ( (Long)(x) << 14 )
#define INT_TO_FIXED( x ) ( (Long)(x) << 16 )
#define F2DOT14_TO_FIXED( x ) ( (Long)(x) << 2 )
#define FLOAT_TO_FIXED( x ) ( (Long)(x * 65536.0) )
#define ROUND_F26DOT6( x ) ( x >= 0 ? ( ((x) + 32) & -64) \
: ( -((32 - (x)) & -64) ) )
#ifdef __cplusplus
}
#endif
#endif /* TTCALC_H */
/* END */
TTCMAP.C 、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
/*******************************************************************
*
* ttcmap.c 1.0
*
* TrueType Character Mappings
*
* Copyright 1996-1999 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used
* modified and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
******************************************************************/
#include "ttobjs.h"
#include "ttdebug.h"
#include "ttfile.h"
#include "ttmemory.h"
#include "ttload.h"
#include "ttcmap.h"
/* required by the tracing mode */
#undef TT_COMPONENT
#define TT_COMPONENT trace_cmap
/*******************************************************************
*
* Function : CharMap_Load
*
* Description : Loads a given charmap into memory.
*
* Input : cmap pointer to cmap table
*
* Output : Error code.
*
* Notes : - Assumes the the stream is already used (opened).
*
* - In case of error, releases all partially allocated
* tables.
*
******************************************************************/
LOCAL_FUNC
TT_Error CharMap_Load( PCMapTable cmap,
TT_Stream input )
{
DEFINE_LOAD_LOCALS( input );
UShort num_SH, num_Seg, i;
UShort u, l;
PCMap0 cmap0;
PCMap2 cmap2;
PCMap4 cmap4;
PCMap6 cmap6;
PCMap2SubHeader cmap2sub;
PCMap4Segment segments;
if ( cmap->loaded )
return TT_Err_Ok;
if ( FILE_Seek( cmap->offset ) )
return error;
switch ( cmap->format )
{
case 0:
cmap0 = &cmap->c.cmap0;
if ( ALLOC( cmap0->glyphIdArray, 256L ) ||
FILE_Read( (void*)cmap0->glyphIdArray, 256L ) )
goto Fail;
break;
case 2:
num_SH = 0;
cmap2 = &cmap->c.cmap2;
/* allocate subheader keys */
if ( ALLOC_ARRAY( cmap2->subHeaderKeys, 256, UShort ) ||
ACCESS_Frame( 512L ) )
goto Fail;
for ( i = 0; i < 256; i++ )
{
u = GET_UShort() / 8;
cmap2->subHeaderKeys[i] = u;
if ( num_SH < u )
num_SH = u;
}
FORGET_Frame();
/* load subheaders */
cmap2->numGlyphId = l =
( ( cmap->length - 2L * (256 + 3) - num_SH * 8L ) & 0xffff) / 2;
if ( ALLOC_ARRAY( cmap2->subHeaders,
num_SH + 1,
TCMap2SubHeader ) ||
ACCESS_Frame( ( num_SH + 1 ) * 8L ) )
goto Fail;
cmap2sub = cmap2->subHeaders;
for ( i = 0; i <= num_SH; i++ )
{
cmap2sub->firstCode = GET_UShort();
cmap2sub->entryCount = GET_UShort();
cmap2sub->idDelta = GET_Short();
/* we apply the location offset immediately */
cmap2sub->idRangeOffset = GET_UShort() - ( num_SH - i ) * 8 - 2;
cmap2sub++;
}
FORGET_Frame();
/* load glyph ids */
if ( ALLOC_ARRAY( cmap2->glyphIdArray, l, UShort ) ||
ACCESS_Frame( l * 2L ) )
goto Fail;
for ( i = 0; i < l; i++ )
cmap2->glyphIdArray[i] = GET_UShort();
FORGET_Frame();
break;
case 4:
cmap4 = &cmap->c.cmap4;
/* load header */
if ( ACCESS_Frame( 8L ) )
goto Fail;
cmap4->segCountX2 = GET_UShort();
cmap4->searchRange = GET_UShort();
cmap4->entrySelector = GET_UShort();
cmap4->rangeShift = GET_UShort();
num_Seg = cmap4->segCountX2 / 2;
FORGET_Frame();
/* load segments */
if ( ALLOC_ARRAY( cmap4->segments,
num_Seg,
TCMap4Segment ) ||
ACCESS_Frame( (num_Seg * 4 + 1) * 2L ) )
goto Fail;
segments = cmap4->segments;
for ( i = 0; i < num_Seg; i++ )
segments[i].endCount = GET_UShort();
(void)GET_UShort();
for ( i = 0; i < num_Seg; i++ )
segments[i].startCount = GET_UShort();
for ( i = 0; i < num_Seg; i++ )
segments[i].idDelta = GET_Short();
for ( i = 0; i < num_Seg; i++ )
segments[i].idRangeOffset = GET_UShort();
FORGET_Frame();
cmap4->numGlyphId = l =
( ( cmap->length - ( 16L + 8L * num_Seg ) ) & 0xffff ) / 2;
/* load ids */
if ( ALLOC_ARRAY( cmap4->glyphIdArray, l , UShort ) ||
ACCESS_Frame( l * 2L ) )
goto Fail;
for ( i = 0; i < l; i++ )
cmap4->glyphIdArray[i] = GET_UShort();
FORGET_Frame();
break;
case 6:
cmap6 = &cmap->c.cmap6;
if ( ACCESS_Frame( 4L ) )
goto Fail;
cmap6->firstCode = GET_UShort();
cmap6->entryCount = GET_UShort();
FORGET_Frame();
l = cmap6->entryCount;
if ( ALLOC_ARRAY( cmap6->glyphIdArray,
cmap6->entryCount,
Short ) ||
ACCESS_Frame( l * 2L ) )
goto Fail;
for ( i = 0; i < l; i++ )
cmap6->glyphIdArray[i] = GET_UShort();
FORGET_Frame();
break;
default: /* corrupt character mapping table */
return TT_Err_Invalid_CharMap_Format;
}
return TT_Err_Ok;
Fail:
CharMap_Free( cmap );
return error;
}
/*******************************************************************
*
* Function : CharMap_Free
*
* Description : Releases a given charmap table.
*
* Input : cmap pointer to cmap table
*
* Output : Error code.
*
******************************************************************/
LOCAL_FUNC
TT_Error CharMap_Free( PCMapTable cmap )
{
if ( !cmap )
return TT_Err_Ok;
switch ( cmap->format )
{
case 0:
FREE( cmap->c.cmap0.glyphIdArray );
break;
case 2:
FREE( cmap->c.cmap2.subHeaderKeys );
FREE( cmap->c.cmap2.subHeaders );
FREE( cmap->c.cmap2.glyphIdArray );
break;
case 4:
FREE( cmap->c.cmap4.segments );
FREE( cmap->c.cmap4.glyphIdArray );
cmap->c.cmap4.segCountX2 = 0;
break;
case 6:
FREE( cmap->c.cmap6.glyphIdArray );
cmap->c.cmap6.entryCount = 0;
break;
default:
/* invalid table format, do nothing */
;
}
cmap->loaded = FALSE;
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : CharMap_Index
*
* Description : Performs charcode->glyph index translation.
*
* Input : cmap pointer to cmap table
*
* Output : Glyph index, 0 in case of failure.
*
******************************************************************/
static UShort code_to_index0( UShort charCode, PCMap0 cmap0 );
static UShort code_to_index2( UShort charCode, PCMap2 cmap2 );
static UShort code_to_index4( UShort charCode, PCMap4 cmap4 );
static UShort code_to_index6( UShort charCode, PCMap6 cmap6 );
LOCAL_FUNC
UShort CharMap_Index( PCMapTable cmap,
UShort charcode )
{
switch ( cmap->format )
{
case 0:
return code_to_index0( charcode, &cmap->c.cmap0 );
case 2:
return code_to_index2( charcode, &cmap->c.cmap2 );
case 4:
return code_to_index4( charcode, &cmap->c.cmap4 );
case 6:
return code_to_index6( charcode, &cmap->c.cmap6 );
default:
return 0;
}
}
/*******************************************************************
*
* Function : code_to_index0
*
* Description : Converts the character code into a glyph index.
* Uses format 0.
* charCode will be masked to get a value in the range
* 0x00-0xFF.
*
* Input : charCode the wanted character code
* cmap0 a pointer to a cmap table in format 0
*
* Output : Glyph index into the glyphs array.
* 0 if the glyph does not exist.
*
******************************************************************/
static UShort code_to_index0( UShort charCode,
PCMap0 cmap0 )
{
if ( charCode <= 0xFF )
return cmap0->glyphIdArray[charCode];
else
return 0;
}
/*******************************************************************
*
* Function : code_to_index2
*
* Description : Converts the character code into a glyph index.
* Uses format 2.
*
* Input : charCode the wanted character code
* cmap2 a pointer to a cmap table in format 2
*
* Output : Glyph index into the glyphs array.
* 0 if the glyph does not exist.
*
******************************************************************/
static UShort code_to_index2( UShort charCode,
PCMap2 cmap2 )
{
UShort index1, idx, offset;
TCMap2SubHeader sh2;
index1 = cmap2->subHeaderKeys[charCode <= 0xFF ?
charCode : (charCode >> 8)];
if ( index1 == 0 )
{
if ( charCode <= 0xFF )
return cmap2->glyphIdArray[charCode]; /* 8bit character code */
else
return 0;
}
else /* 16bit character code */
{
if ( charCode <= 0xFF )
return 0;
sh2 = cmap2->subHeaders[index1];
if ( (charCode & 0xFF) < sh2.firstCode )
return 0;
if ( (charCode & 0xFF) >= (sh2.firstCode + sh2.entryCount) )
return 0;
offset = sh2.idRangeOffset / 2 + (charCode & 0xFF) - sh2.firstCode;
if ( offset < cmap2->numGlyphId )
idx = cmap2->glyphIdArray[offset];
else
return 0;
if ( idx )
return (idx + sh2.idDelta) & 0xFFFF;
else
return 0;
}
}
/*******************************************************************
*
* Function : code_to_index4
*
* Description : Converts the character code into a glyph index.
* Uses format 4.
*
* Input : charCode the wanted character code
* cmap4 a pointer to a cmap table in format 4
*
* Output : Glyph index into the glyphs array.
* 0 if the glyph does not exist.
*
******************************************************************/
static UShort code_to_index4( UShort charCode,
PCMap4 cmap4 )
{
UShort index1, segCount;
UShort i;
TCMap4Segment seg4;
segCount = cmap4->segCountX2 / 2;
for ( i = 0; i < segCount; i++ )
if ( charCode <= cmap4->segments[i].endCount )
break;
/* Safety check - even though the last endCount should be 0xFFFF */
if ( i >= segCount )
return 0;
seg4 = cmap4->segments[i];
if ( charCode < seg4.startCount )
return 0;
if ( seg4.idRangeOffset == 0 )
return ( charCode + seg4.idDelta ) & 0xFFFF;
else
{
index1 = seg4.idRangeOffset / 2 + (charCode - seg4.startCount) -
(segCount - i);
if ( index1 < cmap4->numGlyphId )
{
if ( cmap4->glyphIdArray[index1] == 0 )
return 0;
else
return ( cmap4->glyphIdArray[index1] + seg4.idDelta ) & 0xFFFF;
}
else
return 0;
}
}
/*******************************************************************
*
* Function : code_to_index6
*
* Description : Converts the character code into a glyph index.
* Uses format 6.
*
* Input : charCode the wanted character code
* cmap6 a pointer to a cmap table in format 6
*
* Output : Glyph index into the glyphs array.
* 0 if the glyph does not exist (`missing character glyph').
*
******************************************************************/
static UShort code_to_index6( UShort charCode,
PCMap6 cmap6 )
{
UShort firstCode;
firstCode = cmap6->firstCode;
if ( charCode < firstCode )
return 0;
if ( charCode >= (firstCode + cmap6->entryCount) )
return 0;
return cmap6->glyphIdArray[charCode - firstCode];
}
/* END */
TTCMAP.H 、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
/*******************************************************************
*
* ttcmap.h 1.0
*
* TrueType Character Mappings
*
* Copyright 1996-1999 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used
* modified and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*
******************************************************************/
#ifndef TTCMAP_H
#define TTCMAP_H
#include "ttconfig.h"
#include "tttypes.h"
#ifdef __cplusplus
extern "C" {
#endif
/* format 0 */
struct TCMap0_
{
PByte glyphIdArray;
};
typedef struct TCMap0_ TCMap0;
typedef TCMap0* PCMap0;
/* format 2 */
struct TCMap2SubHeader_
{
UShort firstCode; /* first valid low byte */
UShort entryCount; /* number of valid low bytes */
Short idDelta; /* delta value to glyphIndex */
UShort idRangeOffset; /* offset from here to 1st code */
};
typedef struct TCMap2SubHeader_ TCMap2SubHeader;
typedef TCMap2SubHeader* PCMap2SubHeader;
struct TCMap2_
{
PUShort subHeaderKeys;
/* high byte mapping table */
/* value = subHeader index * 8 */
PCMap2SubHeader subHeaders;
PUShort glyphIdArray;
UShort numGlyphId; /* control value */
};
typedef struct TCMap2_ TCMap2;
typedef TCMap2* PCMap2;
/* format 4 */
struct TCMap4Segment_
{
UShort endCount;
UShort startCount;
Short idDelta; /* in the specs defined as UShort but the
example there gives negative values... */
UShort idRangeOffset;
};
typedef struct TCMap4Segment_ TCMap4Segment;
typedef TCMap4Segment* PCMap4Segment;
struct TCMap4_
{
UShort segCountX2; /* number of segments * 2 */
UShort searchRange; /* these parameters can be used */
UShort entrySelector; /* for a binary search */
UShort rangeShift;
PCMap4Segment segments;
PUShort glyphIdArray;
UShort numGlyphId; /* control value */
};
typedef struct TCMap4_ TCMap4;
typedef TCMap4* PCMap4;
/* format 6 */
struct TCMap6_
{
UShort firstCode; /* first character code of subrange */
UShort entryCount; /* number of character codes in subrange */
PUShort glyphIdArray;
};
typedef struct TCMap6_ TCMap6;
typedef TCMap6* PCMap6;
/* charmap table */
struct TCMapTable_
{
UShort platformID;
UShort platformEncodingID;
UShort format;
UShort length;
UShort version;
Bool loaded;
ULong offset;
union
{
TCMap0 cmap0;
TCMap2 cmap2;
TCMap4 cmap4;
TCMap6 cmap6;
} c;
};
typedef struct TCMapTable_ TCMapTable;
typedef TCMapTable* PCMapTable;
/* Load character mappings directory when face is loaded. */
/* The mappings themselves are only loaded on demand. */
LOCAL_DEF
TT_Error CharMap_Load( PCMapTable table,
TT_Stream input );
/* Destroy one character mapping table */
LOCAL_DEF
TT_Error CharMap_Free( PCMapTable table );
/* Use character mapping table to perform mapping */
LOCAL_DEF
UShort CharMap_Index( PCMapTable cmap,
UShort charCode );
/* NOTE: The PFace type isn't defined at this point */
#ifdef __cplusplus
}
#endif
#endif /* TTCMAP_H */
/* END */
TTCOMMON.H 、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
/*----------------------------
common stand type
----------------------------*/
//#define byte unsigned char
//#define word unsigned short int
//#define sword short int
//#define dword unsigned int
TTCONFIG.H 、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
/*******************************************************************
*
* ttconfig.h 1.0
*
* Configuration settings header file (spec only).
*
* Copyright 1996-1999 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used
* modified and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
* Notes:
*
* All the configuration #define statements have been gathered in
* this file to allow easy check and modification.
*
******************************************************************/
#ifndef TTCONFIG_H
#define TTCONFIG_H
/* ------------ auto configuration ------------------------------------- */
/*************************************************************************/
/* Here we include the file ft_conf.h for system dependent stuff. */
/* The specific makefile is responsible for providing the right path to */
/* this file. */
#include "ft_conf.h"
/**************************************************************************/
/* Define TT_CONFIG_THREAD_SAFE if you want to build a thread-safe */
/* version of the library. */
/* #define TT_CONFIG_OPTION_THREAD_SAFE */
/* ------------ general debugging -------------------------------------- */
/*************************************************************************
*
* There are now three debugging modes:
*
* - trace mode:
*
* Error and trace messages are sent to the log file
* (which can be the standard error output). Define
* DEBUG_LEVEL_TRACE to enable this mode.
*
* - error mode:
*
* Only error messages are generated. Define
* DEBUG_LEVEL_ERROR to enable this mode.
*
* - release mode:
*
* Error messages are neither sent nor generated. The code is
* free from any debugging parts.
*
*
* Note that you should link the engine with the 'ttdebug' component.
* in case either DEBUG_LEVEL_TRACE or DEBUG_LEVEL_ERROR is defined.
*
* Please consult ttdebug.h for more details. */
/* #define DEBUG_LEVEL_TRACE */
/* #define DEBUG_LEVEL_ERROR */
/* ------------ special debugging -------------------------------------- */
/*************************************************************************/
/* Define this if you want to generate a special debug version of the */
/* rasterizer. This will progressively draw the glyphs while the */
/* computations are done directly on the graphics screen... (with */
/* inverted glyphs). */
/* */
/* Use it at your own risk! It is not maintained currently. */
/* */
/* IMPORTANT: This is reserved to developers willing to debug the */
/* rasterizer, which seems working very well in its */
/* current state... */
/* #define DEBUG_RASTER */
/*************************************************************************/
/* Define this to have a simple debugger version of RunIns(). */
/* */
/* Use it at your own risk! It is not maintained currently. */
/* #define DEBUG_INTERPRETER */
/*************************************************************************/
/* Define this to have some housekeeping of allocation and deallocation. */
/* */
/* Please note that probably not all OS-specific versions of ttmemory.c */
/* provide this functionality. */
/* #define DEBUG_MEMORY */
/*************************************************************************/
/* Define this to have bounds checking for file buffer frames. */
/* */
/* Please note that probably not all OS-specific versions of ttfile.c */
/* provide this functionality. */
/* #define DEBUG_FILE */
/* ------------ arithmetic and processor support ----------------------- */
/*************************************************************************/
/* Define TT_USE_LONG_LONG if you want to enable the use of the */
/* 'long long' 64-bit type provided by gcc and other compilers. Note */
/* that : */
/* */
/* 1. The type isn't ANSI, and thus will produce many warnings */
/* during library compilation. */
/* */
/* 2. Though the generated object files are slightly smaller, the */
/* resulting executables are bigger of about 4Kb! gcc must be */
/* linking some extra code in there! */
/* */
/* 3. There is really no speed gain in doing so (but it may help */
/* debug the ttcalc component). */
/* */
/* IMPORTANT NOTE: You don't need to define it on 64-bits machines! */
/* */
/* NOTE 2 : This flag used to be _GNUC_LONG64_ */
/* #define TT_USE_LONG_LONG */
/*************************************************************************/
/* define ALIGNMENT to your processor/environment preferred alignment */
/* size. A value of 8 should work on all current processors, even */
/* 64-bits ones. */
#define ALIGNMENT 8
/* --------------- miscellaneous ----------------------------------- */
/*********************************************************************/
/* The number of extensions available. Don't change this value */
/* except if you add new extensions to the engine. */
#define TT_MAX_EXTENSIONS 8
/* --------------- automatic setup -- don't touch ------------------ */
/*********************************************************************/
/* If HAVE_TT_TEXT is defined we don't provide a default typedef for */
/* defining TT_Text. */
#ifndef HAVE_TT_TEXT
#define HAVE_TT_TEXT
typedef char TT_Text;
#endif
/*********************************************************************/
/* We define NULL in case it's not defined yet. The default */
/* location is stdlib.h. */
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
/*********************************************************************/
/* Some systems can't use vfprintf for error messages on stderr; if */
/* HAVE_PRINT_FUNCTION is defined, the Print macro must be supplied */
/* externally (having the same parameters). */
/* */
/* This is only used by the "ttdebug" component, which should be */
/* linked to the engine only in debug mode. */
#if defined( DEBUG_LEVEL_TRACE ) || defined( DEBUG_LEVEL_ERROR )
#ifndef HAVE_PRINT_FUNCTION
#define Print( format, ap ) vfprintf( stderr, (format), (ap) )
#endif
#endif
/********************************************************************/
/* */
/* I have added the ability to compile the library into a single */
/* object file. This gets rids of all the external symbols defined */
/* in each component interface, and de-pollutes the name-space. */
/* */
/* I use two macros, namely LOCAL_FUNC and LOCAL_DEF, which only */
/* apply to functions that are internal to the engine, and */
/* should never be seen or linked by a client application. */
/* */
/* LOCAL_DEF used in header (.h) files, to define a function */
/* that will be seen by other components. This */
/* translates to "extern" in normal mode, and to */
/* "static" in single-object mode. */
/* */
/* LOCAL_FUNC used in implementation (.c) files, just before */
/* the function body. This translates to nothing */
/* in normal mode, and to "static" in single-object */
/* mode. */
/* */
/* Getting rid of un-necessary symbols makes the "ttcommon" */
/* renaming macros hack unnecessary. Moreover, the stripped */
/* single object file (freetype.o) is 52 Kb, instead of the */
/* previous 57 Kb (size of all combined .o files), and gives */
/* a better idea of the engine's real code size. */
/* */
/* It is called a "MAKE_OPTION" because the macro must be */
/* defined in the Makefile, rather than this one. It allows */
/* any developer to quickly switch from one mode to the other */
/* without messing with "ttconfig.h" each time. */
/* */
#ifndef TT_MAKE_OPTION_SINGLE_OBJECT
#define LOCAL_FUNC /* void */
#define LOCAL_DEF extern
#else
#define LOCAL_FUNC static
#define LOCAL_DEF static
#endif
/*************************************************************************/
/* Define EXPORT_DEF and EXPORT_FUNC as needed to build e.g. a DLL. All */
/* variables and functions visible from outside have these prefixes. */
#ifndef EXPORT_DEF
#define EXPORT_DEF extern
#endif
#ifndef EXPORT_FUNC
#define EXPORT_FUNC /* void */
#endif
/* -------------- internal (developer) configuration toggles ------------ */
#undef TT_STATIC_INTERPRETER
/* Do not undefine this configuration macro. It is now a default that */
/* must be kept in all release builds. */
#undef TT_STATIC_RASTER
/* Define this if you want to generate a static raster. This makes */
/* a non re-entrant version of the scan-line converter, which is */
/* about 10% faster and 50% bigger than an indirect one! */
#endif /* TTCONFIG_H */
/* END */
TTDEBUG.C 、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
/* Simple debugging component. Temporary */
#include "ttdebug.h"
#include "tttables.h"
#include "ttobjs.h"
#ifdef DEBUG_LEVEL_TRACE
char tt_trace_levels[trace_max];
#endif
#if defined( DEBUG_LEVEL_ERROR ) || defined( DEBUG_LEVEL_TRACE )
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
static String tempStr[128];
static const String* OpStr[256] =
{
"SVTCA y", /* Set vectors to coordinate axis y */
"SVTCA x", /* Set vectors to coordinate axis x */
"SPvTCA y", /* Set Proj. vec. to coord. axis y */
"SPvTCA x", /* Set Proj. vec. to coord. axis x */
"SFvTCA y", /* Set Free. vec. to coord. axis y */
"SFvTCA x", /* Set Free. vec. to coord. axis x */
"SPvTL //", /* Set Proj. vec. parallel to segment */
"SPvTL +", /* Set Proj. vec. normal to segment */
"SFvTL //", /* Set Free. vec. parallel to segment */
"SFvTL +", /* Set Free. vec. normal to segment */
"SPvFS", /* Set Proj. vec. from stack */
"SFvFS", /* Set Free. vec. from stack */
"GPV", /* Get projection vector */
"GFV", /* Get freedom vector */
"SFvTPv", /* Set free. vec. to proj. vec. */
"ISECT", /* compute intersection */
"SRP0", /* Set reference point 0 */
"SRP1", /* Set reference point 1 */
"SRP2", /* Set reference point 2 */
"SZP0", /* Set Zone Pointer 0 */
"SZP1", /* Set Zone Pointer 1 */
"SZP2", /* Set Zone Pointer 2 */
"SZPS", /* Set all zone pointers */
"SLOOP", /* Set loop counter */
"RTG", /* Round to Grid */
"RTHG", /* Round to Half-Grid */
"SMD", /* Set Minimum Distance */
"ELSE", /* Else */
"JMPR", /* Jump Relative */
"SCvTCi", /* Set CVT */
"SSwCi", /* */
"SSW", /* */
"DUP",
"POP",
"CLEAR",
"SWAP",
"DEPTH",
"CINDEX",
"MINDEX",
"AlignPTS",
"INS_$28",
"UTP",
"LOOPCALL",
"CALL",
"FDEF",
"ENDF",
"MDAP[-]",
"MDAP[r]",
"IUP[y]",
"IUP[x]",
"SHP[0]",
"SHP[1]",
"SHC[0]",
"SHC[1]",
"SHZ[0]",
"SHZ[1]",
"SHPIX",
"IP",
"MSIRP[0]",
"MSIRP[1]",
"AlignRP",
"RTDG",
"MIAP[-]",
"MIAP[r]",
"NPushB",
"NPushW",
"WS",
"RS",
"WCvtP",
"RCvt",
"GC[0]",
"GC[1]",
"SCFS",
"MD[0]",
"MD[1]",
"MPPEM",
"MPS",
"FlipON",
"FlipOFF",
"DEBUG",
"LT",
"LTEQ",
"GT",
"GTEQ",
"EQ",
"NEQ",
"ODD",
"EVEN",
"IF",
"EIF",
"AND",
"OR",
"NOT",
"DeltaP1",
"SDB",
"SDS",
"ADD",
"SUB",
"DIV",
"MUL",
"ABS",
"NEG",
"FLOOR",
"CEILING",
"ROUND[G]",
"ROUND[B]",
"ROUND[W]",
"ROUND[?]",
"NROUND[G]",
"NROUND[B]",
"NROUND[W]",
"NROUND[?]",
"WCvtF",
"DeltaP2",
"DeltaP3",
"DeltaC1",
"DeltaC2",
"DeltaC3",
"SROUND",
"S45Round",
"JROT",
"JROF",
"ROFF",
"INS_$7B",
"RUTG",
"RDTG",
"SANGW",
"AA",
"FlipPT",
"FlipRgON",
"FlipRgOFF",
"INS_$83",
"INS_$84",
"ScanCTRL",
"SDPVTL[0]",
"SDPVTL[1]",
"GetINFO",
"IDEF",
"ROLL",
"MAX",
"MIN",
"ScanTYPE",
"IntCTRL",
"INS_$8F",
"INS_$90",
"INS_$91",
"INS_$92",
"INS_$93",
"INS_$94",
"INS_$95",
"INS_$96",
"INS_$97",
"INS_$98",
"INS_$99",
"INS_$9A",
"INS_$9B",
"INS_$9C",
"INS_$9D",
"INS_$9E",
"INS_$9F",
"INS_$A0",
"INS_$A1",
"INS_$A2",
"INS_$A3",
"INS_$A4",
"INS_$A5",
"INS_$A6",
"INS_$A7",
"INS_$A8",
"INS_$A9",
"INS_$AA",
"INS_$AB",
"INS_$AC",
"INS_$AD",
"INS_$AE",
"INS_$AF",
"PushB[0]",
"PushB[1]",
"PushB[2]",
"PushB[3]",
"PushB[4]",
"PushB[5]",
"PushB[6]",
"PushB[7]",
"PushW[0]",
"PushW[1]",
"PushW[2]",
"PushW[3]",
"PushW[4]",
"PushW[5]",
"PushW[6]",
"PushW[7]",
"MDRP[G]",
"MDRP[B]",
"MDRP[W]",
"MDRP[?]",
"MDRP[rG]",
"MDRP[rB]",
"MDRP[rW]",
"MDRP[r?]",
"MDRP[mG]",
"MDRP[mB]",
"MDRP[mW]",
"MDRP[m?]",
"MDRP[mrG]",
"MDRP[mrB]",
"MDRP[mrW]",
"MDRP[mr?]",
"MDRP[pG]",
"MDRP[pB]",
"MDRP[pW]",
"MDRP[p?]",
"MDRP[prG]",
"MDRP[prB]",
"MDRP[prW]",
"MDRP[pr?]",
"MDRP[pmG]",
"MDRP[pmB]",
"MDRP[pmW]",
"MDRP[pm?]",
"MDRP[pmrG]",
"MDRP[pmrB]",
"MDRP[pmrW]",
"MDRP[pmr?]",
"MIRP[G]",
"MIRP[B]",
"MIRP[W]",
"MIRP[?]",
"MIRP[rG]",
"MIRP[rB]",
"MIRP[rW]",
"MIRP[r?]",
"MIRP[mG]",
"MIRP[mB]",
"MIRP[mW]",
"MIRP[m?]",
"MIRP[mrG]",
"MIRP[mrB]",
"MIRP[mrW]",
"MIRP[mr?]",
"MIRP[pG]",
"MIRP[pB]",
"MIRP[pW]",
"MIRP[p?]",
"MIRP[prG]",
"MIRP[prB]",
"MIRP[prW]",
"MIRP[pr?]",
"MIRP[pmG]",
"MIRP[pmB]",
"MIRP[pmW]",
"MIRP[pm?]",
"MIRP[pmrG]",
"MIRP[pmrB]",
"MIRP[pmrW]",
"MIRP[pmr?]"
};
const String* Cur_U_Line( void* _exec )
{
String s[32];
Int op, i, n;
PExecution_Context exec;
exec = _exec;
op = exec->code[exec->IP];
sprintf( tempStr, "%s", OpStr[op] );
if ( op == 0x40 )
{
n = exec->code[exec->IP + 1];
sprintf( s, "(%d)", n );
strncat( tempStr, s, 8 );
if ( n > 20 ) n = 20; /* limit output */
for ( i = 0; i < n; i++ )
{
sprintf( s, " $%02hx", exec->code[exec->IP + i + 2] );
strncat( tempStr, s, 8 );
}
}
else if ( op == 0x41 )
{
n = exec->code[exec->IP + 1];
sprintf( s, "(%d)", n );
strncat( tempStr, s, 8 );
if ( n > 20 ) n = 20; /* limit output */
for ( i = 0; i < n; i++ )
{
sprintf( s, " $%02hx%02hx", exec->code[exec->IP + i*2 + 2],
exec->code[exec->IP + i*2 + 3] );
strncat( tempStr, s, 8 );
}
}
else if ( (op & 0xF8) == 0xB0 )
{
n = op - 0xB0;
for ( i = 0; i <= n; i++ )
{
sprintf( s, " $%02hx", exec->code[exec->IP + i + 1] );
strncat( tempStr, s, 8 );
}
}
else if ( (op & 0xF8) == 0xB8 )
{
n = op-0xB8;
for ( i = 0; i <= n; i++ )
{
sprintf( s, " $%02hx%02hx", exec->code[exec->IP + i*2 + 1],
exec->code[exec->IP + i*2 + 2] );
strncat( tempStr, s, 8 );
}
}
return (String*)tempStr;
}
/* the Print() function is defined in ttconfig.h; */
/* it defaults to vprintf on systems which have it */
void TT_Message( const String* fmt, ... )
{
va_list ap;
va_start( ap, fmt );
Print( fmt, ap );
va_end( ap );
}
void TT_Panic( const String* fmt, ... )
{
va_list ap;
va_start( ap, fmt );
Print( fmt, ap );
va_end( ap );
exit( EXIT_FAILURE );
}
#endif /* defined( DEBUG_LEVEL_ERROR ) || defined( DEBUG_LEVEL_TRACE ) */
#if defined( DEBUG_LEVEL_TRACE )
/* use this function to set the values of tt_trace_levels */
void set_tt_trace_levels( int index, char value )
{
tt_trace_levels[index] = value;
}
#endif
/* END */
TTDEBUG.H 、、、、、、、、、、、、、、、、、、、、、、、、、、、
/*******************************************************************
*
* ttdebug.h
*
* Debugging and Logging component (specification)
*
* Copyright 1996-1999 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used
* modified and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*
* This component contains various macros and functions used to
* ease the debugging of the FreeType engine. Its main purpose
* is in assertion checking, tracing, and error detection.
*
* There are now three debugging modes:
*
* - trace mode:
*
* Error and trace messages are sent to the log file
* (which can be the standard error output). Define
* DEBUG_LEVEL_TRACE to enable this mode.
*
* - error mode:
*
* Only error messages are generated. Define
* DEBUG_LEVEL_ERROR to enable this mode.
*
* - release mode:
*
* Error messages are neither sent nor generated. The code is
* free from any debugging parts.
*
******************************************************************/
#ifndef TTDEBUG_H
#define TTDEBUG_H
#include "ttconfig.h"
#include "tttypes.h"
#ifdef __cplusplus
extern "C" {
#endif
#if defined( DEBUG_LEVEL_TRACE )
typedef enum Trace_Component_
{
trace_any = 0,
trace_api,
trace_interp,
trace_load,
trace_gload,
trace_memory,
trace_file,
trace_mutex,
trace_cache,
trace_calc,
trace_cmap,
trace_extend,
trace_objs,
trace_raster,
trace_bitmap,
trace_max
} Trace_Component;
/* Here we define an array to hold the trace levels per component. */
/* Since it is globally defined, all array members are set to 0. */
/* You should set the values in this array either in your program */
/* or with your debugger. */
/* */
/* Currently, up to eight levels (PTRACE0-PTRACE7, see below) are */
/* used in some parts of the engine. */
/* */
/* For example, to have all tracing messages in the raster */
/* component, say */
/* */
/* #define DEBUG_LEVEL_TRACE */
/* #include "ttdebug.h" */
/* */
/* ... */
/* set_tt_trace_levels( trace_raster, 7 ) */
/* */
/* in your code before initializing the FreeType engine. */
/* */
/* Maybe it is better to define DEBUG_LEVEL_TRACE in ttconfig.h... */
extern char tt_trace_levels[trace_max];
/* IMPORTANT: */
/* */
/* Each component must define the macro TT_COMPONENT */
/* to a valid Trace_Component value before using any */
/* PTRACEx macro. */
/* */
#define PTRACE( level, varformat ) \
if ( tt_trace_levels[TT_COMPONENT] >= level ) TT_Message##varformat
#elif defined( DEBUG_LEVEL_ERROR )
#define PTRACE( level, varformat ) /* nothing */
#else /* RELEASE MODE */
#define TT_Assert( condition, action ) /* nothing */
#define PTRACE( level, varformat ) /* nothing */
#define PERROR( varformat ) /* nothing */
#define PANIC( varformat ) /* nothing */
#endif
/************************************************************************/
/* */
/* Define macros and fuctions that are common to the debug and trace */
/* modes. */
/* */
#if defined( DEBUG_LEVEL_TRACE ) || defined( DEBUG_LEVEL_ERROR )
#define TT_Assert( condition, action ) if ( !(condition) ) ( action )
void TT_Message( const String* fmt, ... );
void TT_Panic ( const String* fmt, ... );
/* print a message and exit */
const String* Cur_U_Line( void* exec );
#define PERROR( varformat ) TT_Message##varformat
#define PANIC( varformat ) TT_Panic##varformat
#endif
#if defined( DEBUG_LEVEL_TRACE )
void set_tt_trace_levels( int index, char value );
#endif
#define PTRACE0( varformat ) PTRACE( 0, varformat )
#define PTRACE1( varformat ) PTRACE( 1, varformat )
#define PTRACE2( varformat ) PTRACE( 2, varformat )
#define PTRACE3( varformat ) PTRACE( 3, varformat )
#define PTRACE4( varformat ) PTRACE( 4, varformat )
#define PTRACE5( varformat ) PTRACE( 5, varformat )
#define PTRACE6( varformat ) PTRACE( 6, varformat )
#define PTRACE7( varformat ) PTRACE( 7, varformat )
#ifdef __cplusplus
}
#endif
#endif /* TTDEBUG_H */
TTENGINE.H 、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
/*******************************************************************
*
* ttengine.h 1.1
*
* Engine instance structure definition.
*
* Copyright 1996-1999 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used
* modified and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
* New in 1.1 :
*
* - added the 'raster_lock' mutex field to synchronize
* scan-line conversion in thread-safe and re-entrant builds.
*
******************************************************************/
#ifndef TTENGINE_H
#define TTENGINE_H
#include "tttypes.h"
#include "ttconfig.h"
#include "freetype.h"
#include "ttmutex.h"
#ifdef __cplusplus
extern "C" {
#endif
/********************************************************************/
/* */
/* The freetype engine instance structure. */
/* */
/* This structure holds all the data that is necessary to run */
/* one instance of the freetype engine. It is needed to get a */
/* completely re-entrant version of the library. */
/* */
/* The goal is to move _all_ component-specific variables, either */
/* static or global in the structure; the component initializers */
/* and finalizers will all be called with the address of a valid */
/* TEngine_Instance. */
/* */
/********************************************************************/
struct TEngine_Instance_
{
TMutex lock; /* engine lock */
void* list_free_elements;
void* objs_face_class; /* the face cache class */
void* objs_instance_class; /* the instance cache class */
void* objs_execution_class; /* the context cache class */
void* objs_glyph_class; /* the glyph cache class */
void* objs_face_cache; /* these caches are used to track */
void* objs_exec_cache; /* the current face and execution */
/* context objects */
void* file_component; /* ttfile implementation dependent */
TMutex raster_lock; /* mutex for this engine's render pool */
void* raster_component; /* ttraster implementation depedent */
Byte raster_palette[5]; /* gray-levels palette for anti-aliasing */
void* extension_component; /* extensions dependent */
#if 0
TT_Glyph_Loader_Callback glCallback; /* glyph loader callback, if any */
#endif
};
/* NOTE : The raster's lock is only acquired by the Render_Glyph and */
/* Render_Gray_Glyph functions, which always release it on exit */
/* They do not lock the engine mutex. This means you shouldn't */
/* be concerned about deadlocks between the two mutexes, as these */
/* should never appear.. */
typedef struct TEngine_Instance_ TEngine_Instance;
typedef TEngine_Instance* PEngine_Instance;
#ifdef TT_CONFIG_OPTION_THREAD_SAFE /* for re-entrant builds */
#define ENGINE_ARG TEngine_Instance* _engine
#define ENGINE_ARGS TEngine_Instance* _engine,
#define ENGINE_VAR _engine
#define ENGINE_VARS _engine,
#define ENGINE _engine
#else /* for thread-safe builds */
#define ENGINE_ARG /* void */
#define ENGINE_ARGS
#define ENGINE_VAR
#define ENGINE_VARS
#endif /* TT_CONFIG_OPTION_THREAD_SAFE */
#ifdef __cplusplus
}
#endif
#endif /* TTENGINE_H */
/* END */
TTEXTEND.C 、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
/*******************************************************************
*
* ttextend.h 2.0
*
* Extensions Interface
*
* Copyright 1996-1999 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used
* modified and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
* This is an updated version of the extension component, now
* located in the main library's source directory. It allows
* the dynamic registration/use of various face object extensions
* through a simple API.
*
******************************************************************/
#include "ttextend.h"
#include "ttengine.h"
#include "ttmemory.h"
/* required by the tracing mode */
#undef TT_COMPONENT
#define TT_COMPONENT trace_extend
struct TExtension_Registry_
{
Int num_extensions;
Long cur_offset;
TExtension_Class classes[TT_MAX_EXTENSIONS];
};
typedef struct TExtension_Registry_ TExtension_Registry;
typedef TExtension_Registry* PExtension_Registry;
/* Initialize the extension component */
LOCAL_FUNC
TT_Error TTExtend_Init( PEngine_Instance engine )
{
TT_Error error;
PExtension_Registry exts;
if ( ALLOC( exts, sizeof ( TExtension_Registry ) ) )
return error;
exts->num_extensions = 0;
exts->cur_offset = 0;
engine->extension_component = (void*)exts;
return TT_Err_Ok;
}
/* Finalize the extension component */
LOCAL_FUNC
TT_Error TTExtend_Done( PEngine_Instance engine )
{
FREE( engine->extension_component );
return TT_Err_Ok;
}
/* Register a new extension */
EXPORT_FUNC
TT_Error TT_Register_Extension( PEngine_Instance engine,
Long id,
Long size,
PExt_Constructor create,
PExt_Destructor destroy )
{
PExtension_Registry exts;
PExtension_Class clazz;
Int p;
exts = (PExtension_Registry)engine->extension_component;
if ( !exts )
return TT_Err_Ok;
p = exts->num_extensions;
if ( p >= TT_MAX_EXTENSIONS )
return TT_Err_Too_Many_Extensions;
clazz = exts->classes + p;
clazz->id = id;
clazz->size = size;
clazz->build = create;
clazz->destroy = destroy;
clazz->offset = exts->cur_offset;
exts->num_extensions++;
exts->cur_offset += ( size + ALIGNMENT-1 ) & -ALIGNMENT;
return TT_Err_Ok;
}
/* Query an extension block by extension_ID */
EXPORT_FUNC
TT_Error TT_Extension_Get( PFace face,
Long extension_id,
void** extension_block )
{
PExtension_Registry registry;
PExtension_Class clazz;
Int n;
if ( !face->extension )
return TT_Err_Extensions_Unsupported;
registry = (PExtension_Registry)face->engine->extension_component;
for ( n = 0; n < face->n_extensions; n++ )
{
clazz = registry->classes + n;
if ( clazz->id == extension_id )
{
*extension_block = (PByte)face->extension + clazz->offset;
return TT_Err_Ok;
}
}
return TT_Err_Invalid_Extension_Id;
}
/* Destroy all extensions within a face object. Called by the */
/* face object destructor. */
LOCAL_FUNC
TT_Error Extension_Destroy( PFace face )
{
PEngine_Instance engine = face->engine;
PExtension_Registry registry;
PExtension_Class clazz;
Int n;
PByte ext;
registry = (PExtension_Registry)engine->extension_component;
for ( n = 0; n < face->n_extensions; n++ )
{
clazz = registry->classes + n;
ext = (PByte)face->extension + clazz->offset;
/* the destructor is optional */
if ( clazz->destroy )
clazz->destroy( (void*)ext, face );
}
/* destroy the face's extension block too */
FREE( face->extension );
face->n_extensions = 0;
return TT_Err_Ok;
}
/* Create an extension within a face object. Called by the */
/* face object constructor. */
LOCAL_FUNC
TT_Error Extension_Create( PFace face )
{
PEngine_Instance engine = face->engine;
PExtension_Registry registry;
PExtension_Class clazz;
TT_Error error;
Int n;
PByte ext;
registry = (PExtension_Registry)engine->extension_component;
face->n_extensions = registry->num_extensions;
if ( ALLOC( face->extension, registry->cur_offset ) )
return error;
for ( n = 0; n < face->n_extensions; n++ )
{
clazz = registry->classes + n;
ext = (PByte)face->extension + clazz->offset;
error = clazz->build( (void*)ext, face );
if ( error )
goto Fail;
}
return TT_Err_Ok;
Fail:
Extension_Destroy( face );
return error;
}
/* END */
TTEXTEND.H 、、、、、、、、、、、、、、、、、、、、、、、、、、
/*******************************************************************
*
* ttextend.h 2.0
*
* Extensions Interface.
*
* Copyright 1996-1999 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used
* modified and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
* This is an updated version of the extension component, now
* located in the main library's source directory. It allows
* the dynamic registration/use of various face object extensions
* through a simple API.
*
******************************************************************/
#ifndef TTEXTEND_H
#define TTEXTEND_H
#include "ttconfig.h"
#include "tttypes.h"
#include "ttobjs.h"
#ifdef __cplusplus
extern "C" {
#endif
/* The extensions don't need to be integrated at compile time into */
/* the engine, only at link time. */
/* When a new face object is created, the face constructor calls */
/* the extension constructor with the following arguments: */
/* */
/* ext : typeless pointer to the face's extension block. */
/* Its size is the one given at registration time */
/* in the extension class's 'size' field. */
/* */
/* face : the parent face object. Note that the extension */
/* constructor is called when the face object is */
/* built. */
typedef TT_Error TExt_Constructor( void* ext, PFace face );
/* When a face object is destroyed, the face destructor calls */
/* the extension destructor with the following arguments. */
/* */
/* ext : typeless pointer to the face's extension block. */
/* Its size is the one given at registration time */
/* in the extension class's 'size' field. */
/* */
/* face : the parent face object. Note that the extension */
/* destructor is called before the actual face object */
/* is destroyed. */
typedef TT_Error TExt_Destructor ( void* ext, PFace face );
typedef TExt_Constructor* PExt_Constructor;
typedef TExt_Destructor* PExt_Destructor;
struct TExtension_Class_
{
Long id; /* extension id */
Long size; /* size in bytes of extension record */
PExt_Constructor build; /* the extension's class constructor */
PExt_Destructor destroy; /* the extension's class destructor */
Long offset; /* offset of ext. record in face obj */
/* (set by the engine) */
};
typedef struct TExtension_Class_ TExtension_Class;
typedef TExtension_Class* PExtension_Class;
#define Build_Extension_ID( a, b, c, d ) \
( ((ULong)(a) << 24) | \
((ULong)(b) << 16) | \
((ULong)(c) << 8 ) | \
(ULong)(d) )
/* A note regarding extensions and the single-object compilation */
/* mode : */
/* */
/* When the engine is compiled as a single object file, extensions */
/* must remain linkable *after* compile time. In order to do this, */
/* we need to export the functions that an extension may need. */
/* Fortunately, we can limit ourselves to : */
/* */
/* o TT_Register_Extension (previously called Extension_Register) */
/* which is to be called by each extension on within */
/* it TT_Init_XXXX_Extension initializer. */
/* */
/* o File and frame access functions. Fortunately, these already */
/* have their names prefixed by "TT_", so no change was needed */
/* except replacing the LOCAL_DEF keyword with EXPORT_DEF */
/* */
/* o Memory access functions, i.e. TT_Alloc and TT_Free. Again, */
/* the change is minimal */
/* */
/* o the table-lookup function : TT_LookUp_Table, formerly known */
/* as Load_TrueType_Table in ttload.c. */
/* */
/* */
/* Other than that, an extension should be able to #include all */
/* relevant header files to get access to internal types, but */
/* should not call engine internal functions.. */
/* */
/* If there is a need for a specific internal function call, let */
/* me known to see if we need to export it by default.. */
/* - DavidT */
/* */
/* Register a new extension. Called by extension */
/* service initializers. */
EXPORT_DEF
TT_Error TT_Register_Extension( PEngine_Instance engine,
Long id,
Long size,
PExt_Constructor create,
PExt_Destructor destroy );
#ifdef TT_CONFIG_OPTION_EXTEND_ENGINE
/* Initialize the extension component */
LOCAL_DEF
TT_Error TTExtend_Init( PEngine_Instance engine );
/* Finalize the extension component */
LOCAL_DEF
TT_Error TTExtend_Done( PEngine_Instance engine );
/* Create an extension within a face object. Called by the */
/* face object constructor. */
LOCAL_DEF
TT_Error Extension_Create( PFace face );
/* Destroy all extensions within a face object. Called by the */
/* face object destructor. */
LOCAL_DEF
TT_Error Extension_Destroy( PFace face );
#endif
/* Query an extension block by extension_ID. Called by extension */
/* service routines. */
EXPORT_DEF
TT_Error TT_Extension_Get( PFace face,
Long extension_id,
void** extension_block );
#ifdef __cplusplus
}
#endif
#endif /* TTEXTEND_H */
/* END */
ttextout.c 、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
//#include <stdio.h>
//#include <stdlib.h>
//#include <string.h>
#include <stdlib.h>
#include "XText.h"
#include "XComm.h"
#include "XGraphic.h"
#include "XCodePage.h"
#undef error
#define error error_
#include "freetype.h"
#include "ttobjs.h"
#define UNICODE 1
#define BIG5 4
#define LID_BIG5 0x404
#define LID_SHIFTJIS 0x411
#define LID_GB 0x408
#define LID_KOREA 0x412
#define LID_ENGLISH 0x409
#define CODEPAGE_USE 0
#define CODEPAGE_BRI 1
#define CODEPAGE_GER 2
#define CODEPAGE_FRE 3
#define CODEPAGE_DAN 4
#define CODEPAGE_ITA 5
#define CODEPAGE_SPA 6
#define CODEPAGE_SWE 7
#define CODEPAGE_SWI 8
#define CODEPAGE_437 9
#define CODEPAGE_850 10
#define CODEPAGE_852 11
#define CODEPAGE_860 12
#define CODEPAGE_863 13
#define CODEPAGE_865 14
#define CODEPAGE_857 15
#if defined( TPH_DPI_200 )
#define RESOLUTION 200
#elif defined( TPH_DPI_300 )
#define RESOLUTION 300
#elif defined( TPH_DPI_600 )
#define RESOLUTION 600
#endif
//char Header[128];
TT_Engine engine={NULL};
TT_Face face={NULL};
TT_Instance instance;
TT_Glyph glyph;
TT_CharMap char_map;
TT_Glyph_Metrics ttf_metrics;
TT_Outline outline;
TT_Face_Properties properties;
TT_Instance_Metrics imetrics;
TT_Matrix matrix;
TT_Raster_Map Bit;
int num_glyphs;
int ptsize;
int hinted;
int Fail;
int Num;
int gray_render;
short glyph_code[128];
unsigned short char_unicode[128];
int num_codes;
int BearingY;
// char FaceName[13]="";
int LanguageID;
INT (*lpTTFGetData)(BYTE * , INT); // Get Data Function
VOID (*lpTTFSetDataPoint)(INT); // Set Data Point Function
LONG (*lpTTFGetDataPoint)(VOID);
LONG (*lpTTFGetSize)(VOID);
//
// Convert an ASCII string to a string of glyph indexes.
//
static void CharToUnicode(_TextAttr* psTextAttr , int CodePage)
{
unsigned short i, n, char_idx, *pCodePage;
unsigned short platform, encoding;
TT_Error error;
BYTE* source;
switch(CodePage)
{
case CODEPAGE_437:
pCodePage = (unsigned short *)CodePage437ToUnicode;
break;
case CODEPAGE_850:
pCodePage = (unsigned short *)CodePage850ToUnicode;
break;
case CODEPAGE_852:
pCodePage = (unsigned short *)CodePage852ToUnicode;
break;
case CODEPAGE_860:
pCodePage = (unsigned short *)CodePage860ToUnicode;
break;
case CODEPAGE_863:
pCodePage = (unsigned short *)CodePage863ToUnicode;
break;
case CODEPAGE_865:
pCodePage = (unsigned short *)CodePage865ToUnicode;
break;
case CODEPAGE_857:
pCodePage = (unsigned short *)CodePage857ToUnicode;
break;
default:
pCodePage = (unsigned short *)CodePage850ToUnicode;
break;
}
source = psTextAttr->pExp;
// First, look for a Unicode charmap
n = properties.num_CharMaps;
LanguageID = LID_ENGLISH;
for ( i = 0; i < n; i++ )
{
error = TT_Get_CharMap_ID( face, i, &platform, &encoding );
if ( (platform == 3 && encoding == BIG5) ||
(platform == 3 && encoding == UNICODE))
// (encoding == UNICODE || encoding == BIG5))
{
TT_Get_CharMap( face, i, &char_map );
i = n + 1;
if(encoding == BIG5)
LanguageID = LID_BIG5;
}
}
//not suppose to happen
//But it the font does not have unicode map, we display error here
if ( i == n )
{
// Panic( "Sorry, but this font doesn't contain any Unicode mapping table\n" );
// #if defined( LCD_MODEL )
// ShowFont(0, 48, (BYTE *)"No Unicode map");
// #endif
glyph_code[0]=0x20;glyph_code[1]=0x21;glyph_code[2]=0x22;
glyph_code[3]=0x23;glyph_code[4]=0x24;
num_codes = n;
return;
}
i=0;
for ( n = 0; n < 128 && source[n]; n++ )
{
if(source[n]&0x80 )
{
if(LanguageID == LID_BIG5 && encoding == UNICODE )
{
//calc BIG5 table index
//hi byte
char_idx = (int)(source[n] - 0xA1) * 157;
//lo byte
if(source[n+1] >= 0xA1)
char_idx += source[n+1] - 0xA1 + 0x3f;
else
char_idx += source[n+1] - 0x40;
char_idx = BIG5ToUnicode[char_idx];
n++;
}
else if(LanguageID == LID_GB && encoding == UNICODE )
{
char_idx = (int)(source[n] - 0x81) * 192;
if(source[n+1] >= 0xA1)
char_idx += source[n+1] - 0xA1 + 0x3f;
else
char_idx += source[n+1] - 0x40;
// char_idx = GBToUnicode[char_idx];
n++;
}
else
{
char_idx = pCodePage[source[n] & 0xff];
}
glyph_code[i] = TT_Char_Index( char_map, char_idx );
}
else
{
//char_idx = (short)source[n];
char_idx = pCodePage[source[n] & 0xff];
if( platform == 3 && encoding == 1 ) //unicode
glyph_code[i] = TT_Char_Index( char_map, char_idx );
else
glyph_code[i] = char_idx + 1 ;
}
char_unicode[i] = char_idx;
i++;
}
//for ( n = 0; n < 128 && source[n]; n++ )
//{
// glyph_code[n] = TT_Char_Index( char_map, source[n]);
//}
num_codes = i;
}
TT_Error Reset_Scale( int pointSize )
{
TT_Error error;
if ( (error = TT_Set_Instance_PointSize( instance, pointSize )) )
{
// RestoreScreen();
// printf( "error = 0x%x\n", (int)error );
// Panic( "could not reset instance\n" );
}
TT_Get_Instance_Metrics( instance, &imetrics );
return TT_Err_Ok;
}
static TT_Error LoadTrueTypeChar( int idx, int hint )
{
int flags;
flags = TTLOAD_SCALE_GLYPH;
if ( hint )
flags |= TTLOAD_HINT_GLYPH;
return TT_Load_Glyph( instance, glyph, idx, flags );
}
TT_Error Render_0_Glyph( TT_Glyph glyph,
int x_offset,
int y_offset )
{
TT_Error error;
TT_Get_Glyph_Outline( glyph, &outline );
matrix.xx = (TT_Fixed)(1 * (1L<<16));
matrix.xy = (TT_Fixed)(0 * (1L<<16));
matrix.yx = -matrix.xy;
matrix.yy = -matrix.xx;
TT_Transform_Outline( &outline, &matrix );
TT_Translate_Outline( &outline, 0, BearingY);
error = TT_Get_Glyph_Bitmap( glyph, &Bit,
(long)x_offset*64, (long)y_offset*64 );
return error;
}
TT_Error Render_180_Glyph( TT_Glyph glyph,
int x_offset,
int y_offset )
{
TT_Error error;
TT_Get_Glyph_Outline( glyph, &outline );
//TT_Translate_Outline( &outline, -xcenter*64L, -ycenter*64L );
//0
//matrix.xx = (TT_Fixed)(1 * (1L<<16));
//matrix.xy = (TT_Fixed)(0 * (1L<<16));
//matrix.yx = -matrix.xy;
//matrix.yy = matrix.xx;
//180
matrix.xx = -(TT_Fixed)(1 * (1L<<16));
matrix.xy = (TT_Fixed)(0 * (1L<<16));
matrix.yx = -matrix.xy;
matrix.yy = -matrix.xx;
TT_Transform_Outline( &outline, &matrix );
TT_Translate_Outline( &outline, 0, -BearingY);
error = TT_Get_Glyph_Bitmap( glyph, &Bit,
(long)x_offset*64, (long)y_offset*64 );
return error;
}
TT_Error Render_90_Glyph(TT_Glyph glyph,
int x_offset,
int y_offset )
{
TT_Error error;
TT_Get_Glyph_Outline( glyph, &outline );
//TT_Translate_Outline( &outline, -xcenter*64L, -ycenter*64L );
//0
matrix.xx = (TT_Fixed)(0 * (1L<<16));
matrix.xy = (TT_Fixed)(1 * (1L<<16));
matrix.yx = matrix.xy;
matrix.yy = matrix.xx;
TT_Transform_Outline( &outline, &matrix );
TT_Translate_Outline( &outline, -BearingY,0);
error = TT_Get_Glyph_Bitmap( glyph, &Bit,
(long)x_offset*64, (long)y_offset*64 );
return error;
}
TT_Error Render_270_Glyph( TT_Glyph glyph,
int x_offset,
int y_offset )
{
TT_Error error;
TT_Get_Glyph_Outline( glyph, &outline );
//TT_Translate_Outline( &outline, -xcenter*64L, -ycenter*64L );
//0
matrix.xx = (TT_Fixed)(0 * (1L<<16));
matrix.xy = -(TT_Fixed)(1 * (1L<<16));
matrix.yx = matrix.xy;
matrix.yy = matrix.xx;
TT_Transform_Outline( &outline, &matrix );
TT_Translate_Outline( &outline, BearingY,0);
error = TT_Get_Glyph_Bitmap( glyph, &Bit,
(long)x_offset*64, (long)y_offset*64 );
return error;
}
extern char *_mnext;
extern MEMT _pool;
extern MEMT _memt;
char *pBuf;
/*============================================================*/
//#pragma section Image
/*============================================================*/
//char OurMemorySpace[POOL_SIZE];
/*============================================================*/
//#pragma section
/*============================================================*/
void Display_Error(BYTE *FunctionName, TT_Error error)
{
char buf[20];
long j;
// #if defined( LCD_MODEL )
// ShowFont(0, 0, FunctionName);
// #endif
if(error == TT_Err_Ok)
{
// #if defined( LCD_MODEL )
// ShowFont(0, 16, (BYTE *)"return OK ");
// #endif
}
else
{
// #if defined( LCD_MODEL )
// ShowFont(0, 16, (BYTE *)"return FAIL ");
// #endif
buf[0]='E'; buf[1]='R';buf[2]='R';buf[3]=':';
buf[4] = error /256;
if(buf[4] > 10)buf[4]+=0x41;
else buf[4]+='0';
buf[5] = (error & 0xff) / 16;
if(buf[5] > 10)buf[5]+=0x41;
else buf[5]+='0';
buf[6] = (error & 0xf);
if(buf[6] > 10)buf[6]+=0x41;
else buf[6]+='0';
buf[7] = buf[8] = ' '; buf[9] = 0;
// #if defined( LCD_MODEL )
// ShowFont(0, 32, buf);
// #endif
}
j=0;
while(j<95000000L)j++;
}
MakeInt(char *buf,int num)
{
buf[3] = (num & 0xf);
if(buf[3] > 9) buf[3] += 'A' - 10;
else buf[3] += '0';
buf[2] = (num>>4) & 0xf;
if(buf[2] > 9) buf[2] += 'A'- 10;
else buf[2] += '0';
buf[1] = (num>>8) & 0xf;
if(buf[1] > 9) buf[1] += 'A'- 10;
else buf[1] += '0';
buf[0] = (num>>12) & 0xf;
if(buf[0] > 9) buf[0] += 'A'- 10;
else buf[0] += '0';
buf[4] = 0;
}
Bool Init_Engine( void )
{
TT_Error error;
// //if initialized, simply return
// if(engine.z)
// return TRUE;
//initialize memory pool management
_pool.size = _memt.size = 0;
_pool.top = _memt.top = NULL;
if ( ( pBuf = malloc( POOL_SIZE ) ) == _NULL )
return FALSE;
_mnext = pBuf;
_msize=POOL_SIZE;
// Initialize engine
error = TT_Init_FreeType( &engine );
if(error)
return FALSE;
else
return TRUE;
}
int TTOutText(_TextAttr* psTextAttr, _FontAttr* pFontAttr)
{
int i;
TT_F26Dot6 x, y;
TT_Error error;
int Hodify_iY, Hodify_Height;
char buf[20];
int iEraseHeight = 0;
int iEraseWidth = 0;
if(!Init_Engine())
{
free ( pBuf );
SendString("TTF malloc error");
return FALSE;
}
lpTTFGetData = pFontAttr->lpGetData;
lpTTFSetDataPoint = pFontAttr->lpSetDataPoint;
lpTTFGetDataPoint = pFontAttr->lpGetDataPoint;
lpTTFGetSize = pFontAttr->lpGetSize;
//initialize our own image buffer attributes
Bit.rows = psTextAttr->psImageBuffer->iHeight;
Bit.cols = psTextAttr->psImageBuffer->iByteWidth;
Bit.width = psTextAttr->psImageBuffer->iWidth;
Bit.flow = TT_Flow_Up;//TT_Flow_Down;
Bit.bitmap = psTextAttr->psImageBuffer->pBuffer;
Bit.size = Bit.rows * Bit.cols;
//hinted always
hinted = 1;
// if(strcmp(FaceName,psTextAttr->pFont))
// {
// //if some other font been used, close the font face
// if(face.z)
// TT_Close_Face(face);
// strcpy(FaceName,(char *)psTextAttr->pFont);
// Load new face
error = TT_Open_Face( engine, (char *)psTextAttr->pFont, &face );
if(error)
{
SendPrintf("TT_Open_Face:%d\r\n", error);
free ( pBuf );
return FALSE;
}
// get face properties and allocate preload arrays
TT_Get_Face_Properties( face, &properties );
// create glyph
error = TT_New_Glyph( face, &glyph );
/* if(error)
{
Send_String("TT_New_Glyph:");
Send_Num(error);
Send_String("\r\n");
return -1;
}*/
// create instance
error = TT_New_Instance( face, &instance );
/* if(error)
{
Send_String("TT_New_Instance:");
Send_Num(error);
Send_String("\r\n");
return -1;
}*/
// set resolution, we could use this to expand width
error = TT_Set_Instance_Resolutions( instance, RESOLUTION, RESOLUTION );
/* if(error)
{
Send_String("TT_Set_Instance_Resolution:");
Send_Num(error);
Send_String("\r\n");
return -1;
}*/
// kcmark
// set point size
//if( psTextAttr->iRotation == 90 || psTextAttr->iRotation == 270)
// ptsize = psTextAttr->iHoriMulti;
//else
ptsize = psTextAttr->iVertMulti;
error = TT_Set_Instance_PointSize( instance, ptsize );
if(error)
{
SendPrintf("TT_Set_Instance_PointSize:%d\r\n", error);
free ( pBuf );
return FALSE;
}
// }
// else //it's the same font
// {
// if(ptsize != psTextAttr->iVertMulti)
// {
// ptsize = psTextAttr->iVertMulti;
// error = TT_Set_Instance_PointSize( instance, ptsize );
// }
// }
// get glyph index for every byte in the input string
CharToUnicode(psTextAttr, pFontAttr->iCodePage);
//get (x,y)
x = psTextAttr->sCoord.iX;
y = psTextAttr->sCoord.iY;
i = TT_Char_Index( char_map, 'A'); //
LoadTrueTypeChar( i, hinted );
TT_Get_Glyph_Metrics( glyph, &ttf_metrics );
BearingY = ttf_metrics.bbox.yMax;
i = TT_Char_Index( char_map, 'y'); //
LoadTrueTypeChar( i, hinted );
TT_Get_Glyph_Metrics( glyph, &ttf_metrics );
//for erase box
iEraseHeight = (BearingY - ttf_metrics.bbox.yMin) >> 6;
iEraseWidth = 0;
//check OB ( )
for ( i = 0; i < num_codes; i++ )
{
error = LoadTrueTypeChar( glyph_code[i], hinted );
if(!error)
{
TT_Get_Glyph_Metrics( glyph, &ttf_metrics );
switch(psTextAttr->iRotation)
{
case 0:
if(error = Render_0_Glyph ( glyph, x, y ))
{
// #if defined( LCD_MODEL )
// ShowFont(0, 32,"Glyph Error");
// #endif
MakeInt(buf,error);
// #if defined( LCD_MODEL )
// ShowFont(0, 48,buf);
// #endif
//j=0;while(j<80000000L)j++;
}
if(LanguageID == LID_BIG5 &&
char_unicode[i] < 256)
x += ttf_metrics.advance/64/2;
else
x += ttf_metrics.advance/64;
break;
case 90:
Render_90_Glyph ( glyph, x, y );
if(LanguageID == LID_BIG5 &&
char_unicode[i] < 256)
y += ttf_metrics.advance/64/2;
else
y += ttf_metrics.advance/64;
break;
case 180:
Render_180_Glyph( glyph, x, y );
if(LanguageID == LID_BIG5 &&
char_unicode[i] < 256)
x -= ttf_metrics.advance/64/2;
else
x -= ttf_metrics.advance/64;
break;
case 270:
Render_270_Glyph( glyph, x, y );
if(LanguageID == LID_BIG5 &&
char_unicode[i] < 256)
y -= ttf_metrics.advance/64/2;
else
y -= ttf_metrics.advance/64;
break;
}
//inc bounding box width
if(LanguageID == LID_BIG5 &&
char_unicode[i] < 256)
iEraseWidth += ttf_metrics.advance/64/2;
else
iEraseWidth += ttf_metrics.advance/64;
}
}
// kcmark
iEraseWidth += ( ptsize >> 1 );
//get last line and firstline
switch( psTextAttr->iRotation )
{
case 0:
Hodify_iY = psTextAttr->sCoord.iY;
Hodify_Height = y + iEraseHeight - Hodify_iY;
// // Get the iFirstLine
// if ( psTextAttr->sCoord.iY < psTextAttr->psImageBuffer->iFirstLine )
// psTextAttr->psImageBuffer->iFirstLine = psTextAttr->sCoord.iY;
// // get iLastLine
// if ( y + iEraseHeight > psTextAttr->psImageBuffer->iLastLine )
// psTextAttr->psImageBuffer->iLastLine = y + iEraseHeight - 1;
break;
case 90:
Hodify_iY = psTextAttr->sCoord.iY;
Hodify_Height = y - Hodify_iY;
// Get the iFirstLine
// if ( psTextAttr->sCoord.iY < psTextAttr->psImageBuffer->iFirstLine )
// psTextAttr->psImageBuffer->iFirstLine = psTextAttr->sCoord.iY;
// // get iLastLine
// if ( y > psTextAttr->psImageBuffer->iLastLine )
// psTextAttr->psImageBuffer->iLastLine = y - 1;
break;
case 180:
Hodify_iY = y - iEraseHeight + 1;
Hodify_Height = y - Hodify_iY;
// // Get the iFirstLine
// if ( (y - iEraseHeight) < psTextAttr->psImageBuffer->iFirstLine )
// psTextAttr->psImageBuffer->iFirstLine = y - iEraseHeight + 1;
// // get iLastLine
// if ( y > psTextAttr->psImageBuffer->iLastLine )
// psTextAttr->psImageBuffer->iLastLine = y;
break;
case 270:
Hodify_iY = y - 1;
Hodify_Height = psTextAttr->sCoord.iY - Hodify_iY;
// // Get the iFirstLine
// if ( y < psTextAttr->psImageBuffer->iFirstLine )
// psTextAttr->psImageBuffer->iFirstLine = y - 1;
// // get iLastLine
// if ( y > psTextAttr->psImageBuffer->iLastLine )
// psTextAttr->psImageBuffer->iLastLine = psTextAttr->sCoord.iY;
break;
}
pFontAttr->iRealWidth = iEraseWidth;
pFontAttr->iRealHeight = iEraseHeight;
ModifyImgSection(Hodify_iY, Hodify_Height, psTextAttr->psImageBuffer);
TT_Close_Face(face);
free ( pBuf );
return TRUE;
}
int PreviewTTOutText(_TextAttr* psTextAttr, _FontAttr* pFontAttr)
{
int i;
TT_F26Dot6 x, y;
TT_Error error;
int iEraseHeight;
int iEraseWidth;
if(!Init_Engine())
{
free ( pBuf );
SendString("TTF malloc error");
return FALSE;
}
lpTTFGetData = pFontAttr->lpGetData;
lpTTFSetDataPoint = pFontAttr->lpSetDataPoint;
lpTTFGetDataPoint = pFontAttr->lpGetDataPoint;
lpTTFGetSize = pFontAttr->lpGetSize;
//initialize our own image buffer attributes
Bit.rows = psTextAttr->psImageBuffer->iHeight;
Bit.cols = psTextAttr->psImageBuffer->iByteWidth;
Bit.width = psTextAttr->psImageBuffer->iWidth;
Bit.flow = TT_Flow_Up;//TT_Flow_Down;
Bit.bitmap = psTextAttr->psImageBuffer->pBuffer;
Bit.size = Bit.rows * Bit.cols;
//hinted always
hinted = 1;
// Load new face
error = TT_Open_Face( engine, (char *)psTextAttr->pFont, &face );
if(error)
{
SendPrintf("TT_Open_Face:%d\r\n", error);
free ( pBuf );
return FALSE;
}
// get face properties and allocate preload arrays
TT_Get_Face_Properties( face, &properties );
// create glyph
error = TT_New_Glyph( face, &glyph );
// create instance
error = TT_New_Instance( face, &instance );
// set resolution, we could use this to expand width
error = TT_Set_Instance_Resolutions( instance, RESOLUTION, RESOLUTION );
ptsize = psTextAttr->iVertMulti;
error = TT_Set_Instance_PointSize( instance, ptsize );
if(error)
{
SendPrintf("TT_Set_Instance_PointSize:%d\r\n", error);
free ( pBuf );
return FALSE;
}
// get glyph index for every byte in the input string
CharToUnicode(psTextAttr, pFontAttr->iCodePage);
//get (x,y)
x = psTextAttr->sCoord.iX;
y = psTextAttr->sCoord.iY;
i = TT_Char_Index( char_map, 'A'); //
LoadTrueTypeChar( i, hinted );
TT_Get_Glyph_Metrics( glyph, &ttf_metrics );
BearingY = ttf_metrics.bbox.yMax;
i = TT_Char_Index( char_map, 'y'); //
LoadTrueTypeChar( i, hinted );
TT_Get_Glyph_Metrics( glyph, &ttf_metrics );
//for erase box
iEraseHeight = (BearingY - ttf_metrics.bbox.yMin) >> 6;
iEraseWidth = 0;
//check OB ( )
for ( i = 0; i < num_codes; i++ )
{
error = LoadTrueTypeChar( glyph_code[i], hinted );
if(!error)
{
TT_Get_Glyph_Metrics( glyph, &ttf_metrics );
//inc bounding box width
if(LanguageID == LID_BIG5 &&
char_unicode[i] < 256)
iEraseWidth += ttf_metrics.advance/64/2;
else
iEraseWidth += ttf_metrics.advance/64;
}
}
// kcmark
iEraseWidth += ( ptsize >> 1 );
pFontAttr->iRealWidth = iEraseWidth;
pFontAttr->iRealHeight = iEraseHeight;
TT_Close_Face(face);
free ( pBuf );
return TRUE;
}
ttfile.c 、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
/*******************************************************************
*
* ttfile.c (extended version) 2.1
*
* File I/O Component (body).
*
* Copyright 1996-1999 by
* David Turner, Robert Wilhelm, and Werner Lemberg
*
* This file is part of the FreeType project, and may only be used
* modified and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
* NOTES:
*
* This implementation relies on the ANSI libc. You may wish to
* modify it to get rid of libc and go straight to the your
* platform's stream routines.
*
* The same source code can be used for thread-safe and re-entrant
* builds of the library.
*
* Changes between 2.0 and 2.1 :
*
* - it is now possible to close a stream's file handle explicitely
* through the new API "TT_Flush_Stream". This will simply close
* a stream's file handle (useful to save system resources when
* dealing with lots of opened fonts). Of course, the function
* "TT_Use_Stream" will automatically re-open a stream's handle if
* necessary.
*
* - added "TT_Stream_Size" to replace "TT_File_Size" which wasn't
* used anyway. This one returns the size of any stream, even
* flushed one (when the previous TT_File_Size could only return
* the size of the current working stream). This is used by the
* new "Load_TrueType_Any" function in the tables loader.
*
******************************************************************/
#include "ttconfig.h"
//#include <stdio.h>
#include <string.h>
#ifdef HAVE_UNISTD_H
//#include <unistd.h>
#endif
// #include "..\file.h"
#include "freetype.h"
#include "tttypes.h"
#include "ttdebug.h"
#include "ttengine.h"
#include "ttmutex.h"
#include "ttmemory.h"
#include "ttfile.h" /* our prototypes */
#include "XFileSys.h"
/* required by the tracing mode */
#undef TT_COMPONENT
#define TT_COMPONENT trace_file
/* For now, we don't define additional error messages in the core library */
/* to report open-on demand errors. Define these error as standard ones */
#define TT_Err_Could_Not_ReOpen_File TT_Err_Could_Not_Open_File
#define TT_Err_Could_Not_ReSeek_File TT_Err_Could_Not_Open_File
/* This definition is mandatory for each file component! */
EXPORT_FUNC
const TFileFrame TT_Null_FileFrame = { NULL, 0, 0 };
/* It has proven useful to do some bounds checks during development phase. */
/* They should probably be undefined for speed reasons in a later release. */
#if defined (DEBUG_FILE)
#define CHECK_FRAME( frame, n ) \
do { \
if ( frame.cursor + n > frame.address + frame.size ) \
Panic( "Frame boundary error!\n" ); \
} while ( 0 )
#else
#define CHECK_FRAME( frame, n ) /* nothing */
#endif
/* Because a stream can be flushed, i.e. its file handle can be */
/* closed to save system resources, we must keep the stream's file */
/* pathname to be able to re-open it on demand when it is flushed */
struct TStream_Rec_;
typedef struct TStream_Rec_ TStream_Rec;
typedef TStream_Rec* PStream_Rec;
struct TStream_Rec_
{
Bool opened; /* is the stream handle opened ? */
TT_Text* name; /* the file's pathname */
Long position; /* current position within the file */
//FILE* file;
_FileHandle* file; /* file handle */
Long base; /* stream base in file */
Long size; /* stream size in file */
};
/* We support embedded TrueType files by allowing them to be */
/* inside any file, at any location, hence the 'base' argument. */
/* Note however that the current implementation does not allow you */
/* to specify a 'base' index when opening a file. */
/* (will come later) */
/* I still don't know if this will turn out useful ?? - DavidT */
#define STREAM2REC( x ) ( (TStream_Rec*)HANDLE_Val( x ) )
static TT_Error Stream_Activate ( PStream_Rec stream );
static TT_Error Stream_Deactivate( PStream_Rec stream );
#ifndef TT_CONFIG_OPTION_THREAD_SAFE
/*******************************************************************/
/*******************************************************************/
/*******************************************************************/
/**** ****/
/**** N O N R E E N T R A N T I M P L E M E N T A T I O N ****/
/**** ****/
/*******************************************************************/
/*******************************************************************/
/*******************************************************************/
/* in non-rentrant builds, we allocate a single block where we'll */
/* place all the frames smaller than FRAME_CACHE_SIZE, rather than */
/* allocating a new block on each access. Bigger frames will be */
/* malloced normally in the heap. */
/* */
/* See TT_Access_Frame() and TT_Forget_Frame() for details. */
#define FRAME_CACHE_SIZE 2048
/* The TFile_Component structure holds all the data that was */
/* previously declared static or global in this component. */
/* */
/* It is accessible through the 'engine.file_component' */
/* variable in re-entrant builds, or directly through the */
/* static 'files' variable in other builds. */
struct TFile_Component_
{
TMutex lock; /* used by the thread-safe build only */
Byte* frame_cache; /* frame cache */
PStream_Rec stream; /* current stream */
TFileFrame frame; /* current frame */
};
typedef struct TFile_Component_ TFile_Component;
static TFile_Component files;
#define CUR_Stream files.stream
#define CUR_Frame files.frame
#define STREAM_VARS /* void */
#define STREAM_VAR /* void */
/* The macro CUR_Stream denotes the current input stream. */
/* Note that for the re-entrant version, the 'stream' name has been */
/* chosen according to the macro STREAM_ARGS. */
/* The macro CUR_Frame denotes the current file frame. */
/* Note that for the re-entrant version, the 'frame' name has been */
/* chosen according to the macro FRAME_ARGS. */
/* The macro STREAM_VAR is used when calling public functions */
/* that need an 'optional' stream argument. */
/*******************************************************************
*
* Function : TTFile_Init
*
* Description : Initializes the File component.
*
******************************************************************/
LOCAL_FUNC
TT_Error TTFile_Init( PEngine_Instance engine )
{
TT_Error error;
MUTEX_Create( files.lock );
files.stream = NULL;
ZERO_Frame( files.frame );
if ( ALLOC( files.frame_cache, FRAME_CACHE_SIZE ) )
return error;
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : TTFile_Done
*
* Description : Finalizes the File component.
*
******************************************************************/
LOCAL_FUNC
TT_Error TTFile_Done( PEngine_Instance engine )
{
FREE( files.frame_cache );
MUTEX_Destroy( files.lock );
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : TT_Use_Stream
*
* Description : Copies or duplicates a given stream.
*
* Input : org_stream original stream
* stream target stream (copy or duplicate)
*
* Output : Error code.
*
******************************************************************/
EXPORT_FUNC
TT_Error TT_Use_Stream( TT_Stream org_stream,
TT_Stream* stream )
{
MUTEX_Lock( files.lock ); /* lock file mutex */
*stream = org_stream; /* copy the stream */
files.stream = STREAM2REC(org_stream); /* set current stream */
Stream_Activate( files.stream );
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : TT_Done_Stream
*
* Description : Releases a given stream.
*
* Input : stream target stream
*
* Output : Error code.
*
******************************************************************/
EXPORT_FUNC
TT_Error TT_Done_Stream( TT_Stream* stream )
{
HANDLE_Set( *stream, NULL );
MUTEX_Release( files.lock );
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : TT_Access_Frame
*
* Description : Notifies the component that we're going to read
* 'size' bytes from the current file position.
* This function should load/cache/map these bytes
* so that they will be addressed by the GET_xxx
* functions easily.
*
* Input : size number of bytes to access.
*
* Output : SUCCESS on success. FAILURE on error.
*
* Notes: The function fails if the byte range is not within the
* the file, or if there is not enough memory to cache
* the bytes properly (which usually means that `size' is
* too big in both cases).
*
******************************************************************/
EXPORT_FUNC
TT_Error TT_Access_Frame( STREAM_ARGS FRAME_ARGS Long size )
{
TT_Error error;
if ( CUR_Frame.address != NULL )
return TT_Err_Nested_Frame_Access;
if ( size <= FRAME_CACHE_SIZE )
{
/* use the cache */
CUR_Frame.address = files.frame_cache;
CUR_Frame.size = FRAME_CACHE_SIZE;
}
else
{
if ( ALLOC( CUR_Frame.address, size ) )
return error;
CUR_Frame.size = size;
}
error = TT_Read_File( STREAM_VARS (void*)CUR_Frame.address, size );
if (error)
{
if ( size > FRAME_CACHE_SIZE )
FREE( CUR_Frame.address );
CUR_Frame.address = NULL;
CUR_Frame.size = 0;
}
CUR_Frame.cursor = CUR_Frame.address;
return error;
}
/*******************************************************************
*
* Function : TT_Check_And_Access_Frame
*
* Description : Notifies the component that we're going to read
* `size' bytes from the current file position.
* This function should load/cache/map these bytes
* so that they will be addressed by the GET_xxx
* functions easily.
*
* Input : size number of bytes to access.
*
* Output : SUCCESS on success. FAILURE on error.
*
* Notes: The function truncates `size' if the byte range is not
* within the file.
*
* It will fail if there is not enough memory to cache
* the bytes properly (which usually means that `size' is
* too big).
*
* It will fail if you make two consecutive calls
* to TT_Access_Frame(), without a TT_Forget_Frame() between
* them.
*
* The only difference with TT_Access_Frame() is that we
* check that the frame is within the current file. We
* otherwise truncate it.
*
******************************************************************/
EXPORT_FUNC
TT_Error TT_Check_And_Access_Frame( STREAM_ARGS FRAME_ARGS Long size )
{
TT_Error error;
Long readBytes, requested;
if ( CUR_Frame.address != NULL )
return TT_Err_Nested_Frame_Access;
if ( size <= FRAME_CACHE_SIZE )
{
/* use the cache */
CUR_Frame.address = files.frame_cache;
CUR_Frame.size = FRAME_CACHE_SIZE;
}
else
{
if ( ALLOC( CUR_Frame.address, size ) )
return error;
CUR_Frame.size = size;
}
requested = size;
readBytes = CUR_Stream->size - TT_File_Pos( STREAM_VAR );
if ( size > readBytes )
size = readBytes;
error = TT_Read_File( STREAM_VARS (void*)CUR_Frame.address, size );
if (error)
{
if ( requested > FRAME_CACHE_SIZE )
FREE( CUR_Frame.address );
CUR_Frame.address = NULL;
CUR_Frame.size = 0;
}
CUR_Frame.cursor = CUR_Frame.address;
return error;
}
/*******************************************************************
*
* Function : TT_Forget_Frame
*
* Description : Releases a cached frame after reading.
*
* Input : None
*
* Output : SUCCESS on success. FAILURE on error.
*
******************************************************************/
EXPORT_FUNC
TT_Error TT_Forget_Frame( FRAME_ARG )
{
if ( CUR_Frame.address == NULL )
return TT_Err_Nested_Frame_Access;
if ( CUR_Frame.size > FRAME_CACHE_SIZE )
FREE( CUR_Frame.address );
ZERO_Frame( CUR_Frame );
return TT_Err_Ok;
}
#else /* TT_CONFIG_OPTION_THREAD_SAFE */
/*******************************************************************/
/*******************************************************************/
/*******************************************************************/
/******** ********/
/******** R E E N T R A N T I M P L E M E N T A T I O N ********/
/******** ********/
/*******************************************************************/
/*******************************************************************/
/*******************************************************************/
/* a simple macro to access the file component's data */
#define files ( *((TFile_Component*)engine.file_component) )
#define CUR_Stream STREAM2REC( stream ) /* re-entrant macros */
#define CUR_Frame (*frame)
#define STREAM_VARS stream,
#define STREAM_VAR stream
/*******************************************************************
*
* Function : TTFile_Init
*
* Description : Initializes the File component.
*
******************************************************************/
LOCAL_FUNC
TT_Error TTFile_Init( PEngine_Instance engine )
{
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : TTFile_Done
*
* Description : Finalizes the File component.
*
******************************************************************/
LOCAL_FUNC
TT_Error TTFile_Done( PEngine_Instance engine )
{
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : TT_Use_Stream
*
* Description : Duplicates a stream for a new usage.
*
* Input : input_stream source stream to duplicate
* copy address of target duplicate stream
*
* Output : error code.
* The target stream is set to NULL in case of failure.
*
******************************************************************/
EXPORT_FUNC
TT_Error TT_Use_Stream( TT_Stream input_stream,
TT_Stream* copy )
{
PStream_Rec rec = STREAM2REC( input_stream );
return TT_Open_Stream( rec->name, copy );
}
/*******************************************************************
*
* Function : TT_Done_Stream
*
* Description : Releases a given stream.
*
* Input : stream target stream
*
* Output :
*
******************************************************************/
EXPORT_FUNC
TT_Error TT_Done_Stream( TT_Stream* stream )
{
return TT_Close_Stream( stream );
}
/*******************************************************************
*
* Function : TT_Access_Frame
*
* Description : Notifies the component that we're going to read
* 'size' bytes from the current file position.
* This function should load/cache/map these bytes
* so that they will be addressed by the GET_xxx
* functions easily.
*
* Input : size number of bytes to access.
*
* Output : SUCCESS on success. FAILURE on error.
*
* Notes: The function fails if the byte range is not within the
* the file, or if there is not enough memory to cache
* the bytes properly (which usually means that `size' is
* too big in both cases).
*
******************************************************************/
EXPORT_FUNC
TT_Error TT_Access_Frame( STREAM_ARGS FRAME_ARGS Long size )
{
TT_Error error;
if ( CUR_Frame.address != NULL )
return TT_Err_Nested_Frame_Access;
if ( ALLOC( CUR_Frame.address, size ) )
return error;
CUR_Frame.size = size;
error = TT_Read_File( STREAM_VARS (void*)CUR_Frame.address, size );
if ( error )
{
FREE( CUR_Frame.address );
CUR_Frame.size = 0;
}
CUR_Frame.cursor = CUR_Frame.address;
return error;
}
/*******************************************************************
*
* Function : TT_Check_And_Access_Frame
*
* Description : Notifies the component that we're going to read
* `size' bytes from the current file position.
* This function should load/cache/map these bytes
* so that they will be addressed by the GET_xxx
* functions easily.
*
* Input : size number of bytes to access.
*
* Output : SUCCESS on success. FAILURE on error.
*
* Notes: The function truncates `size' if the byte range is not
* within the file.
*
* It will fail if there is not enough memory to cache
* the bytes properly (which usually means that `size' is
* too big).
*
* It will fail if you make two consecutive calls
* to TT_Access_Frame(), without a TT_Forget_Frame() between
* them.
*
* The only difference with TT_Access_Frame() is that we
* check that the frame is within the current file. We
* otherwise truncate it.
*
******************************************************************/
EXPORT_FUNC
TT_Error TT_Check_And_Access_Frame( STREAM_ARGS FRAME_ARGS Long size )
{
TT_Error error;
Long readBytes;
if ( CUR_Frame.address != NULL )
return TT_Err_Nested_Frame_Access;
if ( ALLOC( CUR_Frame.address, size ) )
return error;
CUR_Frame.size = size;
readBytes = CUR_Stream->size - TT_File_Pos( STREAM_VAR );
if ( size > readBytes )
size = readBytes;
error = TT_Read_File( STREAM_VARS (void*)CUR_Frame.address, size );
if ( error )
{
FREE( CUR_Frame.address );
CUR_Frame.size = 0;
}
CUR_Frame.cursor = CUR_Frame.address;
return error;
}
/*******************************************************************
*
* Function : TT_Forget_Frame
*
* Description : Releases a cached frame after reading.
*
* Input : None
*
* Output : SUCCESS on success. FAILURE on error.
*
******************************************************************/
EXPORT_FUNC
TT_Error TT_Forget_Frame( FRAME_ARG )
{
if ( CUR_Frame.address == NULL )
return TT_Err_Nested_Frame_Access;
FREE( CUR_Frame.address );
ZERO_Frame( CUR_Frame );
return TT_Err_Ok;
}
#endif /* TT_CONFIG_OPTION_THREAD_SAFE */
/*******************************************************************/
/*******************************************************************/
/*******************************************************************/
/*********** ***********/
/*********** C O M M O N I M P L E M E N T A T I O N ***********/
/*********** ***********/
/*******************************************************************/
/*******************************************************************/
/*******************************************************************/
/*******************************************************************
*
* Function : Stream_Activate
*
* Description : activates a stream, this will either:
* - open a new file handle if the stream is closed
* - move the stream to the head of the linked list
*
* Input : stream the stream to activate
*
* Output : error condition.
*
* Note : This function is also called with fresh new streams
* created by TT_Open_Stream(). They have their 'size'
* field set to -1.
*
******************************************************************/
static TT_Error Stream_Activate( PStream_Rec stream )
{
if ( !stream->opened )
{
// if ( (stream->file = fopen( (TT_Text*)stream->name, "rb" )) == 0 )
// if ( (stream->file = fopen( FLASH_DEVICE,(byte *)stream->name)) == 0 )
// if ( (stream->file = fopen( NO_SELECT_DEVICE,(unsigned char *)stream->name)) == 0 ) return TT_Err_Could_Not_ReOpen_File;
stream->opened = TRUE;
/* A newly created stream has a size field of -1 */
if ( stream->size < 0 )
{
//fseek( stream->file, 0, SEEK_END );
//stream->size = ftell( stream->file );
//fseek( stream->file, 0, SEEK_SET );
// stream->size = stream->file->Size;
stream->size = lpTTFGetSize();
}
/* Reset cursor in file */
if ( stream->position )
{
// if ( fseek( stream->file, stream->position, SEEK_SET ) != 0 )
// if ( fseek( stream->file, stream->position ) != 0 )
// {
// /* error during seek */
// fclose( stream->file );
// stream->opened = FALSE;
// return TT_Err_Could_Not_ReSeek_File;
// }
fseek( stream->file, stream->position ) ;
}
}
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : Stream_DeActivate
*
* Description : deactivates a stream, this will :
* - close its file handle if it was opened
* - remove it from the opened list if necessary
*
* Input : stream the stream to deactivate
*
* Output : Error condition
*
* Note : the function is called whenever a stream is deleted
* (_not_ when a stream handle's is closed due to an
* activation). However, the stream record isn't
* destroyed by it..
*
******************************************************************/
static TT_Error Stream_Deactivate( PStream_Rec stream )
{
if ( stream->opened )
{
/* Save its current position within the file */
stream->position = ftell( stream->file );
fclose( stream->file );
stream->file = 0;
stream->opened = FALSE;
}
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : TT_Stream_Size
*
* Description : Returns the length of a given stream, even if it
* is flushed.
*
* Input : stream the stream
*
* Output : Length of stream in bytes.
*
******************************************************************/
EXPORT_FUNC
Long TT_Stream_Size( TT_Stream stream )
{
PStream_Rec rec = STREAM2REC( stream );
if ( rec )
return rec->size;
else
return 0; /* invalid stream - return 0 */
}
/*******************************************************************
*
* Function : TT_Open_Stream
*
* Description : Opens the font file and saves the total file size.
*
* Input : error address of stream's error variable
* (re-entrant build only)
* filepathname pathname of the file to open
* stream address of target TT_Stream structure
*
* Output : SUCCESS on sucess, FAILURE on error.
* The target stream is set to -1 in case of failure.
*
******************************************************************/
LOCAL_FUNC
TT_Error TT_Open_Stream( const TT_Text* filepathname,
TT_Stream* stream )
{
Int len;
TT_Error error;
PStream_Rec stream_rec;
if ( ALLOC( *stream, sizeof ( TStream_Rec ) ) )
return error;
stream_rec = STREAM2REC( *stream );
stream_rec->file = NULL;
stream_rec->size = -1L;
stream_rec->base = 0;
stream_rec->opened = FALSE;
stream_rec->position = 0;
len = strlen( filepathname ) + 1;
if ( ALLOC( stream_rec->name, len ) )
goto Fail;
strncpy( stream_rec->name, filepathname, len );
error = Stream_Activate( stream_rec );
if ( error )
goto Fail_Activate;
#ifndef TT_CONFIG_OPTION_THREAD_SAFE
CUR_Stream = stream_rec;
#endif
return TT_Err_Ok;
Fail_Activate:
FREE( stream_rec->name );
Fail:
FREE( stream_rec );
return error;
}
/*******************************************************************
*
* Function : TT_Close_Stream
*
* Description : Closes a stream.
*
* Input : stream address of target TT_Stream structure
*
* Output : SUCCESS (always).
*
******************************************************************/
LOCAL_FUNC
TT_Error TT_Close_Stream( TT_Stream* stream )
{
PStream_Rec rec = STREAM2REC( *stream );
Stream_Deactivate( rec );
FREE( rec->name );
FREE( rec );
HANDLE_Set( *stream, NULL );
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : TT_Flush_Stream
*
* Description : Flushes a stream, i.e., closes its file handle.
*
* Input : stream address of target TT_Stream structure
*
* Output : Error code
*
* NOTE : Never flush the current opened stream. This means that
* you should _never_ call this function between a
* TT_Use_Stream() and a TT_Done_Stream()!
*
******************************************************************/
EXPORT_FUNC
TT_Error TT_Flush_Stream( TT_Stream* stream )
{
PStream_Rec rec = STREAM2REC( *stream );
if ( rec )
{
Stream_Deactivate( rec );
return TT_Err_Ok;
}
else
return TT_Err_Invalid_Argument;
}
/*******************************************************************
*
* Function : TT_Seek_File
*
* Description : Seeks the file cursor to a different position.
*
* Input : position new position in file
*
* Output : SUCCESS on success. FAILURE if out of range.
*
******************************************************************/
EXPORT_FUNC
TT_Error TT_Seek_File( STREAM_ARGS Long position )
{
position += CUR_Stream->base;
// if ( fseek( CUR_Stream->file, position, SEEK_SET ) )
// if ( fseek( CUR_Stream->file, position) )
// return TT_Err_Invalid_File_Offset;
fseek( CUR_Stream->file, position);
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : TT_Skip_File
*
* Description : Skips forward the file cursor.
*
* Input : distance number of bytes to skip
*
* Output : see TT_Seek_File()
*
******************************************************************/
EXPORT_FUNC
TT_Error TT_Skip_File( STREAM_ARGS Long distance )
{
return TT_Seek_File( STREAM_VARS lpTTFGetDataPoint() -
CUR_Stream->base + distance );
}
/*******************************************************************
*
* Function : TT_Read_File
*
* Description : Reads a chunk of the file and copies it to memory.
*
* Input : buffer target buffer
* count length in bytes to read
*
* Output : SUCCESS on success. FAILURE if out of range.
*
******************************************************************/
EXPORT_FUNC
TT_Error TT_Read_File( STREAM_ARGS void* buffer, Long count )
{
lpTTFGetData(buffer, count);
// if ( fread( buffer, 1, count, CUR_Stream->file ) != (ULong)count )
// return TT_Err_Invalid_File_Read;
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : TT_Read_At_File
*
* Description : Reads file at a specified position.
*
* Input : position position to seek to before read
* buffer target buffer
* count number of bytes to read
*
* Output : SUCCESS on success. FAILURE if error.
*
******************************************************************/
EXPORT_FUNC
TT_Error TT_Read_At_File( STREAM_ARGS Long position,
void* buffer,
Long count )
{
TT_Error error;
if ( (error = TT_Seek_File( STREAM_VARS position )) != TT_Err_Ok ||
(error = TT_Read_File( STREAM_VARS buffer, count )) != TT_Err_Ok )
return error;
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : TT_File_Pos
*
* Description : Returns current file seek pointer.
*
* Input : none
*
* Output : Current file position.
*
******************************************************************/
EXPORT_FUNC
Long TT_File_Pos( STREAM_ARG )
{
return lpTTFGetDataPoint() - CUR_Stream->base;
}
/*******************************************************************
*
* Function : GET_Byte
*
* Description : Extracts a byte from the current file frame.
*
* Input : None or current frame
*
* Output : Extracted Byte.
*
******************************************************************/
#if 0
EXPORT_FUNC
Byte TT_Get_Byte( FRAME_ARG )
{
CHECK_FRAME( CUR_Frame, 1 );
return (Byte)(*CUR_Frame.cursor++);
}
#endif
/*******************************************************************
*
* Function : GET_Char
*
* Description : Extracts a signed byte from the current file frame.
*
* Input : None or current frame
*
* Output : Extracted char.
*
******************************************************************/
EXPORT_FUNC
Char TT_Get_Char( FRAME_ARG )
{
CHECK_FRAME( CUR_Frame, 1 );
return (Char)(*CUR_Frame.cursor++);
}
/*******************************************************************
*
* Function : GET_Short
*
* Description : Extracts a short from the current file frame.
*
* Input : None or current frame
*
* Output : Extracted short.
*
******************************************************************/
EXPORT_FUNC
Short TT_Get_Short( FRAME_ARG )
{
Short getshort;
CHECK_FRAME( CUR_Frame, 2 );
getshort = (Short)((CUR_Frame.cursor[0] << 8) |
CUR_Frame.cursor[1]);
CUR_Frame.cursor += 2;
return getshort;
}
/*******************************************************************
*
* Function : GET_UShort
*
* Description : Extracts an unsigned short from the frame.
*
* Input : None or current frame
*
* Output : Extracted ushort.
*
******************************************************************/
#if 0
EXPORT_FUNC
UShort TT_Get_UShort( FRAME_ARG )
{
UShort getshort;
CHECK_FRAME( CUR_Frame, 2 );
getshort = (UShort)((CUR_Frame.cursor[0] << 8) |
CUR_Frame.cursor[1]);
CUR_Frame.cursor += 2;
return getshort;
}
#endif
/*******************************************************************
*
* Function : GET_Long
*
* Description : Extracts a long from the frame.
*
* Input : None or current frame
*
* Output : Extracted long.
*
******************************************************************/
EXPORT_FUNC
Long TT_Get_Long( FRAME_ARG )
{
Long getlong;
CHECK_FRAME( CUR_Frame, 4 );
getlong = ((Long)CUR_Frame.cursor[0] << 24) |
((Long)CUR_Frame.cursor[1] << 16) |
((Long)CUR_Frame.cursor[2] << 8 ) |
(Long)CUR_Frame.cursor[3];
CUR_Frame.cursor += 4;
return getlong;
}
/*******************************************************************
*
* Function : GET_ULong
*
* Description : Extracts an unsigned long from the frame.
*
* Input : None or current frame
*
* Output : Extracted ulong.
*
******************************************************************/
#if 0
EXPORT_FUNC
ULong TT_Get_ULong( FRAME_ARG )
{
ULong getlong;
CHECK_FRAME( CUR_Frame, 4 );
getlong = ( ((ULong)CUR_Frame.cursor[0] << 24) |
((ULong)CUR_Frame.cursor[1] << 16) |
((ULong)CUR_Frame.cursor[2] << 8 ) |
(ULong)CUR_Frame.cursor[3] );
CUR_Frame.cursor += 4;
return getlong;
}
#endif
/* END */