/******************************************************************* * * 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 */