1496 lines
38 KiB
C
1496 lines
38 KiB
C
/*******************************************************************
|
|
*
|
|
* ttobjs.c 1.0
|
|
*
|
|
* Objects manager.
|
|
*
|
|
* 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 "ttfile.h"
|
|
#include "ttcalc.h"
|
|
#include "ttmemory.h"
|
|
#include "ttload.h"
|
|
#include "ttinterp.h"
|
|
#include "ttdebug.h"
|
|
|
|
|
|
/* Add extensions definition */
|
|
#ifdef TT_CONFIG_OPTION_EXTEND_ENGINE
|
|
#include "ttextend.h"
|
|
#endif
|
|
|
|
/* Required by tracing mode */
|
|
#undef TT_COMPONENT
|
|
#define TT_COMPONENT trace_objs
|
|
|
|
/*******************************************************************
|
|
*
|
|
* Function : New_Context
|
|
*
|
|
* Description : Creates a new execution context for a given
|
|
* face object.
|
|
*
|
|
******************************************************************/
|
|
|
|
LOCAL_FUNC
|
|
PExecution_Context New_Context( PFace face )
|
|
{
|
|
PEngine_Instance engine;
|
|
PExecution_Context exec;
|
|
|
|
|
|
if ( !face )
|
|
return NULL;
|
|
|
|
engine = face->engine;
|
|
CACHE_New( engine->objs_exec_cache, exec, face );
|
|
return exec;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
*
|
|
* Function : Done_Context
|
|
*
|
|
* Description : Discards an execution context.
|
|
*
|
|
******************************************************************/
|
|
|
|
LOCAL_FUNC
|
|
TT_Error Done_Context( PExecution_Context exec )
|
|
{
|
|
PEngine_Instance engine;
|
|
|
|
|
|
if ( !exec )
|
|
return TT_Err_Ok;
|
|
|
|
engine = exec->face->engine;
|
|
return CACHE_Done( engine->objs_exec_cache, exec );
|
|
}
|
|
|
|
|
|
#if 0
|
|
|
|
/*******************************************************************
|
|
*
|
|
* Function : New_Instance
|
|
*
|
|
* Description : Creates a new instance for a given face object.
|
|
*
|
|
******************************************************************/
|
|
|
|
LOCAL_FUNC
|
|
PInstance New_Instance( PFace face )
|
|
{
|
|
PInstance ins;
|
|
|
|
|
|
if ( !face )
|
|
return NULL;
|
|
|
|
CACHE_New( &face->instances, ins, face );
|
|
|
|
return ins;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
*
|
|
* Function : Done_Instance
|
|
*
|
|
* Description : Discards an instance.
|
|
*
|
|
******************************************************************/
|
|
|
|
LOCAL_FUNC
|
|
TT_Error Done_Instance( PInstance instance )
|
|
{
|
|
return CACHE_Done( &instance->owner->instances, instance );
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/*******************************************************************
|
|
* *
|
|
* GLYPH ZONE FUNCTIONS *
|
|
* *
|
|
* *
|
|
*******************************************************************/
|
|
|
|
/*******************************************************************
|
|
*
|
|
* Function : New_Glyph_Zone
|
|
*
|
|
* Description : Allocates a new glyph zone
|
|
*
|
|
* Input : pts pointer to the target glyph zone record
|
|
* maxPoints capacity of glyph zone in points
|
|
* maxContours capacity of glyph zone in contours
|
|
*
|
|
* Return : Error code.
|
|
*
|
|
*****************************************************************/
|
|
|
|
static
|
|
TT_Error New_Glyph_Zone( PGlyph_Zone pts,
|
|
UShort maxPoints,
|
|
UShort maxContours )
|
|
{
|
|
TT_Error error;
|
|
|
|
|
|
if ( ALLOC( pts->org, maxPoints * 2 * sizeof ( TT_F26Dot6 ) ) ||
|
|
ALLOC( pts->cur, maxPoints * 2 * sizeof ( TT_F26Dot6 ) ) ||
|
|
ALLOC( pts->touch, maxPoints * sizeof ( Byte ) ) ||
|
|
ALLOC( pts->contours, maxContours * sizeof ( Short ) ) )
|
|
return error;
|
|
|
|
return TT_Err_Ok;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
*
|
|
* Function : Done_Glyph_Zone
|
|
*
|
|
* Description : Deallocates a glyph zone
|
|
*
|
|
* Input : pts pointer to the target glyph zone record
|
|
*
|
|
* Return : Error code.
|
|
*
|
|
*****************************************************************/
|
|
|
|
static
|
|
TT_Error Done_Glyph_Zone( PGlyph_Zone pts )
|
|
{
|
|
FREE( pts->contours );
|
|
FREE( pts->touch );
|
|
FREE( pts->cur );
|
|
FREE( pts->org );
|
|
|
|
return TT_Err_Ok;
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************
|
|
* *
|
|
* 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).
|
|
*
|
|
*****************************************************************/
|
|
|
|
LOCAL_FUNC
|
|
TT_Error Goto_CodeRange( PExecution_Context exec,
|
|
Int range,
|
|
ULong 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;
|
|
}
|
|
|
|
|
|
#if 0
|
|
|
|
/*******************************************************************
|
|
*
|
|
* 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.
|
|
*
|
|
*****************************************************************/
|
|
|
|
LOCAL_FUNC
|
|
PCodeRange Get_CodeRange( PExecution_Context exec, Int range )
|
|
{
|
|
if ( range < 1 || range > 3 )
|
|
return NULL;
|
|
else /* arrays start with 1 in Pascal, and with 0 in C */
|
|
return &exec->codeRangeTable[range - 1];
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/*******************************************************************
|
|
*
|
|
* Function : Set_CodeRange
|
|
*
|
|
* Description : Sets a code range.
|
|
*
|
|
* Input : exec target execution context
|
|
* range code range index
|
|
* base new code base
|
|
* length range size in bytes
|
|
*
|
|
* Output : SUCCESS on success. FAILURE on error.
|
|
*
|
|
*****************************************************************/
|
|
|
|
LOCAL_FUNC
|
|
TT_Error Set_CodeRange( PExecution_Context exec,
|
|
Int range,
|
|
void* base,
|
|
ULong length )
|
|
{
|
|
if ( range < 1 || range > 3 )
|
|
return TT_Err_Bad_Argument;
|
|
|
|
exec->codeRangeTable[range - 1].Base = (Byte*)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.
|
|
*
|
|
* Note : Does not set the Error variable.
|
|
*
|
|
*****************************************************************/
|
|
|
|
LOCAL_FUNC
|
|
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
|
|
*
|
|
*****************************************************************/
|
|
|
|
LOCAL_FUNC
|
|
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 );
|
|
exec->loadSize = 0;
|
|
|
|
/* points zone */
|
|
Done_Glyph_Zone( &exec->pts );
|
|
exec->maxPoints = 0;
|
|
exec->maxContours = 0;
|
|
|
|
/* free stack */
|
|
FREE( exec->stack );
|
|
exec->stackSize = 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->face = NULL;
|
|
|
|
return TT_Err_Ok;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
*
|
|
* Function : Context_Create
|
|
*
|
|
*****************************************************************/
|
|
|
|
LOCAL_FUNC
|
|
TT_Error Context_Create( void* _context, void* _face )
|
|
{
|
|
PExecution_Context exec = (PExecution_Context)_context;
|
|
|
|
PFace face = (PFace)_face;
|
|
TT_Error error;
|
|
|
|
|
|
/* XXX : We don't reserve arrays anymore, this is done automatically */
|
|
/* during a "Context_Load".. */
|
|
|
|
exec->callSize = 32;
|
|
if ( ALLOC_ARRAY( exec->callStack, exec->callSize, TCallRecord ) )
|
|
goto Fail_Memory;
|
|
|
|
/* all values in the context are set to 0 already, but this is */
|
|
/* here as a remainder */
|
|
exec->maxPoints = 0;
|
|
exec->maxContours = 0;
|
|
|
|
exec->stackSize = 0;
|
|
exec->loadSize = 0;
|
|
exec->glyphSize = 0;
|
|
|
|
exec->stack = NULL;
|
|
exec->loadStack = NULL;
|
|
exec->glyphIns = NULL;
|
|
|
|
exec->face = face;
|
|
exec->instance = NULL;
|
|
|
|
return TT_Err_Ok;
|
|
|
|
Fail_Memory:
|
|
Context_Destroy( exec );
|
|
return error;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
*
|
|
* Function : Context_Load
|
|
*
|
|
*****************************************************************/
|
|
|
|
/****************************************************************/
|
|
/* */
|
|
/* Update_Max : Reallocate a buffer if it needs to */
|
|
/* */
|
|
/* input: size address of buffer's current size */
|
|
/* expressed in elements */
|
|
/* */
|
|
/* multiplier size in bytes of each element in the */
|
|
/* buffer */
|
|
/* */
|
|
/* buff address of the buffer base pointer */
|
|
/* */
|
|
/* new_max new capacity (size) of the buffer */
|
|
|
|
static
|
|
TT_Error Update_Max( ULong* size,
|
|
ULong multiplier,
|
|
void** buff,
|
|
ULong new_max )
|
|
{
|
|
TT_Error error;
|
|
|
|
if ( *size < new_max )
|
|
{
|
|
FREE( *buff );
|
|
if ( ALLOC( *buff, new_max * multiplier ) )
|
|
return error;
|
|
*size = new_max;
|
|
}
|
|
return TT_Err_Ok;
|
|
}
|
|
|
|
|
|
/****************************************************************/
|
|
/* */
|
|
/* Update_Zone: Reallocate a zone if it needs to */
|
|
/* */
|
|
/* input: zone address of the target zone */
|
|
/* */
|
|
/* maxPoints address of the zone's current capacity */
|
|
/* in points */
|
|
/* */
|
|
/* maxContours address of the zone's current capacity */
|
|
/* in contours */
|
|
/* */
|
|
/* newPoints new capacity in points */
|
|
/* */
|
|
/* newContours new capacity in contours */
|
|
/* */
|
|
|
|
static
|
|
TT_Error Update_Zone( PGlyph_Zone zone,
|
|
UShort* maxPoints,
|
|
UShort* maxContours,
|
|
UShort newPoints,
|
|
UShort newContours )
|
|
{
|
|
if ( *maxPoints < newPoints || *maxContours < newContours )
|
|
{
|
|
TT_Error error;
|
|
|
|
|
|
Done_Glyph_Zone( zone );
|
|
|
|
error = New_Glyph_Zone( zone, newPoints, newContours );
|
|
if ( error )
|
|
return error;
|
|
|
|
*maxPoints = newPoints;
|
|
*maxContours = newContours;
|
|
}
|
|
return TT_Err_Ok;
|
|
}
|
|
|
|
|
|
LOCAL_FUNC
|
|
TT_Error Context_Load( PExecution_Context exec,
|
|
PFace face,
|
|
PInstance ins )
|
|
{
|
|
Int i;
|
|
TMaxProfile* maxp;
|
|
TT_Error error;
|
|
|
|
exec->face = face;
|
|
maxp = &face->maxProfile;
|
|
|
|
exec->instance = ins;
|
|
|
|
if ( ins )
|
|
{
|
|
exec->numFDefs = ins->numFDefs;
|
|
exec->numIDefs = ins->numIDefs;
|
|
exec->maxFDefs = ins->maxFDefs;
|
|
exec->maxIDefs = ins->maxIDefs;
|
|
exec->FDefs = ins->FDefs;
|
|
exec->IDefs = ins->IDefs;
|
|
exec->metrics = ins->metrics;
|
|
|
|
exec->maxFunc = ins->maxFunc;
|
|
exec->maxIns = ins->maxIns;
|
|
|
|
for ( i = 0; i < MAX_CODE_RANGES; i++ )
|
|
exec->codeRangeTable[i] = ins->codeRangeTable[i];
|
|
|
|
/* set graphics state */
|
|
exec->GS = ins->GS;
|
|
|
|
exec->cvtSize = ins->cvtSize;
|
|
exec->cvt = ins->cvt;
|
|
|
|
exec->storeSize = ins->storeSize;
|
|
exec->storage = ins->storage;
|
|
|
|
exec->twilight = ins->twilight;
|
|
}
|
|
|
|
error = Update_Max( &exec->loadSize,
|
|
sizeof ( TSubglyph_Record ),
|
|
(void**)&exec->loadStack,
|
|
face->maxComponents + 1 );
|
|
if ( error )
|
|
return error;
|
|
|
|
error = Update_Max( &exec->stackSize,
|
|
sizeof ( TT_F26Dot6 ),
|
|
(void**)&exec->stack,
|
|
maxp->maxStackElements + 32 );
|
|
/* XXX : We reserve a little more elements on the stack to deal safely */
|
|
/* with broken fonts like arialbs, courbs, timesbs... */
|
|
if ( error )
|
|
return error;
|
|
|
|
error = Update_Max( &exec->glyphSize,
|
|
sizeof ( Byte ),
|
|
(void**)&exec->glyphIns,
|
|
maxp->maxSizeOfInstructions );
|
|
if ( error )
|
|
return error;
|
|
|
|
error = Update_Zone( &exec->pts,
|
|
&exec->maxPoints,
|
|
&exec->maxContours,
|
|
exec->face->maxPoints + 2,
|
|
exec->face->maxContours );
|
|
/* XXX : We reserve two positions for the phantom points! */
|
|
if ( error )
|
|
return error;
|
|
|
|
exec->pts.n_points = 0;
|
|
exec->pts.n_contours = 0;
|
|
|
|
exec->instruction_trap = FALSE;
|
|
|
|
return TT_Err_Ok;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
*
|
|
* Function : Context_Save
|
|
*
|
|
*****************************************************************/
|
|
|
|
LOCAL_FUNC
|
|
TT_Error Context_Save( PExecution_Context exec,
|
|
PInstance ins )
|
|
{
|
|
Int i;
|
|
|
|
/* XXXX : Will probably disappear soon with all the coderange */
|
|
/* management, which is now rather obsolete. */
|
|
|
|
ins->numFDefs = exec->numFDefs;
|
|
ins->numIDefs = exec->numIDefs;
|
|
ins->maxFunc = exec->maxFunc;
|
|
ins->maxIns = exec->maxIns;
|
|
|
|
for ( i = 0; i < MAX_CODE_RANGES; i++ )
|
|
ins->codeRangeTable[i] = exec->codeRangeTable[i];
|
|
|
|
return TT_Err_Ok;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
*
|
|
* Function : Context_Run
|
|
*
|
|
*****************************************************************/
|
|
|
|
LOCAL_FUNC
|
|
TT_Error Context_Run( PExecution_Context exec,
|
|
Bool debug )
|
|
{
|
|
TT_Error error;
|
|
|
|
|
|
if ( (error = Goto_CodeRange( exec,
|
|
TT_CodeRange_Glyph, 0 )) != TT_Err_Ok )
|
|
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;
|
|
|
|
/* some glyphs leave something on the stack. so we clean it */
|
|
/* before a new execution. */
|
|
exec->top = 0;
|
|
exec->callTop = 0;
|
|
|
|
if ( !debug )
|
|
return RunIns( exec );
|
|
else
|
|
return TT_Err_Ok;
|
|
}
|
|
|
|
|
|
LOCAL_FUNC
|
|
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.
|
|
*
|
|
******************************************************************/
|
|
|
|
LOCAL_FUNC
|
|
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 storage area */
|
|
FREE( ins->storage );
|
|
ins->storeSize = 0;
|
|
|
|
/* twilight zone */
|
|
Done_Glyph_Zone( &ins->twilight );
|
|
|
|
FREE( ins->FDefs );
|
|
FREE( ins->IDefs );
|
|
ins->numFDefs = 0;
|
|
ins->numIDefs = 0;
|
|
ins->maxFDefs = 0;
|
|
ins->maxIDefs = 0;
|
|
ins->maxFunc = -1;
|
|
ins->maxIns = -1;
|
|
|
|
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.
|
|
*
|
|
******************************************************************/
|
|
|
|
LOCAL_FUNC
|
|
TT_Error Instance_Create( void* _instance,
|
|
void* _face )
|
|
{
|
|
PInstance ins = (PInstance)_instance;
|
|
PFace face = (PFace)_face;
|
|
TT_Error error;
|
|
Int i;
|
|
UShort n_twilight;
|
|
|
|
PMaxProfile maxp = &face->maxProfile;
|
|
|
|
|
|
ins->owner = face;
|
|
ins->valid = FALSE;
|
|
|
|
ins->maxFDefs = maxp->maxFunctionDefs;
|
|
ins->maxIDefs = maxp->maxInstructionDefs;
|
|
ins->cvtSize = face->cvtSize;
|
|
ins->storeSize = maxp->maxStorage;
|
|
|
|
/* Set default metrics */
|
|
{
|
|
PIns_Metrics metrics = &ins->metrics;
|
|
|
|
|
|
metrics->pointSize = 10 * 64; /* default pointsize = 10pts */
|
|
|
|
metrics->x_resolution = 96; /* default resolution = 96dpi */
|
|
metrics->y_resolution = 96;
|
|
|
|
metrics->x_ppem = 0;
|
|
metrics->y_ppem = 0;
|
|
|
|
metrics->rotated = FALSE;
|
|
metrics->stretched = FALSE;
|
|
|
|
/* set default compensation ( all 0 ) */
|
|
for ( i = 0; i < 4; i++ )
|
|
metrics->compensations[i] = 0;
|
|
}
|
|
|
|
/* allocate function defs, instruction defs, cvt and storage area */
|
|
if ( ALLOC_ARRAY( ins->FDefs, ins->maxFDefs, TDefRecord ) ||
|
|
ALLOC_ARRAY( ins->IDefs, ins->maxIDefs, TDefRecord ) ||
|
|
ALLOC_ARRAY( ins->cvt, ins->cvtSize, Long ) ||
|
|
ALLOC_ARRAY( ins->storage, ins->storeSize, Long ) )
|
|
goto Fail_Memory;
|
|
|
|
/* reserve twilight zone */
|
|
n_twilight = maxp->maxTwilightPoints;
|
|
error = New_Glyph_Zone( &ins->twilight, n_twilight, 0 );
|
|
if (error)
|
|
goto Fail_Memory;
|
|
|
|
ins->twilight.n_points = n_twilight;
|
|
|
|
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.
|
|
*
|
|
******************************************************************/
|
|
|
|
LOCAL_FUNC
|
|
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;
|
|
|
|
ins->numFDefs = 0;
|
|
ins->numIDefs = 0;
|
|
ins->maxFunc = -1;
|
|
ins->maxIns = -1;
|
|
|
|
Context_Load( exec, face, ins );
|
|
|
|
exec->callTop = 0;
|
|
exec->top = 0;
|
|
|
|
exec->period = 64;
|
|
exec->phase = 0;
|
|
exec->threshold = 0;
|
|
|
|
{
|
|
PIns_Metrics metrics = &exec->metrics;
|
|
|
|
|
|
metrics->x_ppem = 0;
|
|
metrics->y_ppem = 0;
|
|
metrics->pointSize = 0;
|
|
metrics->x_scale1 = 0;
|
|
metrics->x_scale2 = 1;
|
|
metrics->y_scale1 = 0;
|
|
metrics->y_scale2 = 1;
|
|
|
|
metrics->ppem = 0;
|
|
metrics->scale1 = 0;
|
|
metrics->scale2 = 1;
|
|
metrics->ratio = 1L << 16;
|
|
}
|
|
|
|
exec->instruction_trap = FALSE;
|
|
|
|
exec->cvtSize = ins->cvtSize;
|
|
exec->cvt = ins->cvt;
|
|
|
|
exec->F_dot_P = 0x10000;
|
|
|
|
/* allow font program execution */
|
|
Set_CodeRange( exec,
|
|
TT_CodeRange_Font,
|
|
face->fontProgram,
|
|
face->fontPgmSize );
|
|
|
|
/* disable CVT and glyph programs coderange */
|
|
Clear_CodeRange( exec, TT_CodeRange_Cvt );
|
|
Clear_CodeRange( exec, TT_CodeRange_Glyph );
|
|
|
|
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 : Resets 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.
|
|
*
|
|
******************************************************************/
|
|
|
|
LOCAL_FUNC
|
|
TT_Error Instance_Reset( PInstance ins )
|
|
{
|
|
PExecution_Context exec;
|
|
|
|
TT_Error error;
|
|
ULong i;
|
|
UShort j;
|
|
PFace face;
|
|
|
|
|
|
if ( !ins )
|
|
return TT_Err_Invalid_Instance_Handle;
|
|
|
|
if ( ins->valid )
|
|
return TT_Err_Ok;
|
|
|
|
face = ins->owner;
|
|
|
|
if ( ins->metrics.x_ppem < 1 ||
|
|
ins->metrics.y_ppem < 1 )
|
|
return TT_Err_Invalid_PPem;
|
|
|
|
/* compute new transformation */
|
|
if ( ins->metrics.x_ppem >= ins->metrics.y_ppem )
|
|
{
|
|
ins->metrics.scale1 = ins->metrics.x_scale1;
|
|
ins->metrics.scale2 = ins->metrics.x_scale2;
|
|
ins->metrics.ppem = ins->metrics.x_ppem;
|
|
ins->metrics.x_ratio = 1L << 16;
|
|
ins->metrics.y_ratio = TT_MulDiv( ins->metrics.y_ppem,
|
|
0x10000,
|
|
ins->metrics.x_ppem );
|
|
}
|
|
else
|
|
{
|
|
ins->metrics.scale1 = ins->metrics.y_scale1;
|
|
ins->metrics.scale2 = ins->metrics.y_scale2;
|
|
ins->metrics.ppem = ins->metrics.y_ppem;
|
|
ins->metrics.x_ratio = TT_MulDiv( ins->metrics.x_ppem,
|
|
0x10000,
|
|
ins->metrics.y_ppem );
|
|
ins->metrics.y_ratio = 1L << 16;
|
|
}
|
|
|
|
/* Scale the cvt values to the new ppem. */
|
|
/* We use by default the y ppem to scale the CVT. */
|
|
|
|
for ( i = 0; i < ins->cvtSize; i++ )
|
|
ins->cvt[i] = TT_MulDiv( face->cvt[i],
|
|
ins->metrics.scale1,
|
|
ins->metrics.scale2 );
|
|
|
|
/* All twilight points are originally zero */
|
|
for ( j = 0; j < ins->twilight.n_points; j++ )
|
|
{
|
|
ins->twilight.org[j].x = 0;
|
|
ins->twilight.org[j].y = 0;
|
|
ins->twilight.cur[j].x = 0;
|
|
ins->twilight.cur[j].y = 0;
|
|
}
|
|
|
|
/* clear storage area */
|
|
for ( i = 0; i < ins->storeSize; i++ )
|
|
ins->storage[i] = 0;
|
|
|
|
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, face, ins );
|
|
|
|
Set_CodeRange( exec,
|
|
TT_CodeRange_Cvt,
|
|
face->cvtProgram,
|
|
face->cvtPgmSize );
|
|
|
|
Clear_CodeRange( exec, TT_CodeRange_Glyph );
|
|
|
|
exec->instruction_trap = FALSE;
|
|
|
|
exec->top = 0;
|
|
exec->callTop = 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 object destructor.
|
|
*
|
|
* Input : _face typeless pointer to the face object to destroy
|
|
*
|
|
* Output : Error code.
|
|
*
|
|
******************************************************************/
|
|
|
|
LOCAL_FUNC
|
|
TT_Error Face_Destroy( void* _face )
|
|
{
|
|
PFace face = (PFace)_face;
|
|
UShort n;
|
|
|
|
|
|
if ( !face )
|
|
return TT_Err_Ok;
|
|
|
|
/* well, we assume that no other thread is using the face */
|
|
/* at this moment, but one is never sure enough. */
|
|
MUTEX_Lock( face->lock );
|
|
|
|
/* first of all, destroys the cached sub-objects */
|
|
Cache_Destroy( &face->instances );
|
|
Cache_Destroy( &face->glyphs );
|
|
|
|
/* destroy the extensions */
|
|
#ifdef TT_CONFIG_OPTION_EXTEND_ENGINE
|
|
Extension_Destroy( face );
|
|
#endif
|
|
|
|
/* 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->horizontalHeader.long_metrics );
|
|
FREE( face->horizontalHeader.short_metrics );
|
|
|
|
/* freeing the vertical ones, if any */
|
|
if (face->verticalInfo)
|
|
{
|
|
FREE( face->verticalHeader.long_metrics );
|
|
FREE( face->verticalHeader.short_metrics );
|
|
face->verticalInfo = 0;
|
|
}
|
|
|
|
/* 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 );
|
|
|
|
/* freeing the hdmx table */
|
|
Free_TrueType_Hdmx( face );
|
|
|
|
/* TT_Close_Stream( &face->stream ); -- this is performed by the API */
|
|
|
|
/* destroy the mutex */
|
|
MUTEX_Destroy(face->lock);
|
|
|
|
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().
|
|
*
|
|
******************************************************************/
|
|
|
|
#undef LOAD_
|
|
#define LOAD_( table ) \
|
|
(error = Load_TrueType_##table (face)) != TT_Err_Ok
|
|
|
|
|
|
LOCAL_FUNC
|
|
TT_Error Face_Create( void* _face,
|
|
void* _input )
|
|
{
|
|
PEngine_Instance engine;
|
|
|
|
TFont_Input* input = (TFont_Input*)_input;
|
|
PFace face = (PFace)_face;
|
|
TT_Error error;
|
|
|
|
|
|
face->stream = input->stream;
|
|
face->engine = input->engine;
|
|
|
|
engine = face->engine;
|
|
|
|
MUTEX_Create( face->lock );
|
|
|
|
Cache_Create( engine,
|
|
engine->objs_instance_class,
|
|
&face->instances,
|
|
&face->lock );
|
|
|
|
Cache_Create( engine,
|
|
engine->objs_glyph_class,
|
|
&face->glyphs,
|
|
&face->lock );
|
|
|
|
/* Load collection directory if present, then font directory */
|
|
|
|
error = Load_TrueType_Directory( face, input->fontIndex );
|
|
if ( error )
|
|
goto Fail;
|
|
|
|
/* Load tables */
|
|
|
|
if ( LOAD_( Header ) ||
|
|
LOAD_( MaxProfile ) ||
|
|
LOAD_( Locations ) ||
|
|
|
|
(error = Load_TrueType_Metrics_Header( face, 0 )) != TT_Err_Ok ||
|
|
/* load the 'hhea' & 'hmtx' tables at once */
|
|
|
|
LOAD_( CMap ) ||
|
|
LOAD_( CVT ) ||
|
|
LOAD_( Programs ) ||
|
|
LOAD_( Gasp ) ||
|
|
LOAD_( Names ) ||
|
|
LOAD_( OS2 ) ||
|
|
LOAD_( PostScript ) ||
|
|
|
|
(error = Load_TrueType_Metrics_Header( face, 1 )) != TT_Err_Ok ||
|
|
/* try to load the 'vhea' & 'vmtx' at once if present */
|
|
|
|
LOAD_( Hdmx ) )
|
|
|
|
goto Fail;
|
|
|
|
#ifdef TT_CONFIG_OPTION_EXTEND_ENGINE
|
|
if ( ( error = Extension_Create( face ) ) != TT_Err_Ok )
|
|
return error;
|
|
#endif
|
|
|
|
return TT_Err_Ok;
|
|
|
|
Fail :
|
|
Face_Destroy( face );
|
|
return error;
|
|
}
|
|
|
|
#undef LOAD_
|
|
|
|
|
|
/*******************************************************************
|
|
*
|
|
* Function : Glyph_Destroy
|
|
*
|
|
* Description : The glyph object destructor.
|
|
*
|
|
* Input : _glyph typeless pointer to the glyph record to destroy
|
|
*
|
|
* Output : Error code.
|
|
*
|
|
******************************************************************/
|
|
|
|
LOCAL_FUNC
|
|
TT_Error Glyph_Destroy( void* _glyph )
|
|
{
|
|
PGlyph glyph = (PGlyph)_glyph;
|
|
|
|
|
|
if ( !glyph )
|
|
return TT_Err_Ok;
|
|
|
|
glyph->outline.owner = TRUE;
|
|
return TT_Done_Outline( &glyph->outline );
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
*
|
|
* Function : Glyph_Create
|
|
*
|
|
* Description : The glyph object constructor.
|
|
*
|
|
* Input : _glyph glyph record to build.
|
|
* _face the glyph's parent face.
|
|
*
|
|
* Output : Error code.
|
|
*
|
|
******************************************************************/
|
|
|
|
LOCAL_FUNC
|
|
TT_Error Glyph_Create( void* _glyph,
|
|
void* _face )
|
|
{
|
|
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;
|
|
|
|
/* XXX: Don't forget the space for the 2 phantom points */
|
|
return TT_New_Outline( glyph->face->maxPoints + 2,
|
|
glyph->face->maxContours,
|
|
&glyph->outline );
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
*
|
|
* Function : Scale_X
|
|
*
|
|
* Description : scale an horizontal distance from font
|
|
* units to 26.6 pixels
|
|
*
|
|
* Input : metrics pointer to metrics
|
|
* x value to scale
|
|
*
|
|
* Output : scaled value
|
|
*
|
|
******************************************************************/
|
|
|
|
LOCAL_FUNC
|
|
TT_Pos Scale_X( PIns_Metrics metrics, TT_Pos x )
|
|
{
|
|
return TT_MulDiv( x, metrics->x_scale1, metrics->x_scale2 );
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
*
|
|
* Function : Scale_Y
|
|
*
|
|
* Description : scale a vertical distance from font
|
|
* units to 26.6 pixels
|
|
*
|
|
* Input : metrics pointer to metrics
|
|
* y value to scale
|
|
*
|
|
* Output : scaled value
|
|
*
|
|
******************************************************************/
|
|
|
|
LOCAL_FUNC
|
|
TT_Pos Scale_Y( PIns_Metrics metrics, TT_Pos y )
|
|
{
|
|
return TT_MulDiv( y, metrics->y_scale1, metrics->y_scale2 );
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
*
|
|
* Function : TTObjs_Init
|
|
*
|
|
* Description : The TTObjs component initializer. Creates the
|
|
* object cache classes, as well as the face record
|
|
* cache.
|
|
*
|
|
* Input : engine engine instance
|
|
*
|
|
* Output : Error code.
|
|
*
|
|
******************************************************************/
|
|
|
|
static
|
|
const TCache_Class objs_face_class =
|
|
{
|
|
sizeof ( TFace ),
|
|
-1,
|
|
Face_Create,
|
|
Face_Destroy,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
static
|
|
const TCache_Class objs_instance_class =
|
|
{
|
|
sizeof ( TInstance ),
|
|
-1,
|
|
Instance_Create,
|
|
Instance_Destroy,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
/* Note that we use a cache size of 1 for the execution context. */
|
|
/* This is to avoid re-creating a new context each time we */
|
|
/* change one instance's attribute (resolution and/or char sizes) */
|
|
/* or when we load a glyph. */
|
|
|
|
static
|
|
const TCache_Class objs_exec_class =
|
|
{
|
|
sizeof ( TExecution_Context ),
|
|
1,
|
|
Context_Create,
|
|
Context_Destroy,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
static
|
|
const TCache_Class objs_glyph_class =
|
|
{
|
|
sizeof ( TGlyph ),
|
|
-1,
|
|
Glyph_Create,
|
|
Glyph_Destroy,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
|
|
LOCAL_FUNC
|
|
TT_Error TTObjs_Init( PEngine_Instance engine )
|
|
{
|
|
PCache face_cache, exec_cache;
|
|
TT_Error error;
|
|
|
|
|
|
face_cache = 0;
|
|
exec_cache = 0;
|
|
|
|
if ( ALLOC( face_cache, sizeof ( TCache ) ) ||
|
|
ALLOC( exec_cache, sizeof ( TCache ) ) )
|
|
goto Fail;
|
|
|
|
/* create face cache */
|
|
error = Cache_Create( engine, (PCache_Class)&objs_face_class,
|
|
face_cache, &engine->lock );
|
|
if ( error )
|
|
goto Fail;
|
|
|
|
engine->objs_face_cache = face_cache;
|
|
|
|
error = Cache_Create( engine, (PCache_Class)&objs_exec_class,
|
|
exec_cache, &engine->lock );
|
|
if ( error )
|
|
goto Fail;
|
|
|
|
engine->objs_exec_cache = exec_cache;
|
|
|
|
engine->objs_face_class = (PCache_Class)&objs_face_class;
|
|
engine->objs_instance_class = (PCache_Class)&objs_instance_class;
|
|
engine->objs_execution_class = (PCache_Class)&objs_exec_class;
|
|
engine->objs_glyph_class = (PCache_Class)&objs_glyph_class;
|
|
|
|
goto Exit;
|
|
|
|
Fail:
|
|
FREE( face_cache );
|
|
FREE( exec_cache );
|
|
|
|
Exit:
|
|
return error;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
*
|
|
* Function : TTObjs_Done
|
|
*
|
|
* Description : The TTObjs component finalizer.
|
|
*
|
|
* Input : engine engine instance
|
|
*
|
|
* Output : Error code.
|
|
*
|
|
******************************************************************/
|
|
|
|
LOCAL_FUNC
|
|
TT_Error TTObjs_Done( PEngine_Instance engine )
|
|
{
|
|
/* destroy all active faces and contexts before releasing the */
|
|
/* caches */
|
|
Cache_Destroy( (TCache*)engine->objs_exec_cache );
|
|
Cache_Destroy( (TCache*)engine->objs_face_cache );
|
|
|
|
/* Now frees caches and cache classes */
|
|
FREE( engine->objs_exec_cache );
|
|
FREE( engine->objs_face_cache );
|
|
|
|
return TT_Err_Ok;
|
|
}
|
|
|
|
|
|
/* END */
|