#include "ttobjs.h"
#include "ttfile.h"
#include "ttcalc.h"
#include "ttmemory.h"
#include "ttload.h"
#include "ttinterp.h"
#include "ttdebug.h"
#ifdef TT_CONFIG_OPTION_EXTEND_ENGINE
#include "ttextend.h"
#endif
#undef TT_COMPONENT
#define TT_COMPONENT trace_objs
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;
}
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
LOCAL_FUNC
PInstance New_Instance( PFace face )
{
PInstance ins;
if ( !face )
return NULL;
CACHE_New( &face->instances, ins, face );
return ins;
}
LOCAL_FUNC
TT_Error Done_Instance( PInstance instance )
{
return CACHE_Done( &instance->owner->instances, instance );
}
#endif
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;
}
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;
}
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;
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
LOCAL_FUNC
PCodeRange Get_CodeRange( PExecution_Context exec, Int range )
{
if ( range < 1 || range > 3 )
return NULL;
else
return &exec->codeRangeTable[range - 1];
}
#endif
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;
}
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;
}
LOCAL_FUNC
TT_Error Context_Destroy( void* _context )
{
PExecution_Context exec = (PExecution_Context)_context;
if ( !exec )
return TT_Err_Ok;
FREE( exec->loadStack );
exec->loadSize = 0;
Done_Glyph_Zone( &exec->pts );
exec->maxPoints = 0;
exec->maxContours = 0;
FREE( exec->stack );
exec->stackSize = 0;
FREE( exec->callStack );
exec->callSize = 0;
exec->callTop = 0;
FREE( exec->glyphIns );
exec->glyphSize = 0;
exec->instance = NULL;
exec->face = NULL;
return TT_Err_Ok;
}
LOCAL_FUNC
TT_Error Context_Create( void* _context, void* _face )
{
PExecution_Context exec = (PExecution_Context)_context;
PFace face = (PFace)_face;
TT_Error error;
exec->callSize = 32;
if ( ALLOC_ARRAY( exec->callStack, exec->callSize, TCallRecord ) )
goto Fail_Memory;
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;
}
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;
}
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];
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 );
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 );
if ( error )
return error;
exec->pts.n_points = 0;
exec->pts.n_contours = 0;
exec->instruction_trap = FALSE;
return TT_Err_Ok;
}
LOCAL_FUNC
TT_Error Context_Save( PExecution_Context exec,
PInstance ins )
{
Int i;
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;
}
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;
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
};
LOCAL_FUNC
TT_Error Instance_Destroy( void* _instance )
{
PInstance ins = (PInstance)_instance;
if ( !_instance )
return TT_Err_Ok;
if ( ins->debug )
{
ins->context = NULL;
ins->debug = FALSE;
}
FREE( ins->cvt );
ins->cvtSize = 0;
FREE( ins->storage );
ins->storeSize = 0;
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;
}
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;
{
PIns_Metrics metrics = &ins->metrics;
metrics->pointSize = 10 * 64;
metrics->x_resolution = 96;
metrics->y_resolution = 96;
metrics->x_ppem = 0;
metrics->y_ppem = 0;
metrics->rotated = FALSE;
metrics->stretched = FALSE;
for ( i = 0; i < 4; i++ )
metrics->compensations[i] = 0;
}
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;
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;
}
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 );
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;
Set_CodeRange( exec,
TT_CodeRange_Font,
face->fontProgram,
face->fontPgmSize );
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 );
ins->valid = FALSE;
return error;
}
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;
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;
}
for ( i = 0; i < ins->cvtSize; i++ )
ins->cvt[i] = TT_MulDiv( face->cvt[i],
ins->metrics.scale1,
ins->metrics.scale2 );
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;
}
for ( i = 0; i < ins->storeSize; i++ )
ins->storage[i] = 0;
ins->GS = Default_GraphicsState;
if ( ins->debug )
exec = ins->context;
else
exec = New_Context(face);
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;
Fin:
Context_Save( exec, ins );
if ( !ins->debug )
Done_Context( exec );
if ( !error )
ins->valid = TRUE;
return error;
}
LOCAL_FUNC
TT_Error Face_Destroy( void* _face )
{
PFace face = (PFace)_face;
UShort n;
if ( !face )
return TT_Err_Ok;
MUTEX_Lock( face->lock );
Cache_Destroy( &face->instances );
Cache_Destroy( &face->glyphs );
#ifdef TT_CONFIG_OPTION_EXTEND_ENGINE
Extension_Destroy( face );
#endif
FREE( face->ttcHeader.TableDirectory );
face->ttcHeader.DirCount = 0;
FREE( face->dirTables );
face->numTables = 0;
FREE( face->glyphLocations );
face->numLocations = 0;
for ( n = 0; n < face->numCMaps; n++ )
CharMap_Free( face->cMaps + n );
FREE( face->cMaps );
face->numCMaps = 0;
FREE( face->cvt );
face->cvtSize = 0;
FREE( face->horizontalHeader.long_metrics );
FREE( face->horizontalHeader.short_metrics );
if (face->verticalInfo)
{
FREE( face->verticalHeader.long_metrics );
FREE( face->verticalHeader.short_metrics );
face->verticalInfo = 0;
}
FREE( face->fontProgram );
FREE( face->cvtProgram );
face->fontPgmSize = 0;
face->cvtPgmSize = 0;
FREE( face->gasp.gaspRanges );
face->gasp.numRanges = 0;
Free_TrueType_Names( face );
Free_TrueType_Hdmx( face );
MUTEX_Destroy(face->lock);
return TT_Err_Ok;
}
#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 );
error = Load_TrueType_Directory( face, input->fontIndex );
if ( error )
goto Fail;
if ( LOAD_( Header ) ||
LOAD_( MaxProfile ) ||
LOAD_( Locations ) ||
(error = Load_TrueType_Metrics_Header( face, 0 )) != TT_Err_Ok ||
LOAD_( CMap ) ||
LOAD_( CVT ) ||
LOAD_( Programs ) ||
LOAD_( Gasp ) ||
LOAD_( Names ) ||
LOAD_( OS2 ) ||
LOAD_( PostScript ) ||
(error = Load_TrueType_Metrics_Header( face, 1 )) != TT_Err_Ok ||
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_
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 );
}
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;
return TT_New_Outline( glyph->face->maxPoints + 2,
glyph->face->maxContours,
&glyph->outline );
}
LOCAL_FUNC
TT_Pos Scale_X( PIns_Metrics metrics, TT_Pos x )
{
return TT_MulDiv( x, metrics->x_scale1, metrics->x_scale2 );
}
LOCAL_FUNC
TT_Pos Scale_Y( PIns_Metrics metrics, TT_Pos y )
{
return TT_MulDiv( y, metrics->y_scale1, metrics->y_scale2 );
}
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
};
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;
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;
}
LOCAL_FUNC
TT_Error TTObjs_Done( PEngine_Instance engine )
{
Cache_Destroy( (TCache*)engine->objs_exec_cache );
Cache_Destroy( (TCache*)engine->objs_face_cache );
FREE( engine->objs_exec_cache );
FREE( engine->objs_face_cache );
return TT_Err_Ok;
}