home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: SysTools
/
SysTools.zip
/
ft-beta.zip
/
freetype
/
lib
/
ttobjs.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-10-06
|
31KB
|
1,146 lines
/*******************************************************************
*
* ttobjs.c 1.0
*
* Objects manager.
*
* Copyright 1996, 1997 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 "ttfile.h"
#include "ttcalc.h"
#include "ttmemory.h"
#include "ttload.h"
#include "ttinterp.h"
/* Add extensions definition */
#ifdef TT_EXTEND_ENGINE
#include "ttextend.h"
#endif
/*******************************************************************
*
* Function : New_Context
*
* Description : Creates a new execution context for a given
* face objet.
*
******************************************************************/
PExecution_Context New_Context( PFace face )
{
PExecution_Context exec;
if (!face)
return NULL;
CACHE_New( &face->contexts, exec, face );
return exec;
}
/*******************************************************************
*
* Function : Done_Context
*
* Description : discards an execution context
*
******************************************************************/
TT_Error Done_Context( PExecution_Context exec )
{
if (!exec)
return TT_Err_Ok;
return CACHE_Done( &exec->owner->contexts, exec );
}
/*******************************************************************
*
* Function : New_Instance
*
* Description : Creates a new instance for a given face objet
*
******************************************************************/
PInstance New_Instance( PFace face )
{
PInstance ins;
if (!face)
return NULL;
CACHE_New( &face->instances, ins, face );
return ins;
}
/*******************************************************************
*
* Function : Done_Instance
*
* Description :
*
******************************************************************/
TT_Error Done_Instance( PInstance instance )
{
return CACHE_Done( &instance->owner->instances, instance );
}
/*******************************************************************
* *
* CODERANGE FUNCTIONS *
* *
* *
*******************************************************************/
/*******************************************************************
*
* Function : Goto_CodeRange
*
* Description : Switch to a new code range (updates Code and IP).
*
* Input : exec target execution context
* range new execution code range
* IP new IP in new code range
*
* Output : SUCCESS on success. FAILURE on error (no code range).
*
*****************************************************************/
TT_Error Goto_CodeRange( PExecution_Context exec, Int range, Int IP )
{
PCodeRange cr;
if ( range < 1 || range > 3 )
return TT_Err_Bad_Argument;
cr = &exec->codeRangeTable[ range-1 ];
if ( cr->Base == NULL )
return TT_Err_Invalid_Coderange;
/* NOTE : Because the last instruction of a program may be a CALL */
/* which will return to the first byte *after* the code */
/* range, we test for IP <= Size, instead of IP < Size. */
if ( IP > cr->Size )
return TT_Err_Code_Overflow;
exec->code = cr->Base;
exec->codeSize = cr->Size;
exec->IP = IP;
exec->curRange = range;
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : Get_CodeRange
*
* Description : Returns a pointer to a given code range. Should
* be used only by the debugger. Returns NULL if
* 'range' is out of current bounds.
*
* Input : exec target execution context
* range new execution code range
*
* Output : Pointer to the code range record. NULL on failure.
*
*****************************************************************/
PCodeRange Get_CodeRange( PExecution_Context exec, Int range )
{
if ( range < 1 || range > 3 )
return NULL;
else /* arrays start with 1 in pas, and with 0 in c */
return &exec->codeRangeTable[ range-1 ];
}
/*******************************************************************
*
* Function : Set_CodeRange
*
* Description : Sets a code range.
*
* Input : exec target execution context
* range code range index
* base new code base
* length sange size in bytes
*
* Output : SUCCESS on success. FAILURE on error.
*
*****************************************************************/
TT_Error Set_CodeRange( PExecution_Context exec,
Int range,
void* base,
Int length )
{
if ( range < 1 || range > 3 )
return TT_Err_Bad_Argument;
exec->codeRangeTable[ range-1 ].Base = (unsigned char*)base;
exec->codeRangeTable[ range-1 ].Size = length;
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : Clear_CodeRange
*
* Description : clears a code range.
*
* Input : exec target execution context
* range code range index
*
* Output : SUCCESS on success. FAILURE on error.
*
* Notes : Does not set the Error variable.
*
*****************************************************************/
TT_Error Clear_CodeRange( PExecution_Context exec, Int range )
{
if ( range < 1 || range > 3 )
return TT_Err_Bad_Argument;
exec->codeRangeTable[ range-1 ].Base = NULL;
exec->codeRangeTable[ range-1 ].Size = 0;
return TT_Err_Ok;
}
/*******************************************************************
* *
* EXECUTION CONTEXT ROUTINES *
* *
* *
*******************************************************************/
/*******************************************************************
*
* Function : Context_Destroy
*
*****************************************************************/
TT_Error Context_Destroy( void* _context )
{
PExecution_Context exec = (PExecution_Context)_context;
if (!exec)
return TT_Err_Ok;
/* free composite load stack */
FREE( exec->loadStack );
/* contours array */
FREE( exec->endContours );
exec->numContours = 0;
/* points zone */
FREE( exec->pts.touch );
FREE( exec->pts.cur_y );
FREE( exec->pts.cur_x );
FREE( exec->pts.org_y );
FREE( exec->pts.org_x );
exec->pts.n = 0;
/* twilight zone */
FREE( exec->twilight.touch );
FREE( exec->twilight.cur_y );
FREE( exec->twilight.cur_x );
FREE( exec->twilight.org_y );
FREE( exec->twilight.org_x );
exec->twilight.n = 0;
/* free stack */
FREE( exec->stack );
exec->stackSize = 0;
/* free storage area */
FREE( exec->storage );
exec->storeSize = 0;
/* free call stack */
FREE( exec->callStack );
exec->callSize = 0;
exec->callTop = 0;
/* free glyph code range */
FREE( exec->glyphIns );
exec->glyphSize = 0;
exec->instance = NULL;
exec->owner = NULL;
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : Context_Create
*
*****************************************************************/
TT_Error Context_Create( void* _context, void* _face )
{
PExecution_Context exec = (PExecution_Context)_context;
PFace face = (PFace)_face;
TMaxProfile* maxp = &face->maxProfile;
TT_Error error;
Int n_points, n_twilight;
exec->callSize = 32;
exec->storeSize = maxp->maxStorage;
exec->stackSize = maxp->maxStackElements;
n_points = face->maxPoints + 2;
n_twilight = maxp->maxTwilightPoints;
if ( ALLOC( exec->glyphIns, maxp->maxSizeOfInstructions ) ||
/* reserve glyph code range */
ALLOC_ARRAY( exec->callStack, exec->callSize, TCallRecord ) ||
/* reserve interpreter call stack */
ALLOC_ARRAY( exec->storage, exec->storeSize, Long ) ||
/* reserve storage area */
ALLOC_ARRAY( exec->stack, exec->stackSize, Long ) ||
/* reserve interpreter stack */
ALLOC_ARRAY( exec->pts.org_x, n_points, TT_F26Dot6 ) ||
ALLOC_ARRAY( exec->pts.org_y, n_points, TT_F26Dot6 ) ||
ALLOC_ARRAY( exec->pts.cur_x, n_points, TT_F26Dot6 ) ||
ALLOC_ARRAY( exec->pts.cur_y, n_points, TT_F26Dot6 ) ||
ALLOC( exec->pts.touch, n_points ) ||
/* reserve points zone */
ALLOC_ARRAY( exec->twilight.org_x, n_twilight, TT_F26Dot6 ) ||
ALLOC_ARRAY( exec->twilight.org_y, n_twilight, TT_F26Dot6 ) ||
ALLOC_ARRAY( exec->twilight.cur_x, n_twilight, TT_F26Dot6 ) ||
ALLOC_ARRAY( exec->twilight.cur_y, n_twilight, TT_F26Dot6 ) ||
ALLOC( exec->twilight.touch, n_twilight ) ||
/* reserve twilight zone */
ALLOC_ARRAY( exec->endContours, face->maxContours, UShort ) ||
/* reserve contours array */
ALLOC_ARRAY( exec->loadStack, face->maxComponents+1, TSubglyph_Record ))
goto Fail_Memory;
exec->twilight.n = n_twilight;
exec->owner = face;
exec->instance = NULL;
return TT_Err_Ok;
Fail_Memory :
Context_Destroy( exec );
return error;
}
/*******************************************************************
*
* Function : Context_Load
*
*****************************************************************/
TT_Error Context_Load( PExecution_Context exec,
PInstance ins )
{
Int i;
exec->instance = ins;
exec->numFDefs = ins->numFDefs;
exec->numIDefs = ins->numIDefs;
exec->FDefs = ins->FDefs;
exec->IDefs = ins->IDefs;
exec->metrics = ins->metrics;
for ( i = 0; i < MAX_CODE_RANGES; i++ )
exec->codeRangeTable[i] = ins->codeRangeTable[i];
exec->pts.n = 0;
exec->numContours = 0;
exec->instruction_trap = FALSE;
/* set default graphics state */
exec->GS = ins->GS;
exec->cvtSize = ins->cvtSize;
exec->cvt = ins->cvt;
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : Context_Save
*
*****************************************************************/
TT_Error Context_Save( PExecution_Context exec,
PInstance ins )
{
Int i;
for ( i = 0; i < MAX_CODE_RANGES; i++ )
ins->codeRangeTable[i] = exec->codeRangeTable[i];
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : Context_Run
*
*****************************************************************/
TT_Error Context_Run( PExecution_Context exec,
Bool debug )
{
TT_Error error;
if ( (error = Goto_CodeRange( exec, TT_CodeRange_Glyph, 0 ) ))
return error;
exec->zp0 = exec->pts;
exec->zp1 = exec->pts;
exec->zp2 = exec->pts;
exec->GS.gep0 = 1;
exec->GS.gep1 = 1;
exec->GS.gep2 = 1;
exec->GS.projVector.x = 0x4000;
exec->GS.projVector.y = 0x0000;
exec->GS.freeVector = exec->GS.projVector;
exec->GS.dualVector = exec->GS.projVector;
exec->GS.round_state = 1;
exec->GS.loop = 1;
exec->top = 0;
exec->callTop = 0;
/* some glyphs leave something on the stack. so we clean it */
/* before a new execution.. */
if (!debug)
return RunIns( exec );
else
return TT_Err_Ok;
}
const TGraphicsState Default_GraphicsState =
{
0, 0, 0,
{ 0x4000, 0 },
{ 0x4000, 0 },
{ 0x4000, 0 },
1, 64, 1,
TRUE, 68, 0, 0, 9, 3,
0, FALSE, 2, 1, 1, 1
};
/*******************************************************************
* *
* INSTANCE FUNCTIONS *
* *
* *
*******************************************************************/
/*******************************************************************
*
* Function : Instance_Destroy
*
* Description :
*
* Input : _instance the instance object to destroy
*
* Output : error code.
*
******************************************************************/
TT_Error Instance_Destroy( void* _instance )
{
PInstance ins = (PInstance)_instance;
if (!_instance)
return TT_Err_Ok;
if ( ins->debug )
{
/* the debug context must be deleted by the debugger itself */
ins->context = NULL;
ins->debug = FALSE;
}
FREE( ins->cvt );
ins->cvtSize = 0;
FREE( ins->FDefs );
FREE( ins->IDefs );
ins->numFDefs = 0;
ins->numIDefs = 0;
ins->owner = NULL;
ins->valid = FALSE;
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : Instance_Create
*
* Description :
*
* Input : _instance instance record to initialize
* _face parent face object
*
* Output : Error code. All partially built subtables are
* released on error..
*
******************************************************************/
TT_Error Instance_Create( void* _instance,
void* _face )
{
PInstance ins = (PInstance)_instance;
PFace face = (PFace)_face;
TT_Error error;
Int i;
PMaxProfile maxp = &face->maxProfile;
ins->owner = face;
ins->valid = FALSE;
ins->numFDefs = maxp->maxFunctionDefs;
ins->numIDefs = maxp->maxInstructionDefs;
ins->cvtSize = face->cvtSize;
ins->metrics.pointSize = 10 * 64; /* default pointsize = 10 pts */
ins->metrics.x_resolution = 96; /* default resolution = 96 dpi */
ins->metrics.y_resolution = 96;
ins->metrics.x_ppem = 0;
ins->metrics.y_ppem = 0;
ins->metrics.rotated = FALSE;
ins->metrics.stretched = FALSE;
for (i=0; i <4; i++)
ins->metrics.compensations[i] = 0; /* Default compensations */
if ( ALLOC_ARRAY( ins->FDefs, ins->numFDefs, TDefRecord ) ||
ALLOC_ARRAY( ins->IDefs, ins->numIDefs, TDefRecord ) ||
ALLOC_ARRAY( ins->cvt, ins->cvtSize, Long ) )
goto Fail_Memory;
ins->GS = Default_GraphicsState;
return TT_Err_Ok;
Fail_Memory :
Instance_Destroy( ins );
return error;
}
/*******************************************************************
*
* Function : Instance_Init
*
* Description : Initialize a fresh new instance.
* Executes the font program if any is found..
*
* Input : _instance the instance object to destroy
*
* Output : error code.
*
******************************************************************/
TT_Error Instance_Init( PInstance ins )
{
PExecution_Context exec;
TT_Error error;
PFace face = ins->owner;
if (ins->debug)
exec = ins->context;
else
exec = New_Context(face);
/* debugging instances have their own context */
if (!exec)
return TT_Err_Could_Not_Find_Context;
ins->GS = Default_GraphicsState;
Context_Load( exec, ins );
exec->callTop = 0;
exec->top = 0;
exec->period = 64;
exec->phase = 0;
exec->threshold = 0;
exec->metrics.x_ppem = 0;
exec->metrics.y_ppem = 0;
exec->metrics.pointSize = 0;
exec->metrics.x_scale1 = 0;
exec->metrics.x_scale2 = 1;
exec->metrics.y_scale1 = 0;
exec->metrics.y_scale2 = 1;
exec->instruction_trap = FALSE;
exec->cvtSize = ins->cvtSize;
exec->cvt = ins->cvt;
exec->F_dot_P = 0x10000;
Set_CodeRange( exec,
TT_CodeRange_Font,
face->fontProgram,
face->fontPgmSize );
/* allow font program execution */
Clear_CodeRange( exec, TT_CodeRange_Cvt );
Clear_CodeRange( exec, TT_CodeRange_Glyph );
/* disable CVT and glyph programs coderange */
if ( face->fontPgmSize > 0 )
{
error = Goto_CodeRange( exec, TT_CodeRange_Font, 0 );
if ( error )
goto Fin;
error = RunIns( exec );
}
else
error = TT_Err_Ok;
Fin:
Context_Save( exec, ins );
if (!ins->debug)
Done_Context( exec );
/* debugging instances keep their context */
ins->valid = FALSE;
return error;
}
/*******************************************************************
*
* Function : Instance_Reset
*
* Description : Reset an instance to a new pointsize/transform.
* Executes the cvt program if any is found..
*
* Input : _instance the instance object to destroy
*
* Output : error code.
*
******************************************************************/
TT_Error Instance_Reset( PInstance ins,
Bool debug )
{
PExecution_Context exec;
TT_Error error;
Int i;
PFace face;
if (!ins)
return TT_Err_Invalid_Instance_Handle;
if ( ins->valid )
return TT_Err_Ok;
face = ins->owner;
/* compute new transform */
ins->metrics.x_ppem = ( (ins->metrics.pointSize/64) *
ins->metrics.x_resolution + 36 ) / 72;
ins->metrics.y_ppem = ( (ins->metrics.pointSize/64) *
ins->metrics.y_resolution + 36 ) / 72;
ins->metrics.x_scale1 = ins->metrics.x_ppem * 64;
ins->metrics.y_scale1 = ins->metrics.y_ppem * 64;
ins->metrics.x_scale2 = face->fontHeader.Units_Per_EM;
ins->metrics.y_scale2 = face->fontHeader.Units_Per_EM;
/* scale the cvt values to the new ppem */
for ( i = 0; i < ins->cvtSize; i++ )
ins->cvt[i] = MulDiv_Round( face->cvt[i],
ins->metrics.y_scale1,
ins->metrics.y_scale2 );
/* We use by default the y ppem to scale the CVT */
ins->GS = Default_GraphicsState;
/* get execution context and run prep program */
if (ins->debug)
exec = ins->context;
else
exec = New_Context(face);
/* debugging instances have their own context */
if (!exec)
return TT_Err_Could_Not_Find_Context;
Context_Load( exec, ins );
Set_CodeRange( exec,
TT_CodeRange_Cvt,
face->cvtProgram,
face->cvtPgmSize );
Clear_CodeRange( exec, TT_CodeRange_Glyph );
for ( i = 0; i < exec->storeSize; i++ )
exec->storage[i] = 0;
exec->instruction_trap = FALSE;
exec->top = 0;
exec->callTop = 0;
/* All twilight points are originally zero */
for ( i = 0; i < exec->twilight.n; i++ )
{
exec->twilight.org_x[i] = 0;
exec->twilight.org_y[i] = 0;
exec->twilight.cur_x[i] = 0;
exec->twilight.cur_y[i] = 0;
}
if ( face->cvtPgmSize > 0 )
{
error = Goto_CodeRange( exec, TT_CodeRange_Cvt, 0 );
if (error)
goto Fin;
if (!ins->debug)
error = RunIns( exec );
}
else
error = TT_Err_Ok;
ins->GS = exec->GS;
/* save default graphics state */
Fin:
Context_Save( exec, ins );
if (!ins->debug)
Done_Context(exec);
/* debugging instances keep their context */
if (!error)
ins->valid = TRUE;
return error;
}
/*******************************************************************
* *
* FACE FUNCTIONS *
* *
* *
*******************************************************************/
/*******************************************************************
*
* Function : Face_Destroy
*
* Description : The face objet destructor
*
* Input : _face typeless pointer to the face object to destroy
*
* Output : Error code.
*
******************************************************************/
TT_Error Face_Destroy( void* _face )
{
PFace face = (PFace)_face;
Int n;
if (!face)
return TT_Err_Ok;
MUTEX_Lock(face->lock);
/* well, we assume that no other thread is using the face */
/* at this moment, but one is never sure enough.. */
/* first of all, destroys the cached sub-objects */
Cache_Destroy( &face->instances );
Cache_Destroy( &face->contexts );
/* freeing the collection table */
FREE( face->ttcHeader.TableDirectory );
face->ttcHeader.DirCount = 0;
/* freeing table directory */
FREE( face->dirTables );
face->numTables = 0;
/* freeing the locations table */
FREE( face->glyphLocations );
face->numLocations = 0;
/* freeing the character mapping tables */
for ( n = 0; n < face->numCMaps; n++ )
CharMap_Free( face->cMaps + n );
FREE( face->cMaps );
face->numCMaps = 0;
/* freeing the CVT */
FREE( face->cvt );
face->cvtSize = 0;
/* freeing the horizontal metrics */
FREE( face->longHMetrics );
FREE( face->shortMetrics );
/* freeing the programs */
FREE( face->fontProgram );
FREE( face->cvtProgram );
face->fontPgmSize = 0;
face->cvtPgmSize = 0;
/* freeing the gasp table */
FREE( face->gasp.gaspRanges );
face->gasp.numRanges = 0;
/* freeing the name table */
Free_TrueType_Names( face );
#ifdef TT_EXTEND_ENGINE
Extension_Destroy( face );
#endif
TT_Close_Stream( &face->stream );
MUTEX_Destroy(face->lock);
/* destroy the mutex */
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : Face_Create
*
* Description : the face object constructor.
*
* Input : _face face record to build
* _input input stream where to load font data
*
* Output : Error code
*
* NOTE : the input stream is kept in the face object. the
* caller shouldn't destroy it after calling Face_Create.
*
******************************************************************/
#define LOAD_( table ) \
( error = Load_TrueType_##table (face) )
TT_Error Face_Create( void* _face,
void* _input )
{
TFont_Input* input = (TFont_Input*)_input;
PFace face = (PFace)_face;
TT_Error error;
face->stream = input->stream;
MUTEX_Create( face->lock );
Cache_Create( engine.objs_instance_class, &face->instances, &face->lock );
Cache_Create( engine.objs_execution_class, &face->contexts, &face->lock );
/* Load collection directory if present, then font directory */
if ( (error = Load_TrueType_Directory( face, input->fontIndex )) )
goto Fail;
/* Load tables */
if ( LOAD_(Header) ||
LOAD_(MaxProfile) ||
LOAD_(Locations) ||
LOAD_(CMap) ||
LOAD_(CVT) ||
LOAD_(Horizontal_Header) ||
LOAD_(Programs) ||
LOAD_(HMTX) ||
LOAD_(Gasp) ||
LOAD_(Names) ||
LOAD_(OS2) ||
LOAD_(PostScript) )
goto Fail;
#ifdef TT_EXTEND_ENGINE
if ( (error = Extension_Create( face )) )
return error;
#endif
return TT_Err_Ok;
Fail :
Face_Destroy( face );
return error;
}
/*******************************************************************
*
* Function : Glyph_Destroy
*
* Description : The glyph objet destructor
*
* Input : _glyph typeless pointer to the glyph record to destroy
*
* Output : Error code.
*
******************************************************************/
TT_Error Glyph_Destroy( void* _glyph )
{
PGlyph glyph = (PGlyph)_glyph;
if (!glyph)
return TT_Err_Ok;
FREE( glyph->endContours );
FREE( glyph->touch );
FREE( glyph->y_coord );
FREE( glyph->x_coord );
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : Glyph_Create
*
* Description : the face object constructor.
*
* Input : _glyph gylph record to build.
* _face the glyph's parent face.
*
* Output : Error code
*
******************************************************************/
TT_Error Glyph_Create( void* _glyph,
void* _face )
{
TT_Error error;
PFace face = (PFace)_face;
PGlyph glyph = (PGlyph)_glyph;
if (!face)
return TT_Err_Invalid_Face_Handle;
if (!glyph)
return TT_Err_Invalid_Glyph_Handle;
glyph->face = face;
glyph->num_points = 0;
glyph->num_contours = 0;
glyph->high_precision = TRUE;
glyph->scan_type = 2;
if ( ALLOC_ARRAY( glyph->x_coord, face->maxPoints+2, TT_F26Dot6 ) ||
ALLOC_ARRAY( glyph->y_coord, face->maxPoints+2, TT_F26Dot6 ) ||
ALLOC_ARRAY( glyph->touch, face->maxPoints+2, Byte ) ||
ALLOC_ARRAY( glyph->endContours, face->maxContours, UShort ) )
goto Fail;
return TT_Err_Ok;
Fail:
Glyph_Destroy(glyph);
return error;
}
/*******************************************************************
*
* Function : TTObjs_Init
*
* Description : TTObjs component initializer. Creates the
* object cache classes, as well as the face record
* cache.
*
* Input : None
*
* Output : Error code.
*
******************************************************************/
TT_Error TTObjs_Init()
{
PCache_Class instances, contexts, faces, glyphs;
PCache face_cache, glyph_cache;
TT_Error error;
instances = NULL;
contexts = NULL;
faces = NULL;
glyphs = NULL;
glyph_cache = NULL;
face_cache = NULL;
if ( !ALLOC( instances, sizeof(TCache_Class) ) &&
!ALLOC( contexts, sizeof(TCache_Class) ) &&
!ALLOC( faces, sizeof(TCache_Class) ) &&
!ALLOC( glyphs, sizeof(TCache_Class) ) &&
!ALLOC( glyph_cache, sizeof(TCache) ) &&
!ALLOC( face_cache, sizeof(TCache) ) )
{
/* create the face cache class */
faces->object_size = sizeof(TFace);
faces->idle_limit = -1; /* no recycling of face objects */
faces->init = Face_Create;
faces->done = Face_Destroy;
engine.objs_face_class = faces;
/* create the instance cache class */
instances->object_size = sizeof(TInstance);
instances->idle_limit = 2;
instances->init = Instance_Create;
instances->done = Instance_Destroy;
engine.objs_instance_class = instances;
/* create the execution context cache class */
contexts->object_size = sizeof(TExecution_Context);
contexts->idle_limit = 1;
contexts->init = Context_Create;
contexts->done = Context_Destroy;
engine.objs_execution_class = contexts;
glyphs->object_size = sizeof(TGlyph);
glyphs->idle_limit = -1; /* no recycling of glyph objects */
glyphs->init = Glyph_Create;
glyphs->done = Glyph_Destroy;
engine.objs_glyph_class = glyphs;
/* create face and glyph 'caches'. These are used only */
/* for tracking purpose. No recycling is performed */
Cache_Create( faces, face_cache, &engine.lock );
Cache_Create( glyphs, glyph_cache, &engine.lock );
engine.objs_face_cache = face_cache;
engine.objs_glyph_cache = glyph_cache;
}
else
{
FREE( face_cache );
FREE( glyph_cache );
FREE( glyphs );
FREE( faces );
FREE( contexts );
FREE( instances );
}
return error;
}
TT_Error TTObjs_Done()
{
/* destroy all active faces and glyphs before releasing the */
/* caches */
Cache_Destroy( (TCache*)engine.objs_face_cache );
Cache_Destroy( (TCache*)engine.objs_glyph_cache );
/* No frees caches and cache classes */
FREE( engine.objs_face_cache );
FREE( engine.objs_glyph_cache );
FREE( engine.objs_glyph_class );
FREE( engine.objs_execution_class );
FREE( engine.objs_instance_class );
FREE( engine.objs_face_class );
return TT_Err_Ok;
}