TTLOAD.C 、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
/*******************************************************************
*
* ttload.c 1.0
*
* TrueType Tables Loader.
*
* 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 "tttypes.h"
#include "ttdebug.h"
#include "ttcalc.h"
#include "ttfile.h"
#include "tttables.h"
#include "ttobjs.h"
#include "ttmemory.h"
#include "tttags.h"
#include "ttload.h"
/* required by the tracing mode */
#undef TT_COMPONENT
#define TT_COMPONENT trace_load
/* In all functions, the stream is taken from the 'face' object */
#define DEFINE_LOCALS DEFINE_LOAD_LOCALS( face->stream )
#define DEFINE_LOCALS_WO_FRAME DEFINE_LOAD_LOCALS_WO_FRAME( face->stream )
/*******************************************************************
*
* Function : LookUp_TrueType_Table
*
* Description : Looks for a TrueType table by name.
*
* Input : face face table to look for
* tag searched tag
*
* Output : Index of table if found, -1 otherwise.
*
******************************************************************/
EXPORT_FUNC
Long TT_LookUp_Table( PFace face,
ULong tag )
{
UShort i;
PTRACE4(( "TT_LookUp_Table( %08lx, %c%c%c%c )\n",
(Long)face,
(Char)(tag >> 24),
(Char)(tag >> 16),
(Char)(tag >> 8),
(Char)(tag) ));
for ( i = 0; i < face->numTables; i++ )
if ( face->dirTables[i].Tag == tag )
return i;
PTRACE4(( " Could not find table!\n" ));
return -1;
}
/*******************************************************************
*
* Function : Load_TrueType_Collection
*
* Description : Loads the TTC table directory into face table.
*
* Input : face face record to look for
*
* Output : Error code.
*
******************************************************************/
static TT_Error Load_TrueType_Collection( PFace face )
{
DEFINE_LOCALS;
ULong n;
PTRACE3(( "Load_TrueType_Collection( %08lx )\n", (long)face ));
if ( FILE_Seek ( 0L ) ||
ACCESS_Frame( 12L ) )
return error;
face->ttcHeader.Tag = GET_Tag4();
face->ttcHeader.version = GET_Long();
face->ttcHeader.DirCount = GET_Long();
FORGET_Frame();
if ( face->ttcHeader.Tag != TTAG_ttcf )
{
face->ttcHeader.Tag = 0;
face->ttcHeader.version = 0;
face->ttcHeader.DirCount = 0;
face->ttcHeader.TableDirectory = NULL;
PTRACE3(("skipped.\n"));
return TT_Err_File_Is_Not_Collection;
}
if ( ALLOC_ARRAY( face->ttcHeader.TableDirectory,
face->ttcHeader.DirCount,
ULong ) ||
ACCESS_Frame( face->ttcHeader.DirCount * 4L ) )
return error;
for ( n = 0; n < face->ttcHeader.DirCount; n++ )
face->ttcHeader.TableDirectory[n] = GET_ULong();
FORGET_Frame();
PTRACE3(( "collections directory loaded.\n" ));
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : Load_TrueType_Directory
*
* Description : Loads the table directory into face table.
*
* Input : face face record to look for
*
* faceIndex the index of the TrueType font, when
* we're opening a collection.
*
* Output : SUCCESS on success. FAILURE on error.
*
******************************************************************/
LOCAL_FUNC
TT_Error Load_TrueType_Directory( PFace face, ULong faceIndex )
{
DEFINE_LOCALS;
UShort n, limit;
TTableDir tableDir;
PTableDirEntry entry;
PTRACE2(("Load_TT_Directory( %08lx, %ld )\n", (long)face, faceIndex));
error = Load_TrueType_Collection( face );
if ( error )
{
if ( error != TT_Err_File_Is_Not_Collection )
return error;
/* the file isn't a collection, exit if we're asking */
/* for a collected font */
if ( faceIndex != 0 )
return error;
/* Now skip to the beginning of the file */
if ( FILE_Seek( 0L ) )
return error;
}
else
{
/* The file is a collection. Check the font index */
if ( faceIndex >= face->ttcHeader.DirCount )
return TT_Err_Invalid_Argument;
/* select a TrueType font in the ttc file */
if ( FILE_Seek( face->ttcHeader.TableDirectory[faceIndex] ) )
return error;
}
if ( ACCESS_Frame( 12L ) )
return error;
tableDir.version = GET_Long();
tableDir.numTables = GET_UShort();
tableDir.searchRange = GET_UShort();
tableDir.entrySelector = GET_UShort();
tableDir.rangeShift = GET_UShort();
FORGET_Frame();
PTRACE2(( "-- Tables count : %12u\n", tableDir.numTables ));
PTRACE2(( "-- Format version : %08lx\n", tableDir.version ));
/* Check that we have a 'sfnt' format there */
if ( tableDir.version != 0x00010000 && /* MS fonts */
tableDir.version != 0x74727565 && /* Mac fonts */
tableDir.version != 0x00000000 ) /* some Korean fonts */
{
PERROR(( "!! invalid file format" ));
return TT_Err_Invalid_File_Format;
}
face->numTables = tableDir.numTables;
if ( ALLOC_ARRAY( face->dirTables,
face->numTables,
TTableDirEntry ) )
return error;
if ( ACCESS_Frame( face->numTables * 16L ) )
return error;
limit = face->numTables;
entry = face->dirTables;
for ( n = 0; n < limit; n++ )
{ /* loop through the tables and get all entries */
entry->Tag = GET_Tag4();
entry->CheckSum = GET_ULong();
entry->Offset = GET_Long();
entry->Length = GET_Long();
PTRACE2(( " %c%c%c%c - %08lx - %08lx\n",
(Char)(entry->Tag >> 24),
(Char)(entry->Tag >> 16),
(Char)(entry->Tag >> 8 ),
(Char)(entry->Tag),
entry->Offset,
entry->Length ));
entry++;
}
FORGET_Frame();
PTRACE2(( "Directory loaded\n\n" ));
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : Load_TrueType_MaxProfile
*
* Description : Loads the maxp table into face table.
*
* Input : face face table to look for
*
* Output : Error code.
*
******************************************************************/
LOCAL_FUNC
TT_Error Load_TrueType_MaxProfile( PFace face )
{
DEFINE_LOCALS;
Long i;
PMaxProfile maxProfile = &face->maxProfile;
PTRACE2(( "Load_TT_MaxProfile( %08lx )\n", (long)face ));
if ( ( i = TT_LookUp_Table( face, TTAG_maxp ) ) < 0 )
return TT_Err_Max_Profile_Missing;
if ( FILE_Seek( face->dirTables[i].Offset ) ) /* seek to maxprofile */
return error;
if ( ACCESS_Frame( 32L ) ) /* read into frame */
return error;
/* read frame data into face table */
maxProfile->version = GET_ULong();
maxProfile->numGlyphs = GET_UShort();
maxProfile->maxPoints = GET_UShort();
maxProfile->maxContours = GET_UShort();
maxProfile->maxCompositePoints = GET_UShort();
maxProfile->maxCompositeContours = GET_UShort();
maxProfile->maxZones = GET_UShort();
maxProfile->maxTwilightPoints = GET_UShort();
maxProfile->maxStorage = GET_UShort();
maxProfile->maxFunctionDefs = GET_UShort();
maxProfile->maxInstructionDefs = GET_UShort();
maxProfile->maxStackElements = GET_UShort();
maxProfile->maxSizeOfInstructions = GET_UShort();
maxProfile->maxComponentElements = GET_UShort();
maxProfile->maxComponentDepth = GET_UShort();
FORGET_Frame();
/* XXX : an adjustement that is necessary to load certain */
/* broken fonts like "Keystrokes MT" :-( */
/* */
/* We allocate 64 function entries by default when */
/* the maxFunctionDefs field is null. */
if (maxProfile->maxFunctionDefs == 0)
maxProfile->maxFunctionDefs = 64;
face->numGlyphs = maxProfile->numGlyphs;
face->maxPoints = MAX( maxProfile->maxCompositePoints,
maxProfile->maxPoints );
face->maxContours = MAX( maxProfile->maxCompositeContours,
maxProfile->maxContours );
face->maxComponents = maxProfile->maxComponentElements +
maxProfile->maxComponentDepth;
/* XXX: Some fonts have maxComponents set to 0; we will */
/* then use 16 of them by default. */
if ( face->maxComponents == 0 )
face->maxComponents = 16;
/* We also increase maxPoints and maxContours in order to support */
/* some broken fonts. */
face->maxPoints += 8;
face->maxContours += 4;
PTRACE2(( "GASP loaded.\n" ));
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : Load_TrueType_Gasp
*
* Description : Loads the TrueType Gasp table into the face
* table.
*
* Input : face face table to look for
*
* Output : Error code.
*
******************************************************************/
LOCAL_FUNC
TT_Error Load_TrueType_Gasp( PFace face )
{
DEFINE_LOCALS;
Long i;
UShort j;
TGasp* gas;
GaspRange* gaspranges;
PTRACE2(( "Load_TT_Gasp( %08lx )\n", (long)face ));
if ( ( i = TT_LookUp_Table( face, TTAG_gasp ) ) < 0 )
return TT_Err_Ok; /* gasp table is not required */
if ( FILE_Seek( face->dirTables[i].Offset ) ||
ACCESS_Frame( 4L ) )
return error;
gas = &face->gasp;
gas->version = GET_UShort();
gas->numRanges = GET_UShort();
FORGET_Frame();
PTRACE3(( "number of ranges = %d\n", gas->numRanges ));
if ( ALLOC_ARRAY( gaspranges, gas->numRanges, GaspRange ) ||
ACCESS_Frame( gas->numRanges * 4L ) )
goto Fail;
face->gasp.gaspRanges = gaspranges;
for ( j = 0; j < gas->numRanges; j++ )
{
gaspranges[j].maxPPEM = GET_UShort();
gaspranges[j].gaspFlag = GET_UShort();
PTRACE3(( " [max:%d flag:%d]",
gaspranges[j].maxPPEM,
gaspranges[j].gaspFlag ));
}
PTRACE3(("\n"));
FORGET_Frame();
PTRACE2(( "GASP loaded\n" ));
return TT_Err_Ok;
Fail:
FREE( gaspranges );
gas->numRanges = 0;
return error;
}
/*******************************************************************
*
* Function : Load_TrueType_Header
*
* Description : Loads the TrueType header table into the face
* table.
*
* Input : face face table to look for
*
* Output : Error code.
*
******************************************************************/
LOCAL_FUNC
TT_Error Load_TrueType_Header( PFace face )
{
DEFINE_LOCALS;
Long i;
TT_Header* header;
PTRACE2(( "Load_TT_Header( %08lx )\n", (long)face ));
if ( ( i = TT_LookUp_Table( face, TTAG_head ) ) < 0 )
{
PTRACE0(( "Font Header is missing !!\n" ));
return TT_Err_Header_Table_Missing;
}
if ( FILE_Seek( face->dirTables[i].Offset ) ||
ACCESS_Frame( 54L ) )
return error;
header = &face->fontHeader;
header->Table_Version = GET_ULong();
header->Font_Revision = GET_ULong();
header->CheckSum_Adjust = GET_Long();
header->Magic_Number = GET_Long();
header->Flags = GET_UShort();
header->Units_Per_EM = GET_UShort();
header->Created [0] = GET_Long();
header->Created [1] = GET_Long();
header->Modified[0] = GET_Long();
header->Modified[1] = GET_Long();
header->xMin = GET_Short();
header->yMin = GET_Short();
header->xMax = GET_Short();
header->yMax = GET_Short();
header->Mac_Style = GET_UShort();
header->Lowest_Rec_PPEM = GET_UShort();
header->Font_Direction = GET_Short();
header->Index_To_Loc_Format = GET_Short();
header->Glyph_Data_Format = GET_Short();
FORGET_Frame();
PTRACE2(( " Units per EM : %8u\n", header->Units_Per_EM ));
PTRACE2(( " IndexToLoc : %8d\n", header->Index_To_Loc_Format ));
PTRACE2(( "Font Header Loaded.\n" ));
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : Load_TrueType_Metrics
*
* Description : Loads the horizontal or vertical metrics table
* into face object.
*
* Input : face
* vertical set to true when loading the vmtx table,
* or false for hmtx
*
* Output : Error code.
*
******************************************************************/
static
TT_Error Load_TrueType_Metrics( PFace face,
Bool vertical )
{
DEFINE_LOCALS;
Long n, num_shorts, num_shorts_checked, num_longs;
PLongMetrics* longs;
PShortMetrics* shorts;
PLongMetrics long_metric;
PTRACE2(( "Load_TT_%s_Metrics( %08lx )\n",
vertical ? "Vertical" : "Horizontal",
(long)face ));
if ( vertical )
{
/* The table is optional, quit silently if it wasn't found */
/* XXX : Some fonts have a valid vertical header with a non-null */
/* "number_of_VMetrics" fields, but no corresponding */
/* 'vmtx' table to get the metrics from (e.g. mingliu) */
/* */
/* For safety, we set the field to 0 ! */
/* */
n = TT_LookUp_Table( face, TTAG_vmtx );
if ( n < 0 )
{
/* Set the number_Of_VMetrics to 0! */
PTRACE2(( " no vertical header in file.\n" ));
face->verticalHeader.number_Of_VMetrics = 0;
return TT_Err_Ok;
}
num_longs = face->verticalHeader.number_Of_VMetrics;
longs = (PLongMetrics*)&face->verticalHeader.long_metrics;
shorts = (PShortMetrics*)&face->verticalHeader.short_metrics;
}
else
{
if ( ( n = TT_LookUp_Table( face, TTAG_hmtx ) ) < 0 )
{
PERROR(( "!! No Horizontal metrics in file !!\n" ));
return TT_Err_Hmtx_Table_Missing;
}
num_longs = face->horizontalHeader.number_Of_HMetrics;
longs = (PLongMetrics*)&face->horizontalHeader.long_metrics;
shorts = (PShortMetrics*)&face->horizontalHeader.short_metrics;
}
/* never trust derived values! */
num_shorts = face->maxProfile.numGlyphs - num_longs;
num_shorts_checked = ( face->dirTables[n].Length - num_longs * 4 ) / 2;
if ( num_shorts < 0 ) /* sanity check */
{
PERROR(( "!! more metrics than glyphs!\n" ));
if ( vertical )
return TT_Err_Invalid_Vert_Metrics;
else
return TT_Err_Invalid_Horiz_Metrics;
}
if ( ALLOC_ARRAY( *longs, num_longs, TLongMetrics ) ||
ALLOC_ARRAY( *shorts, num_shorts, TShortMetrics ) )
return error;
if ( FILE_Seek( face->dirTables[n].Offset ) ||
ACCESS_Frame( face->dirTables[n].Length ) )
return error;
long_metric = *longs;
for ( n = 0; n < num_longs; n++ )
{
long_metric->advance = GET_UShort();
long_metric->bearing = GET_Short();
long_metric++;
}
/* do we have an inconsistent number of metric values? */
if ( num_shorts > num_shorts_checked )
{
for ( n = 0; n < num_shorts_checked; n++ )
(*shorts)[n] = GET_Short();
/* we fill up the missing left side bearings with the */
/* last valid value. Since this will occur for buggy CJK */
/* fonts usually, nothing serious will happen. */
for ( n = num_shorts_checked; n < num_shorts; n++ )
(*shorts)[n] = (*shorts)[num_shorts_checked - 1];
}
else
{
for ( n = 0; n < num_shorts; n++ )
(*shorts)[n] = GET_Short();
}
FORGET_Frame();
PTRACE2(( "loaded\n" ));
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : Load_TrueType_Metrics_Header
*
* Description : Loads either the "hhea" or "vhea" table in memory
*
* Input : face face table to look for
* vertical a boolean. When set, queries the optional
* "vhea" table. Otherwise, load the mandatory
* "hhea" horizontal header.
*
* Output : Error code.
*
* Note : This function now loads the corresponding metrics table
* (either hmtx or vmtx) and attaches it to the header.
*
******************************************************************/
LOCAL_FUNC
TT_Error Load_TrueType_Metrics_Header( PFace face,
Bool vertical )
{
DEFINE_LOCALS;
Long i;
TT_Horizontal_Header* header;
PTRACE2(( vertical ? "Vertical header" : "Horizontal header " ));
if ( vertical )
{
face->verticalInfo = 0;
/* The vertical header table is optional, so return quietly if */
/* we don't find it.. */
if ( ( i = TT_LookUp_Table( face, TTAG_vhea ) ) < 0 )
return TT_Err_Ok;
face->verticalInfo = 1;
header = (TT_Horizontal_Header*)&face->verticalHeader;
}
else
{
/* The orizontal header is mandatory, return an error if we */
/* don't find it. */
if ( ( i = TT_LookUp_Table( face, TTAG_hhea ) ) < 0 )
return TT_Err_Horiz_Header_Missing;
header = &face->horizontalHeader;
}
if ( FILE_Seek( face->dirTables[i].Offset ) ||
ACCESS_Frame( 36L ) )
return error;
header->Version = GET_ULong();
header->Ascender = GET_Short();
header->Descender = GET_Short();
header->Line_Gap = GET_Short();
header->advance_Width_Max = GET_UShort();
header->min_Left_Side_Bearing = GET_Short();
header->min_Right_Side_Bearing = GET_Short();
header->xMax_Extent = GET_Short();
header->caret_Slope_Rise = GET_Short();
header->caret_Slope_Run = GET_Short();
header->Reserved0 = GET_Short(); /* this is caret_Offset for
vertical headers */
header->Reserved1 = GET_Short();
header->Reserved2 = GET_Short();
header->Reserved3 = GET_Short();
header->Reserved4 = GET_Short();
header->metric_Data_Format = GET_Short();
header->number_Of_HMetrics = GET_UShort();
FORGET_Frame();
header->long_metrics = NULL;
header->short_metrics = NULL;
PTRACE2(( "loaded\n" ));
/* Now try to load the corresponding metrics */
return Load_TrueType_Metrics( face, vertical );
}
/*******************************************************************
*
* Function : Load_TrueType_Locations
*
* Description : Loads the location table into face table.
*
* Input : face face table to look for
*
* Output : Error code.
*
* NOTE:
* The Font Header *must* be loaded in the leading segment
* calling this function.
*
******************************************************************/
LOCAL_FUNC
TT_Error Load_TrueType_Locations( PFace face )
{
DEFINE_LOCALS;
Long n, limit;
Short LongOffsets;
PTRACE2(( "Locations " ));
LongOffsets = face->fontHeader.Index_To_Loc_Format;
if ( ( n = TT_LookUp_Table( face, TTAG_loca ) ) < 0 )
return TT_Err_Locations_Missing;
if ( FILE_Seek( face->dirTables[n].Offset ) )
return error;
if ( LongOffsets != 0 )
{
face->numLocations = face->dirTables[n].Length >> 2;
PTRACE2(( "(32 bit offsets): %12lu ",
face->numLocations ));
if ( ALLOC_ARRAY( face->glyphLocations,
face->numLocations,
Long ) )
return error;
if ( ACCESS_Frame( face->numLocations * 4L ) )
return error;
limit = face->numLocations;
for ( n = 0; n < limit; n++ )
face->glyphLocations[n] = GET_Long();
FORGET_Frame();
}
else
{
face->numLocations = face->dirTables[n].Length >> 1;
PTRACE2(( "(16 bit offsets): %12lu ",
face->numLocations ));
if ( ALLOC_ARRAY( face->glyphLocations,
face->numLocations,
Long ) )
return error;
if ( ACCESS_Frame( face->numLocations * 2L ) )
return error;
limit = face->numLocations;
for ( n = 0; n < limit; n++ )
face->glyphLocations[n] =
(Long)((ULong)GET_UShort() * 2);
FORGET_Frame();
}
PTRACE2(( "loaded\n" ));
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : Load_TrueType_Names
*
* Description : Loads the name table into face table.
*
* Input : face face table to look for
*
* Output : Error code.
*
******************************************************************/
LOCAL_FUNC
TT_Error Load_TrueType_Names( PFace face )
{
DEFINE_LOCALS;
UShort i, bytes;
Long n;
PByte storage;
TName_Table* names;
TNameRec* namerec;
PTRACE2(( "Names " ));
if ( ( n = TT_LookUp_Table( face, TTAG_name ) ) < 0 )
{
/* The name table is required so indicate failure. */
PTRACE2(( "is missing!\n" ));
return TT_Err_Name_Table_Missing;
}
/* Seek to the beginning of the table and check the frame access. */
/* The names table has a 6 byte header. */
if ( FILE_Seek( face->dirTables[n].Offset ) ||
ACCESS_Frame( 6L ) )
return error;
names = &face->nameTable;
/* Load the initial names data. */
names->format = GET_UShort();
names->numNameRecords = GET_UShort();
names->storageOffset = GET_UShort();
FORGET_Frame();
/* Allocate the array of name records. */
if ( ALLOC_ARRAY( names->names,
names->numNameRecords,
TNameRec ) ||
ACCESS_Frame( names->numNameRecords * 12L ) )
{
names->numNameRecords = 0;
goto Fail;
}
/* Load the name records and determine how much storage is needed */
/* to hold the strings themselves. */
for ( i = bytes = 0; i < names->numNameRecords; i++ )
{
namerec = names->names + i;
namerec->platformID = GET_UShort();
namerec->encodingID = GET_UShort();
namerec->languageID = GET_UShort();
namerec->nameID = GET_UShort();
namerec->stringLength = GET_UShort();
namerec->stringOffset = GET_UShort();
#if 0
/* check the ids */
if ( namerec->platformID <= 3 )
{
#endif
/* this test takes care of 'holes' in the names tables, as */
/* reported by Erwin */
if ( (namerec->stringOffset + namerec->stringLength) > bytes )
bytes = namerec->stringOffset + namerec->stringLength;
#if 0
}
#endif
}
FORGET_Frame();
/* Allocate storage for the strings if they exist. */
names->storage = NULL;
if ( bytes > 0 )
{
if ( ALLOC( storage, bytes ) ||
FILE_Read_At( face->dirTables[n].Offset + names->storageOffset,
(void*)storage,
bytes ) )
goto Fail_Storage;
names->storage = storage;
/* Go through and assign the string pointers to the name records. */
for ( i = 0; i < names->numNameRecords; i++ )
{
namerec = names->names + i;
namerec->string = storage + names->names[i].stringOffset;
/* It is possible (but rather unlikely) that a new platform ID will be */
/* added by Apple, so we can't rule out IDs > 3. */
#if 0
if ( namerec->platformID <= 3 )
namerec->string = storage + names->names[i].stringOffset;
else
{
namerec->string = NULL;
namerec->stringLength = 0;
}
#endif
}
}
#ifdef DEBUG_LEVEL_TRACE
for ( i = 0; i < names->numNameRecords; i++ )
{
int j;
PTRACE2(( "%d %d %x %d ",
names->names[i].platformID,
names->names[i].encodingID,
names->names[i].languageID,
names->names[i].nameID ));
/* I know that M$ encoded strings are Unicode, */
/* but this works reasonable well for debugging purposes. */
for ( j = 0; j < names->names[i].stringLength; j++ )
{
if (names->names[i].string)
{
Char c = *(names->names[i].string + j);
if ( (Byte)c < 128 )
PTRACE2(( "%c", c ));
}
}
PTRACE2(( "\n" ));
}
#endif /* DEBUG_LEVEL_TRACE */
PTRACE2(( "loaded\n" ));
return TT_Err_Ok;
Fail_Storage:
FREE( storage );
Fail:
Free_TrueType_Names( face );
return error;
}
/*******************************************************************
*
* Function : Free_TrueType_Names
*
* Description : Frees a name table.
*
* Input : face face table to look for
*
* Output : TT_Err_Ok.
*
******************************************************************/
LOCAL_FUNC
TT_Error Free_TrueType_Names( PFace face )
{
TName_Table* names = &face->nameTable;
/* free strings table */
FREE( names->names );
/* free strings storage */
FREE( names->storage );
names->numNameRecords = 0;
names->format = 0;
names->storageOffset = 0;
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : Load_TrueType_CVT
*
* Description : Loads cvt table into resident table.
*
* Input : face face table to look for
*
* Output : Error code.
*
******************************************************************/
LOCAL_FUNC
TT_Error Load_TrueType_CVT( PFace face )
{
DEFINE_LOCALS;
Long n, limit;
PTRACE2(( "CVT " ));
if ( ( n = TT_LookUp_Table( face, TTAG_cvt ) ) < 0 )
{
PTRACE2(( "is missing!\n" ));
face->cvtSize = 0;
face->cvt = NULL;
return TT_Err_Ok;
}
face->cvtSize = face->dirTables[n].Length / 2;
if ( ALLOC_ARRAY( face->cvt,
face->cvtSize,
Short ) )
return error;
if ( FILE_Seek( face->dirTables[n].Offset ) ||
ACCESS_Frame( face->cvtSize * 2L ) )
return error;
limit = face->cvtSize;
for ( n = 0; n < limit; n++ )
face->cvt[n] = GET_Short();
FORGET_Frame();
PTRACE2(( "loaded\n" ));
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : Load_TrueType_CMap
*
* Description : Loads the cmap directory in memory.
* The cmaps themselves are loaded in ttcmap.c .
*
* Input : face
*
* Output : Error code.
*
******************************************************************/
LOCAL_FUNC
TT_Error Load_TrueType_CMap( PFace face )
{
DEFINE_LOCALS;
Long off, table_start;
Long n, limit;
TCMapDir cmap_dir;
TCMapDirEntry entry_;
PCMapTable cmap;
PTRACE2(( "CMaps " ));
if ( ( n = TT_LookUp_Table( face, TTAG_cmap ) ) < 0 )
return TT_Err_CMap_Table_Missing;
table_start = face->dirTables[n].Offset;
//ShowFont(0, 32,"table_start ");
//MakeInt(buf,table_start);
//ShowFont(0, 48,buf);
//j=0;while(j<95000000L)j++;
if ( ( FILE_Seek( table_start ) ) ||
( ACCESS_Frame( 4L ) ) ) /* 4 bytes cmap header */
return error;
cmap_dir.tableVersionNumber = GET_UShort();
cmap_dir.numCMaps = GET_UShort();
FORGET_Frame();
off = FILE_Pos(); /* save offset to cmapdir[] which follows */
//ShowFont(0, 32,"off ");
//MakeInt(buf,off);
//ShowFont(0, 48,buf);
//j=0;while(j<95000000L)j++;
/* save space in face table for cmap tables */
if ( ALLOC_ARRAY( face->cMaps,
cmap_dir.numCMaps,
TCMapTable ) )
return error;
face->numCMaps = cmap_dir.numCMaps;
limit = face->numCMaps;
cmap = face->cMaps;
for ( n = 0; n < limit; n++ )
{
if ( FILE_Seek( off ) ||
ACCESS_Frame( 8L ) )
return error;
//ShowFont(0, 32,"n = ");
//MakeInt(buf,n);
//ShowFont(0, 48,buf);
//j=0;while(j<95000000L)j++;
//ShowFont(0, 32,"off = ");
//MakeInt(buf,off);
//ShowFont(0, 48,buf);
//j=0;while(j<95000000L)j++;
/* extra code using entry_ for platxxx could be cleaned up later */
cmap->loaded = FALSE;
cmap->platformID = entry_.platformID = GET_UShort();
cmap->platformEncodingID = entry_.platformEncodingID = GET_UShort();
entry_.offset = GET_Long();
//ShowFont(0, 32,"entry_.offset ");
//MakeInt(buf,entry_.offset);
//ShowFont(0, 48,buf);
//j=0;while(j<95000000L)j++;
FORGET_Frame();
off = FILE_Pos();
//ShowFont(0, 32,"entry_.offset ");
//MakeInt(buf,entry_.offset);
//ShowFont(0, 48,buf);
//j=0;while(j<95000000L)j++;
if ( FILE_Seek( table_start + entry_.offset ) ||
ACCESS_Frame( 6L ) )
return error;
cmap->format = GET_UShort();
cmap->length = GET_UShort();
cmap->version = GET_UShort();
FORGET_Frame();
cmap->offset = FILE_Pos();
//ShowFont(0, 32,"platformID ");
//MakeInt(buf,cmap->platformID);
//ShowFont(0, 48,buf);
//j=0;while(j<95000000L)j++;
//ShowFont(0, 32,"EncodingID ");
//MakeInt(buf,cmap->platformEncodingID);
//ShowFont(0, 48,buf);
//j=0;while(j<95000000L)j++;
//ShowFont(0, 32,"length ");
//MakeInt(buf,cmap->length);
//ShowFont(0, 48,buf);
//j=0;while(j<95000000L)j++;
//ShowFont(0, 32,"offset ");
//MakeInt(buf,cmap->offset);
//ShowFont(0, 48,buf);
//j=0;while(j<95000000L)j++;
cmap++;
}
PTRACE2(( "loaded\n" ));
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : Load_TrueType_Programs
*
* Description : Loads the font (fpgm) and cvt programs into the
* face table.
*
* Input : face
*
* Output : Error code.
*
******************************************************************/
LOCAL_FUNC
TT_Error Load_TrueType_Programs( PFace face )
{
DEFINE_LOCALS_WO_FRAME;
Long n;
PTRACE2(( "Font program " ));
/* The font program is optional */
if ( ( n = TT_LookUp_Table( face, TTAG_fpgm ) ) < 0 )
{
face->fontProgram = NULL;
face->fontPgmSize = 0;
PTRACE2(( "is missing!\n" ));
}
else
{
face->fontPgmSize = face->dirTables[n].Length;
if ( ALLOC( face->fontProgram,
face->fontPgmSize ) ||
FILE_Read_At( face->dirTables[n].Offset,
(void*)face->fontProgram,
face->fontPgmSize ) )
return error;
PTRACE2(( "loaded, %12d bytes\n", face->fontPgmSize ));
}
PTRACE2(( "Prep program " ));
if ( ( n = TT_LookUp_Table( face, TTAG_prep ) ) < 0 )
{
face->cvtProgram = NULL;
face->cvtPgmSize = 0;
PTRACE2(( "is missing!\n" ));
}
else
{
face->cvtPgmSize = face->dirTables[n].Length;
if ( ALLOC( face->cvtProgram,
face->cvtPgmSize ) ||
FILE_Read_At( face->dirTables[n].Offset,
(void*)face->cvtProgram,
face->cvtPgmSize ) )
return error;
PTRACE2(( "loaded, %12d bytes\n", face->cvtPgmSize ));
}
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : Load_TrueType_OS2
*
* Description : Loads the OS2 Table.
*
* Input : face
*
* Output : Error code.
*
******************************************************************/
LOCAL_FUNC
TT_Error Load_TrueType_OS2( PFace face )
{
DEFINE_LOCALS;
Long i;
TT_OS2* os2;
PTRACE2(( "OS/2 Table " ));
/* We now support old Mac fonts where the OS/2 table doesn't */
/* exist. Simply put, we set the `version' field to 0xFFFF */
/* and test this value each time we need to access the table. */
if ( ( i = TT_LookUp_Table( face, TTAG_OS2 ) ) < 0 )
{
PTRACE2(( "is missing\n!" ));
face->os2.version = 0xFFFF;
error = TT_Err_Ok;
return TT_Err_Ok;
}
if ( FILE_Seek( face->dirTables[i].Offset ) ||
ACCESS_Frame( 78L ) )
return error;
os2 = &face->os2;
os2->version = GET_UShort();
os2->xAvgCharWidth = GET_Short();
os2->usWeightClass = GET_UShort();
os2->usWidthClass = GET_UShort();
os2->fsType = GET_Short();
os2->ySubscriptXSize = GET_Short();
os2->ySubscriptYSize = GET_Short();
os2->ySubscriptXOffset = GET_Short();
os2->ySubscriptYOffset = GET_Short();
os2->ySuperscriptXSize = GET_Short();
os2->ySuperscriptYSize = GET_Short();
os2->ySuperscriptXOffset = GET_Short();
os2->ySuperscriptYOffset = GET_Short();
os2->yStrikeoutSize = GET_Short();
os2->yStrikeoutPosition = GET_Short();
os2->sFamilyClass = GET_Short();
for ( i = 0; i < 10; i++ )
os2->panose[i] = GET_Byte();
os2->ulUnicodeRange1 = GET_ULong();
os2->ulUnicodeRange2 = GET_ULong();
os2->ulUnicodeRange3 = GET_ULong();
os2->ulUnicodeRange4 = GET_ULong();
for ( i = 0; i < 4; i++ )
os2->achVendID[i] = GET_Byte();
os2->fsSelection = GET_UShort();
os2->usFirstCharIndex = GET_UShort();
os2->usLastCharIndex = GET_UShort();
os2->sTypoAscender = GET_Short();
os2->sTypoDescender = GET_Short();
os2->sTypoLineGap = GET_Short();
os2->usWinAscent = GET_UShort();
os2->usWinDescent = GET_UShort();
FORGET_Frame();
if ( os2->version >= 0x0001 )
{
/* only version 1 tables */
if ( ACCESS_Frame( 8L ) ) /* read into frame */
return error;
os2->ulCodePageRange1 = GET_ULong();
os2->ulCodePageRange2 = GET_ULong();
FORGET_Frame();
}
else
{
os2->ulCodePageRange1 = 0;
os2->ulCodePageRange2 = 0;
}
PTRACE2(( "loaded\n" ));
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : Load_TrueType_PostScript
*
* Description : Loads the post table into face table.
*
* Input : face face table to look for
*
* Output : SUCCESS on success. FAILURE on error.
*
******************************************************************/
LOCAL_FUNC
TT_Error Load_TrueType_PostScript( PFace face )
{
DEFINE_LOCALS;
Long i;
TT_Postscript* post = &face->postscript;
PTRACE2(( "PostScript " ));
if ( ( i = TT_LookUp_Table( face, TTAG_post ) ) < 0 )
return TT_Err_Post_Table_Missing;
if ( FILE_Seek( face->dirTables[i].Offset ) ||
ACCESS_Frame( 32L ) )
return error;
/* read frame data into face table */
post->FormatType = GET_ULong();
post->italicAngle = GET_ULong();
post->underlinePosition = GET_Short();
post->underlineThickness = GET_Short();
post->isFixedPitch = GET_ULong();
post->minMemType42 = GET_ULong();
post->maxMemType42 = GET_ULong();
post->minMemType1 = GET_ULong();
post->maxMemType1 = GET_ULong();
FORGET_Frame();
/* we don't load the glyph names, we do that in a */
/* library extension (ftxpost). */
PTRACE2(( "loaded\n" ));
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : Load_TrueType_Hdmx
*
* Description : Loads the horizontal device metrics table.
*
* Input : face face object to look for
*
* Output : SUCCESS on success. FAILURE on error.
*
******************************************************************/
LOCAL_FUNC
TT_Error Load_TrueType_Hdmx( PFace face )
{
DEFINE_LOCALS;
TT_Hdmx_Record* rec;
TT_Hdmx hdmx;
Long table;
UShort n, num_glyphs;
Long record_size;
hdmx.version = 0;
hdmx.num_records = 0;
hdmx.records = 0;
face->hdmx = hdmx;
if ( ( table = TT_LookUp_Table( face, TTAG_hdmx ) ) < 0 )
return TT_Err_Ok;
if ( FILE_Seek( face->dirTables[table].Offset ) ||
ACCESS_Frame( 8L ) )
return error;
hdmx.version = GET_UShort();
hdmx.num_records = GET_Short();
record_size = GET_Long();
FORGET_Frame();
/* Only recognize format 0 */
if ( hdmx.version != 0 )
return TT_Err_Ok;
if ( ALLOC( hdmx.records, sizeof ( TT_Hdmx_Record ) * hdmx.num_records ) )
return error;
num_glyphs = face->numGlyphs;
record_size -= num_glyphs+2;
rec = hdmx.records;
for ( n = 0; n < hdmx.num_records; n++ )
{
/* read record */
if ( ACCESS_Frame( 2L ) )
goto Fail;
rec->ppem = GET_Byte();
rec->max_width = GET_Byte();
FORGET_Frame();
if ( ALLOC( rec->widths, num_glyphs ) ||
FILE_Read( rec->widths, num_glyphs ) )
goto Fail;
/* skip padding bytes */
if ( record_size > 0 )
if ( FILE_Skip( record_size ) )
goto Fail;
rec++;
}
face->hdmx = hdmx;
return TT_Err_Ok;
Fail:
for ( n = 0; n < hdmx.num_records; n++ )
FREE( hdmx.records[n].widths );
FREE( hdmx.records );
return error;
}
/*******************************************************************
*
* Function : Free_TrueType_Hdmx
*
* Description : Frees the horizontal device metrics table.
*
* Input : face face object to look for
*
* Output : TT_Err_Ok.
*
******************************************************************/
LOCAL_FUNC
TT_Error Free_TrueType_Hdmx( PFace face )
{
UShort n;
if ( !face )
return TT_Err_Ok;
for ( n = 0; n < face->hdmx.num_records; n++ )
FREE( face->hdmx.records[n].widths );
FREE( face->hdmx.records );
face->hdmx.num_records = 0;
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : Load_TrueType_Any
*
* Description : Loads any font table into client memory. Used by
* the TT_Get_Font_Data() API function.
*
* Input : face face object to look for
*
* tag tag of table to load. Use the value 0 if you
* want to access the whole font file, else set
* this parameter to a valid TrueType table tag
* that you can forge with the MAKE_TT_TAG
* macro.
*
* offset starting offset in the table (or the file
* if tag == 0 )
*
* buffer address of target buffer
*
* length address of decision variable :
*
* if length == NULL :
* load the whole table. returns an
* an error if 'offset' == 0 !!
*
* if *length == 0 :
* exit immediately, returning the
* length of the given table, or of
* the font file, depending on the
* value of 'tag'
*
* if *length != 0 :
* load the next 'length' bytes of
* table or font, starting at offset
* 'offset' (in table or font too).
*
* Output : Error condition
*
******************************************************************/
LOCAL_FUNC
TT_Error Load_TrueType_Any( PFace face,
ULong tag,
Long offset,
void* buffer,
Long* length )
{
TT_Stream stream;
TT_Error error;
Long table;
ULong size;
if ( tag != 0 )
{
/* look for tag in font directory */
table = TT_LookUp_Table( face, tag );
if ( table < 0 )
return TT_Err_Table_Missing;
offset += face->dirTables[table].Offset;
size = face->dirTables[table].Length;
}
else
/* tag = 0 -- the use want to access the font file directly */
size = TT_Stream_Size( face->stream );
if ( length && *length == 0 )
{
*length = size;
return TT_Err_Ok;
}
if ( length )
size = *length;
if ( !USE_Stream( face->stream, stream ) )
(void)FILE_Read_At( offset, buffer, size );
DONE_Stream( stream );
return error;
}
/* END */
TTLOAD.H 、、、、、、、、、、、、、、、、、、、、、、、、
/*******************************************************************
*
* ttload.h 1.1
*
* TrueType Tables Loader.
*
* Copyright 1996-1999 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used
* modified and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*
* Changes between 1.1 and 1.0 :
*
* - add function Load_TrueType_Any used by TT_Get_Font_Data
*
******************************************************************/
#ifndef TTLOAD_H
#define TTLOAD_H
#include "ttconfig.h"
#include "tttypes.h"
#include "ttobjs.h"
#ifdef __cplusplus
extern "C" {
#endif
EXPORT_DEF
Long TT_LookUp_Table( PFace face, ULong tag );
LOCAL_DEF TT_Error Load_TrueType_Directory ( PFace face,
ULong faceIndex );
LOCAL_DEF TT_Error Load_TrueType_MaxProfile ( PFace face );
LOCAL_DEF TT_Error Load_TrueType_Gasp ( PFace face );
LOCAL_DEF TT_Error Load_TrueType_Header ( PFace face );
LOCAL_DEF TT_Error Load_TrueType_Locations ( PFace face );
LOCAL_DEF TT_Error Load_TrueType_Names ( PFace face );
LOCAL_DEF TT_Error Load_TrueType_CVT ( PFace face );
LOCAL_DEF TT_Error Load_TrueType_CMap ( PFace face );
LOCAL_DEF TT_Error Load_TrueType_Programs ( PFace face );
LOCAL_DEF TT_Error Load_TrueType_OS2 ( PFace face );
LOCAL_DEF TT_Error Load_TrueType_PostScript ( PFace face );
LOCAL_DEF TT_Error Load_TrueType_Hdmx ( PFace face );
LOCAL_DEF TT_Error Load_TrueType_Metrics_Header( PFace face,
Bool vertical );
LOCAL_DEF TT_Error Load_TrueType_Any( PFace face,
ULong tag,
Long offset,
void* buffer,
Long* length );
LOCAL_DEF TT_Error Free_TrueType_Names( PFace face );
LOCAL_DEF TT_Error Free_TrueType_Hdmx ( PFace face );
/* The following macros are defined to simplify the writing of */
/* the various table and glyph loaders. */
/* For examples see the code in ttload.c, ttgload.c etc. */
#define USE_Stream( original, duplicate ) \
( (error = TT_Use_Stream( original, &duplicate )) != TT_Err_Ok )
#define DONE_Stream( _stream ) \
TT_Done_Stream( &_stream )
/* Define a file frame -- use it only when needed */
#define DEFINE_A_FRAME TFileFrame frame = TT_Null_FileFrame
/* Define a stream -- use it only when needed */
#define DEFINE_A_STREAM TT_Stream stream
#ifdef TT_CONFIG_OPTION_THREAD_SAFE /* re-entrant implementation */
/* The following macros define the necessary local */
/* variables used to access streams and frames. */
/* Define stream locals with frame */
#define DEFINE_STREAM_LOCALS \
TT_Error error; \
DEFINE_A_STREAM; \
DEFINE_A_FRAME
/* Define stream locals without frame */
#define DEFINE_STREAM_LOCALS_WO_FRAME \
TT_Error error; \
DEFINE_A_STREAM
/* Define locals with a predefined stream in reentrant mode -- see ttload.c */
#define DEFINE_LOAD_LOCALS( STREAM ) \
TT_Error error; \
DEFINE_A_STREAM = (STREAM); \
DEFINE_A_FRAME
/* Define locals without frame with a predefined stream - see ttload.c */
#define DEFINE_LOAD_LOCALS_WO_FRAME( STREAM ) \
TT_Error error; \
DEFINE_A_STREAM = (STREAM)
/* Define all locals necessary to access a font file */
#define DEFINE_ALL_LOCALS \
TT_Error error; \
DEFINE_A_STREAM; \
DEFINE_A_FRAME
#define ACCESS_Frame( _size_ ) \
( (error = TT_Access_Frame( stream, \
&frame, \
(Long)(_size_) )) != TT_Err_Ok )
#define CHECK_ACCESS_Frame( _size_ ) \
( (error = TT_Check_And_Access_Frame( stream, \
&frame, \
(Long)(_size_) )) != TT_Err_Ok )
#define FORGET_Frame() \
( (void)TT_Forget_Frame( &frame ) )
#define GET_Byte() TT_Get_Byte ( &frame )
#define GET_Char() TT_Get_Char ( &frame )
#define GET_UShort() TT_Get_UShort( &frame )
#define GET_Short() TT_Get_Short ( &frame )
#define GET_Long() TT_Get_Long ( &frame )
#define GET_ULong() TT_Get_ULong ( &frame )
#define GET_Tag4() TT_Get_ULong ( &frame )
#define FILE_Pos() TT_File_Pos ( stream )
#define FILE_Seek( _position_ ) \
( (error = TT_Seek_File( stream, \
(Long)(_position_) )) != TT_Err_Ok )
#define FILE_Skip( _distance_ ) \
( (error = TT_Skip_File( stream, \
(Long)(_distance_) )) != TT_Err_Ok )
#define FILE_Read( buffer, count ) \
( (error = TT_Read_File ( stream, \
buffer, \
(Long)(count) )) != TT_Err_Ok )
#define FILE_Read_At( pos, buffer, count ) \
( (error = TT_Read_At_File( stream, \
(Long)(pos), \
buffer, \
(Long)(count) )) != TT_Err_Ok )
#else /* thread-safe implementation */
/* Define stream locals with frame -- nothing in thread-safe mode */
#define DEFINE_STREAM_LOCALS \
TT_Error error
/* Define stream locals without frame -- nothing in thread-safe mode */
#define DEFINE_STREAM_LOCALS_WO_FRAME \
TT_Error error
/* Define locals with a predefined stream in reentrant mode -- see ttload.c */
#define DEFINE_LOAD_LOCALS( STREAM ) \
TT_Error error
/* Define locals without frame with a predefined stream - see ttload.c */
#define DEFINE_LOAD_LOCALS_WO_FRAME( STREAM ) \
TT_Error error
/* Define all locals necessary to access a font file */
#define DEFINE_ALL_LOCALS \
TT_Error error; \
DEFINE_A_STREAM
#define ACCESS_Frame( _size_ ) \
( (error = TT_Access_Frame( (Long)(_size_) )) != TT_Err_Ok )
#define CHECK_ACCESS_Frame( _size_ ) \
( (error = TT_Check_And_Access_Frame( (Long)(_size_) )) != TT_Err_Ok )
#define FORGET_Frame() \
( (void)TT_Forget_Frame() )
#define GET_Byte() TT_Get_Byte ()
#define GET_Char() TT_Get_Char ()
#define GET_UShort() TT_Get_UShort()
#define GET_Short() TT_Get_Short ()
#define GET_Long() TT_Get_Long ()
#define GET_ULong() TT_Get_ULong ()
#define GET_Tag4() TT_Get_ULong ()
#define FILE_Pos() TT_File_Pos()
#define FILE_Seek( _position_ ) \
( (error = TT_Seek_File( (Long)(_position_) )) != TT_Err_Ok )
#define FILE_Skip( _distance_ ) \
( (error = TT_Skip_File( (Long)(_distance_) )) != TT_Err_Ok )
#define FILE_Read( buffer, count ) \
( (error = TT_Read_File ( buffer, \
(Long)(count) )) != TT_Err_Ok )
#define FILE_Read_At( pos, buffer, count ) \
( (error = TT_Read_At_File( (Long)(pos), \
buffer, \
(Long)(count) )) != TT_Err_Ok )
#endif /* TT_CONFIG_OPTION_THREAD_SAFE */
#ifdef __cplusplus
}
#endif
#endif /* TTLOAD_H */
/* END */
TTMEMORY.C 、、、、、、、、、、、、、、、、、、、、、、、、、、、、
/*******************************************************************
*
* ttmemory.c 1.2
*
* Memory management component (body).
*
* Copyright 1996-1999 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used
* modified and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*
* Changes between 1.1 and 1.2:
*
* - the font pool is gone.
*
* - introduced the FREE macro and the Free function for
* future use in destructors.
*
* - Init_FontPool() is now a macro to allow the compilation of
* 'legacy' applications (all four test programs have been updated).
*
******************************************************************/
#include "ttdebug.h"
#include "ttmemory.h"
#include "ttengine.h"
/* required by the tracing mode */
#undef TT_COMPONENT
#define TT_COMPONENT trace_memory
#ifdef DEBUG_MEMORY
#include <stdio.h>
#define MAX_TRACKED_BLOCKS 1024
struct TMemRec_
{
void* base;
Long size;
};
typedef struct TMemRec_ TMemRec;
static TMemRec pointers[MAX_TRACKED_BLOCKS + 1];
static Int num_alloc;
static Int num_free;
static Int num_realloc; /* counts only `real' reallocations
(i.e., an existing buffer will be resized
to a value larger than zero */
static Int fail_alloc;
static Int fail_realloc;
static Int fail_free;
#endif /* DEBUG_MEMORY */
#ifndef TT_CONFIG_OPTION_THREAD_SAFE
Long TTMemory_Allocated;
Long TTMemory_MaxAllocated;
#endif
/*******************************************************************
*
* Function : TT_Alloc
*
* Description : Allocates memory from the heap buffer.
*
* Input : Size size of the memory to be allocated
* P pointer to a buffer pointer
*
* Output : Error code.
*
* NOTE : The newly allocated block should _always_ be zeroed
* on return. Many parts of the engine rely on this to
* work properly.
*
******************************************************************/
EXPORT_FUNC
TT_Error TT_Alloc( ULong Size, void** P )
{
#ifdef DEBUG_MEMORY
Int i;
#endif
if ( !P )
return TT_Err_Invalid_Argument;
if ( Size > (size_t)-1 )
return TT_Err_Out_Of_Memory;
if ( Size > 0 )
{
//*P = (void*)malloc( Size );
*P = (void*)dlmalloc( Size );
if ( !*P )
return TT_Err_Out_Of_Memory;
#ifndef TT_CONFIG_OPTION_THREAD_SAFE
TTMemory_Allocated += Size;
TTMemory_MaxAllocated += Size;
#endif
#ifdef DEBUG_MEMORY
num_alloc++;
i = 0;
while ( i < MAX_TRACKED_BLOCKS && pointers[i].base != NULL )
i++;
if ( i >= MAX_TRACKED_BLOCKS )
fail_alloc++;
else
{
pointers[i].base = *P;
pointers[i].size = Size;
}
#endif /* DEBUG_MEMORY */
MEM_Set( *P, 0, Size );
}
else
*P = NULL;
return TT_Err_Ok;
}
#ifdef TT_CONFIG_OPTION_EXTEND_ENGINE
/*******************************************************************
*
* Function : TT_Realloc
*
* Description : Reallocates memory from the heap buffer.
*
* Input : Size new size of the memory to be allocated;
* if zero, TT_Free() will be called
* P pointer to a buffer pointer; if *P == NULL,
* TT_Alloc() will be called
*
* Output : Error code.
*
* NOTES : It's not necessary to zero the memory in case the
* reallocated buffer is larger than before -- the
* application has to take care of this.
*
* If the memory request fails, TT_Free() will be
* called on *P, and TT_Err_Out_Of_Memory returned.
*
******************************************************************/
EXPORT_FUNC
TT_Error TT_Realloc( ULong Size, void** P )
{
void* Q;
#ifdef DEBUG_MEMORY
Int i;
#endif
if ( !P )
return TT_Err_Invalid_Argument;
if ( !*P )
return TT_Alloc( Size, P );
if ( Size == 0 )
return TT_Free( P );
if ( Size > (size_t)-1 )
{
TT_Free( *P );
return TT_Err_Out_Of_Memory;
}
//Q = (void*)realloc( *P, Size );
Q = (void*)dlrealloc( *P, Size );
if ( !Q )
{
TT_Free( *P );
return TT_Err_Out_Of_Memory;
}
#ifdef DEBUG_MEMORY
num_realloc++;
i = 0;
while ( i < MAX_TRACKED_BLOCKS && pointers[i].base != *P )
i++;
if ( i >= MAX_TRACKED_BLOCKS )
fail_realloc++;
else
{
#ifndef TT_CONFIG_OPTION_THREAD_SAFE
TTMemory_Allocated += Size - pointers[i].size;
if ( Size > pointers[i].size )
TTMemory_MaxAllocated += Size - pointers[i].size;
#endif
pointers[i].base = Q;
pointers[i].size = size;
}
#endif /* DEBUG_MEMORY */
*P = Q;
return TT_Err_Ok;
}
#endif /* TT_CONFIG_OPTION_EXTEND_ENGINE */
/*******************************************************************
*
* Function : TT_Free
*
* Description : Releases a previously allocated block of memory.
*
* Input : P pointer to memory block
*
* Output : Always SUCCESS.
*
* Note : The pointer must _always_ be set to NULL by this function.
*
******************************************************************/
EXPORT_FUNC
TT_Error TT_Free( void** P )
{
#ifdef DEBUG_MEMORY
Int i;
#endif /* DEBUG_MEMORY */
if ( !P || !*P )
return TT_Err_Ok;
#ifdef DEBUG_MEMORY
num_free++;
i = 0;
while ( i < MAX_TRACKED_BLOCKS && pointers[i].base != *P )
i++;
if ( i >= MAX_TRACKED_BLOCKS )
fail_free++;
else
{
#ifndef TT_CONFIG_OPTION_THREAD_SAFE
TTMemory_Allocated -= pointers[i].size;
#endif
pointers[i].base = NULL;
pointers[i].size = 0;
}
#endif /* DEBUG_MEMORY */
dlfree( *P );
*P = NULL;
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : TTMemory_Init
*
* Description : Initializes the memory.
*
* Output : Always SUCCESS.
*
******************************************************************/
LOCAL_FUNC
TT_Error TTMemory_Init( void )
{
#ifdef DEBUG_MEMORY
Int i;
for ( i = 0; i < MAX_TRACKED_BLOCKS; i++ )
{
pointers[i].base = NULL;
pointers[i].size = 0;
}
num_alloc = 0;
num_realloc = 0;
num_free = 0;
fail_alloc = 0;
fail_realloc = 0;
fail_free = 0;
#endif
#ifndef TT_CONFIG_OPTION_THREAD_SAFE
TTMemory_Allocated = 0;
TTMemory_MaxAllocated = 0;
#endif
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : TTMemory_Done
*
* Description : Finalizes memory usage.
*
* Output : Always SUCCESS.
*
******************************************************************/
LOCAL_FUNC
TT_Error TTMemory_Done( void )
{
#ifdef DEBUG_MEMORY
Int i, num_leaked, tot_leaked;
num_leaked = 0;
tot_leaked = 0;
for ( i = 0; i < MAX_TRACKED_BLOCKS; i++ )
{
if ( pointers[i].base )
{
num_leaked ++;
tot_leaked += pointers[i].size;
}
}
fprintf( stderr,
"%d memory allocations, of which %d failed\n",
num_alloc,
fail_alloc );
fprintf( stderr,
"%d memory reallocations, of which %d failed\n",
num_realloc,
fail_realloc );
fprintf( stderr,
"%d memory frees, of which %d failed\n",
num_free,
fail_free );
if ( num_leaked > 0 )
{
fprintf( stderr,
"There are %d leaked memory blocks, totalizing %d bytes\n",
num_leaked, tot_leaked );
for ( i = 0; i < MAX_TRACKED_BLOCKS; i++ )
{
if ( pointers[i].base )
{
fprintf( stderr,
"index: %4d (base: $%08lx, size: %08ld)\n",
i,
(long)pointers[i].base,
pointers[i].size );
}
}
}
else
fprintf( stderr, "No memory leaks !\n" );
#endif /* DEBUG_MEMORY */
return TT_Err_Ok;
}
/* END */
TTMEMORY.H 、、、、、、、、、、、、、、、、、、、、、、、、、、、
/*******************************************************************
*
* ttmemory.h 1.2
*
* Memory management component (specification).
*
* Copyright 1996-1999 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used
* modified and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
* Changes between 1.2 and 1.1:
*
* - the font pool is gone! All allocations are now performed
* with malloc() and free().
*
* - introduced the FREE() macro and the Free() function for
* future use in destructors.
*
* - Init_FontPool() is now a macro to allow the compilation of
* 'legacy' applications (all four test programs have been updated).
*
******************************************************************/
#ifndef TTMEMORY_H
#define TTMEMORY_H
#include "ttconfig.h"
#include "tttypes.h"
//#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
#define MEM_Set( dest, byte, count ) memset( dest, byte, count )
#ifdef HAVE_MEMCPY
#define MEM_Copy( dest, source, count ) memcpy( dest, source, count )
#else
#define MEM_Copy( dest, source, count ) bcopy( source, dest, count )
#endif
#ifdef HAVE_MEMMOVE
#define MEM_Move( dest, source, count ) memmove( dest, source, count )
#else
#define MEM_Move( dest, source, count ) bcopy( source, dest, count )
#endif
#define MEM_Alloc( _pointer_, _size_ ) \
TT_Alloc( _size_, (void**)&(_pointer_) )
#define MEM_Realloc( _pointer_, _size_ ) \
TT_Realloc( _size_, (void**)&(_pointer_) )
#define ALLOC( _pointer_, _size_ ) \
( ( error = MEM_Alloc( _pointer_, _size_ ) ) != TT_Err_Ok )
#define ALLOC_ARRAY( _pointer_, _count_, _type_ ) \
( ( error = MEM_Alloc( _pointer_, \
(_count_) * sizeof ( _type_ ) ) ) != TT_Err_Ok )
#define REALLOC( _pointer_, _size_ ) \
( ( error = MEM_Realloc( _pointer_, _size_ ) ) != TT_Err_Ok )
#define REALLOC_ARRAY( _pointer_, _count_, _type_ ) \
( (error = MEM_Realloc( _pointer_, \
(_count_) * sizeof ( _type_ ) ) ) != TT_Err_Ok )
#define FREE( _pointer_ ) \
TT_Free( (void**)&(_pointer_) )
/* Allocate a block of memory of 'Size' bytes from the heap, and */
/* sets the pointer '*P' to its address. If 'Size' is 0, or in */
/* case of error, the pointer is always set to NULL. */
EXPORT_DEF
TT_Error TT_Alloc( ULong Size, void** P );
#ifdef TT_CONFIG_OPTION_EXTEND_ENGINE
/* Reallocates a block of memory pointed to by '*P' to 'Size' */
/* bytes from the heap, possibly changing '*P'. If 'Size' is 0, */
/* TT_Free() is called, if '*P' is NULL, TT_Alloc() is called. */
/* '*P' is freed (if it's non-NULL) in case of error. */
EXPORT_DEF
TT_Error TT_Realloc( ULong Size, void** P );
#endif /* TT_CONFIG_OPTION_EXTEND_ENGINE */
/* Releases a block that was previously allocated through Alloc. */
/* Note that the function returns successfully when P or *P are */
/* already NULL. The pointer '*P' is set to NULL on exit in */
/* case of success. */
EXPORT_DEF
TT_Error TT_Free( void** P );
/* For "legacy" applications, that should be re-coded. */
/* Note that this won't release the previously allocated font pool. */
#define Init_FontPool( x, y ) while( 0 ) { }
LOCAL_DEF TT_Error TTMemory_Init( void );
LOCAL_DEF TT_Error TTMemory_Done( void );
#ifdef __cplusplus
}
#endif
#endif /* TTMEMORY_H */
/* END */
TTMUTEX.C 、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
/*******************************************************************
*
* ttmutex.c 1.0
*
* Mutual exclusion object, single-threaded implementation
*
* 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.
*
* NOTE: This is a generic non-functional implementation
* that you are welcome to refine for your own system.
*
* Please name your system-specific source with a
* different name (like ttmutex-os2.c or ttmutex-linux.c)
* and change your makefile accordingly.
*
******************************************************************/
#include "ttmutex.h"
/* required by the tracing mode */
#undef TT_COMPONENT
#define TT_COMPONENT trace_mutex
/* ANSI C prevents the compilation of empty units. We thus introduce */
/* a dummy typedef to get rid of compiler warnings/errors. */
/* Note that gcc's -ansi -pedantic does not report any error here. */
/* Watcom, VC++ or Borland C++ do however. */
typedef void _ttmutex_to_satisfy_ANSI_C_;
#ifdef TT_CONFIG_OPTION_THREAD_SAFE
LOCAL_FUNC
void TT_Mutex_Create ( TMutex* mutex )
{
*mutex = (void*)-1;
/* Replace this line with your own mutex creation code */
}
LOCAL_FUNC
void TT_Mutex_Delete ( TMutex* mutex )
{
*mutex = (void*)0;
/* Replace this line with your own mutex destruction code */
}
LOCAL_FUNC
void TT_Mutex_Lock ( TMutex* mutex )
{
/* NOTE: It is legal to call this function with a NULL argument */
/* in which case an immediate return is appropriate. */
if ( !mutex )
return;
; /* Insert your own mutex locking code here */
}
LOCAL_FUNC
void TT_Mutex_Release( TMutex* mutex )
{
/* NOTE: It is legal to call this function with a NULL argument */
/* in which case an immediate return is appropriate */
if ( !mutex )
return;
; /* Insert your own mutex release code here */
}
#endif /* TT_CONFIG_OPTION_THREAD_SAFE */
/* END */
TTMUTEX.H 、、、、、、、、、、、、、、、、、、、、、、、、、、、、
/*******************************************************************
*
* ttmutex.h 1.0
*
* Mutual exclusion object / dummy generic interface.
*
* Copyright 1996-1999 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used
* modified and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
* Note: This file provides a generic interface. The implementation
* to compile depends on your system and the type of
* library you want to build (either singly-threaded,
* thread-safe or re-entrant).
*
* Please read the technical documentation for more details.
*
******************************************************************/
#ifndef TTMUTEX_H
#define TTMUTEX_H
#include "ttconfig.h"
typedef void* TMutex; /* typeless reference to a mutex */
#ifdef TT_CONFIG_OPTION_THREAD_SAFE /* thread-safe and re-entrant builds */
#define MUTEX_Create( mutex ) TT_Mutex_Create ( &(mutex) )
#define MUTEX_Destroy( mutex ) TT_Mutex_Delete ( &(mutex) )
#define MUTEX_Lock( mutex ) TT_Mutex_Lock ( &(mutex) )
#define MUTEX_Release( mutex ) TT_Mutex_Release( &(mutex) )
LOCAL_DEF void TT_Mutex_Create ( TMutex* mutex ); /* Create a new mutex */
LOCAL_DEF void TT_Mutex_Delete ( TMutex* mutex ); /* Delete a mutex */
LOCAL_DEF void TT_Mutex_Lock ( TMutex* mutex ); /* Lock a mutex. */
LOCAL_DEF void TT_Mutex_Release( TMutex* mutex ); /* Release a mutex */
#else /* for the single-thread build */
#define MUTEX_Create( mutex ) /* nothing */
#define MUTEX_Destroy( mutex ) /* nothing */
#define MUTEX_Lock( mutex ) /* nothing */
#define MUTEX_Release( mutex ) /* nothing */
/* No code will be generated for mutex operations */
#endif /* TT_CONFIG_OPTION_THREAD_SAFE */
#endif /* TTMUTEX_H */
/* END */
TTOBJS.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 */
TTOBJS.H 、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
/*******************************************************************
*
* ttobjs.h 1.0
*
* Objects definition unit.
*
* Copyright 1996-1999 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used
* modified and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
******************************************************************/
#ifndef TTOBJS_H
#define TTOBJS_H
#include "ttconfig.h"
#include "ttengine.h"
#include "ttmutex.h"
#include "ttcache.h"
#include "tttables.h"
#include "ttcmap.h"
#ifdef __cplusplus
extern "C" {
#endif
/* */
/* This file contains the definitions and methods of the four */
/* kinds of objects managed by the FreeType engine. These are: */
/* */
/* */
/* Face objects: */
/* */
/* There is always one face object per opened TrueType font */
/* file, and only one. The face object contains data that is */
/* independent of current transform/scaling/rotation and */
/* pointsize, or glyph index. This data is made of several */
/* critical tables that are loaded on face object creation. */
/* */
/* A face object tracks all active and recycled objects of */
/* the instance and execution context classes. Destroying a face */
/* object will automatically destroy all associated instances. */
/* */
/* */
/* Instance objects: */
/* */
/* An instance object always relates to a given face object, */
/* known as its 'parent' or 'owner', and contains only the */
/* data that is specific to one given pointsize/transform of */
/* the face. You can only create an instance from a face object. */
/* */
/* An instance's current transform/pointsize can be changed */
/* at any time using a single high-level API call, */
/* TT_Reset_Instance(). */
/* */
/* Execution Context objects: */
/* */
/* An execution context (or context in short) relates to a face. */
/* It contains the data and tables that are necessary to load */
/* and hint (i.e. execute the glyph instructions of) one glyph. */
/* A context is a transient object that is queried/created on */
/* the fly: client applications never deal with them directly. */
/* */
/* */
/* Glyph objects: */
/* */
/* A glyph object contains only the minimal glyph information */
/* needed to render one glyph correctly. This means that a glyph */
/* object really contains tables that are sized to hold the */
/* contents of _any_ glyph of a given face. A client application */
/* can usually create one glyph object for a given face, then use */
/* it for all subsequent loads. */
/* */
/* Here is an example of a client application : */
/* (NOTE: No error checking performed here!) */
/* */
/* */
/* TT_Face face; -- face handle */
/* TT_Instance ins1, ins2; -- two instance handles */
/* TT_Glyph glyph; -- glyph handle */
/* */
/* TT_Init_FreeType(); */
/* */
/* -- Initialize the engine. This must be done prior to _any_ */
/* operation. */
/* */
/* TT_Open_Face( "/some/face/name.ttf", &face ); */
/* */
/* -- create the face object. This call opens the font file */
/* */
/* TT_New_Instance( face, &ins1 ); */
/* TT_New_Instance( face, &ins2 ); */
/* */
/* TT_Set_Instance_PointSize( ins1, 8 ); */
/* TT_Set_Instance_PointSize( ins2, 12 ); */
/* */
/* -- create two distinct instances of the same face */
/* -- ins1 is pointsize 8 at resolution 96 dpi */
/* -- ins2 is pointsize 12 at resolution 96 dpi */
/* */
/* TT_New_Glyph( face, &glyph ); */
/* */
/* -- create a new glyph object which will receive the contents */
/* of any glyph of 'face' */
/* */
/* TT_Load_Glyph( ins1, glyph, 64, DEFAULT_GLYPH_LOAD ); */
/* */
/* -- load glyph indexed 64 at pointsize 8 in the 'glyph' object */
/* -- NOTE: This call will fail if the instance and the glyph */
/* do not relate to the same face object. */
/* */
/* TT_Get_Outline( glyph, &outline ); */
/* */
/* -- extract the glyph outline from the object and copies it */
/* to the 'outline' record */
/* */
/* TT_Get_Metrics( glyph, &metrics ); */
/* */
/* -- extract the glyph metrics and put them into the 'metrics' */
/* record */
/* */
/* TT_Load_Glyph( ins2, glyph, 64, DEFAULT_GLYPH_LOAD ); */
/* */
/* -- load the same glyph at pointsize 12 in the 'glyph' object */
/* */
/* */
/* TT_Close_Face( &face ); */
/* */
/* -- destroy the face object. This will destroy 'ins1' and */
/* 'ins2'. However, the glyph object will still be available */
/* */
/* TT_Done_FreeType(); */
/* */
/* -- Finalize the engine. This will also destroy all pending */
/* glyph objects (here 'glyph'). */
struct TFace_;
struct TInstance_;
struct TExecution_Context_;
struct TGlyph_;
typedef struct TFace_ TFace;
typedef TFace* PFace;
typedef struct TInstance_ TInstance;
typedef TInstance* PInstance;
typedef struct TExecution_Context_ TExecution_Context;
typedef TExecution_Context* PExecution_Context;
typedef struct TGlyph_ TGlyph;
typedef TGlyph* PGlyph;
/*************************************************************/
/* */
/* ADDITIONAL SUBTABLES */
/* */
/* These tables are not precisely defined by the specs */
/* but their structures is implied by the TrueType font */
/* file layout. */
/* */
/*************************************************************/
/* Graphics State */
/* */
/* The Graphics State (GS) is managed by the */
/* instruction field, but does not come from */
/* the font file. Thus, we can use 'int's */
/* where needed. */
struct TGraphicsState_
{
UShort rp0;
UShort rp1;
UShort rp2;
TT_UnitVector dualVector;
TT_UnitVector projVector;
TT_UnitVector freeVector;
Long loop;
TT_F26Dot6 minimum_distance;
Int round_state;
Bool auto_flip;
TT_F26Dot6 control_value_cutin;
TT_F26Dot6 single_width_cutin;
TT_F26Dot6 single_width_value;
Short delta_base;
Short delta_shift;
Byte instruct_control;
Bool scan_control;
Int scan_type;
UShort gep0;
UShort gep1;
UShort gep2;
};
typedef struct TGraphicsState_ TGraphicsState;
LOCAL_DEF
const TGraphicsState Default_GraphicsState;
/*************************************************************/
/* */
/* EXECUTION SUBTABLES */
/* */
/* These sub-tables relate to instruction execution. */
/* */
/*************************************************************/
#define MAX_CODE_RANGES 3
/* There can only be 3 active code ranges at once: */
/* - the Font Program */
/* - the CVT Program */
/* - a glyph's instructions set */
#define TT_CodeRange_Font 1
#define TT_CodeRange_Cvt 2
#define TT_CodeRange_Glyph 3
struct TCodeRange_
{
PByte Base;
ULong Size;
};
typedef struct TCodeRange_ TCodeRange;
typedef TCodeRange* PCodeRange;
/* Defintion of a code range */
/* */
/* Code ranges can be resident to a glyph (i.e. the Font Program) */
/* while some others are volatile (Glyph instructions). */
/* Tracking the state and presence of code ranges allows function */
/* and instruction definitions within a code range to be forgotten */
/* when the range is discarded. */
typedef TCodeRange TCodeRangeTable[MAX_CODE_RANGES];
/* defines a function/instruction definition record */
struct TDefRecord_
{
Int Range; /* in which code range is it located ? */
ULong Start; /* where does it start ? */
Int Opc; /* function #, or instruction code */
Bool Active; /* is it active ? */
};
typedef struct TDefRecord_ TDefRecord;
typedef TDefRecord* PDefRecord;
typedef TDefRecord* PDefArray;
/* defines a call record, used to manage function calls. */
struct TCallRecord_
{
Int Caller_Range;
ULong Caller_IP;
Long Cur_Count;
ULong Cur_Restart;
};
typedef struct TCallRecord_ TCallRecord;
typedef TCallRecord* PCallRecord;
typedef TCallRecord* PCallStack; /* defines a simple call stack */
/* This type defining a set of glyph points will be used to represent */
/* each zone (regular and twilight) during instructions decoding. */
struct TGlyph_Zone_
{
UShort n_points; /* number of points in zone */
Short n_contours; /* number of contours */
TT_Vector* org; /* original points coordinates */
TT_Vector* cur; /* current points coordinates */
Byte* touch; /* current touch flags */
UShort* contours; /* contour end points */
};
typedef struct TGlyph_Zone_ TGlyph_Zone;
typedef TGlyph_Zone* PGlyph_Zone;
#ifndef TT_STATIC_INTEPRETER /* indirect implementation */
#define EXEC_OPS PExecution_Context exc,
#define EXEC_OP PExecution_Context exc
#define EXEC_ARGS exc,
#define EXEC_ARG exc
#else /* static implementation */
#define EXEC_OPS /* void */
#define EXEC_OP /* void */
#define EXEC_ARGS /* void */
#define EXEC_ARG /* void */
#endif
/* Rounding function, as used by the interpreter */
typedef TT_F26Dot6 (*TRound_Function)( EXEC_OPS TT_F26Dot6 distance,
TT_F26Dot6 compensation );
/* Point displacement along the freedom vector routine, as */
/* used by the interpreter */
typedef void (*TMove_Function)( EXEC_OPS PGlyph_Zone zone,
UShort point,
TT_F26Dot6 distance );
/* Distance projection along one of the proj. vectors, as used */
/* by the interpreter */
typedef TT_F26Dot6 (*TProject_Function)( EXEC_OPS TT_Vector* v1,
TT_Vector* v2 );
/* reading a cvt value. Take care of non-square pixels when needed */
typedef TT_F26Dot6 (*TGet_CVT_Function)( EXEC_OPS ULong index );
/* setting or moving a cvt value. Take care of non-square pixels */
/* when needed */
typedef void (*TSet_CVT_Function)( EXEC_OPS ULong index,
TT_F26Dot6 value );
/* subglyph transformation record */
struct TTransform_
{
TT_Fixed xx, xy; /* transformation */
TT_Fixed yx, yy; /* matrix */
TT_F26Dot6 ox, oy; /* offsets */
};
typedef struct TTransform_ TTransform;
typedef TTransform* PTransform;
/* subglyph loading record. Used to load composite components */
struct TSubglyph_Record_
{
Long index; /* subglyph index; initialized with -1 */
Bool is_scaled; /* is the subglyph scaled? */
Bool is_hinted; /* should it be hinted? */
Bool preserve_pps; /* preserve phantom points? */
Long file_offset;
TT_Big_Glyph_Metrics metrics;
TGlyph_Zone zone;
Long arg1; /* first argument */
Long arg2; /* second argument */
UShort element_flag; /* current load element flag */
TTransform transform; /* transform */
TT_Vector pp1, pp2; /* phantom points */
};
typedef struct TSubglyph_Record_ TSubglyph_Record;
typedef TSubglyph_Record* PSubglyph_Record;
typedef TSubglyph_Record* PSubglyph_Stack;
/* A note regarding non-squared pixels: */
/* */
/* (This text will probably go into some docs at some time, for */
/* now, it is kept there to explain some definitions in the */
/* TIns_Metrics record). */
/* */
/* The CVT is a one-dimensional array containing values that */
/* control certain important characteristics in a font, like */
/* the height of all capitals, all lowercase letter, default */
/* spacing or stem width/height. */
/* */
/* These values are found in FUnits in the font file, and must be */
/* scaled to pixel coordinates before being used by the CVT and */
/* glyph programs. Unfortunately, when using distinct x and y */
/* resolutions (or distinct x and y pointsizes), there are two */
/* possible scalings. */
/* */
/* A first try was to implement a 'lazy' scheme where all values */
/* were scaled when first used. However, while some values are always */
/* used in the same direction, and some other are used in many */
/* different circumstances and orientations. */
/* */
/* I have found a simpler way to do the same, and it even seems to */
/* work in most of the cases: */
/* */
/* - all CVT values are scaled to the maximum ppem size */
/* */
/* - when performing a read or write in the CVT, a ratio factor */
/* is used to perform adequate scaling. Example: */
/* */
/* x_ppem = 14 */
/* y_ppem = 10 */
/* */
/* we choose ppem = x_ppem = 14 as the CVT scaling size. All cvt */
/* entries are scaled to it. */
/* */
/* x_ratio = 1.0 */
/* y_ratio = y_ppem/ppem (< 1.0) */
/* */
/* we compute the current ratio like: */
/* */
/* - if projVector is horizontal, */
/* ratio = x_ratio = 1.0 */
/* - if projVector is vertical, */
/* ratop = y_ratio */
/* - else, */
/* ratio = sqrt((proj.x*x_ratio)^2 + (proj.y*y_ratio)^2) */
/* */
/* reading a cvt value returns ratio * cvt[index] */
/* writing a cvt value in pixels cvt[index] / ratio */
/* */
/* the current ppem is simply ratio * ppem */
/* */
/* metrics used by the instance and execution context objects */
struct TIns_Metrics_
{
TT_F26Dot6 pointSize; /* point size. 1 point = 1/72 inch. */
UShort x_resolution; /* device horizontal resolution in dpi. */
UShort y_resolution; /* device vertical resolution in dpi. */
UShort x_ppem; /* horizontal pixels per EM */
UShort y_ppem; /* vertical pixels per EM */
Long x_scale1;
Long x_scale2; /* used to scale FUnits to fractional pixels */
Long y_scale1;
Long y_scale2; /* used to scale FUnits to fractional pixels */
/* for non-square pixels */
Long x_ratio;
Long y_ratio;
UShort ppem; /* maximum ppem size */
Long ratio; /* current ratio */
Long scale1;
Long scale2; /* scale for ppem */
TT_F26Dot6 compensations[4]; /* device-specific compensations */
Bool rotated; /* `is the glyph rotated?'-flag */
Bool stretched; /* `is the glyph stretched?'-flag */
};
typedef struct TIns_Metrics_ TIns_Metrics;
typedef TIns_Metrics* PIns_Metrics;
/***********************************************************************/
/* */
/* FreeType Face Type */
/* */
/***********************************************************************/
struct TFace_
{
/* parent engine instance for the face object */
PEngine_Instance engine;
/* i/o stream */
TT_Stream stream;
/* used only by the threaded builds of the library */
TMutex lock;
/* TrueType collection header, if any was found */
TTTCHeader ttcHeader;
/* maximum profile table, as found in the TrueType file */
TMaxProfile maxProfile;
/* Note: */
/* it seems that some maximum values cannot be */
/* taken directly from this table, but rather by */
/* combining some of its fields; e.g. the max. */
/* number of points seems to be given by */
/* MAX( maxPoints, maxCompositePoints ) */
/* */
/* For this reason, we define later our own */
/* max values that are used to load and allocate */
/* further tables. */
TT_Header fontHeader; /* the font header, as */
/* found in the TTF file */
TT_Horizontal_Header horizontalHeader; /* the horizontal header */
Bool verticalInfo; /* True when vertical table */
TT_Vertical_Header verticalHeader; /* is present in the font */
TT_OS2 os2; /* 'OS/2' table */
TT_Postscript postscript; /* 'Post' table */
TT_Hdmx hdmx; /* 'Hdmx' table */
TName_Table nameTable; /* name table */
TGasp gasp; /* the 'gasp' table */
/* The directory of TrueType tables for this typeface */
UShort numTables;
PTableDirEntry dirTables;
/* The directory of character mappings table for */
/* this typeface */
UShort numCMaps;
PCMapTable cMaps;
/* The glyph locations table */
ULong numLocations; /* UShort is not enough */
#ifndef TT_HUGE_PTR
PStorage glyphLocations;
#else
Storage TT_HUGE_PTR * glyphLocations;
#endif
/* NOTE : The "hmtx" is now part of the horizontal header */
/* the font program, if any */
ULong fontPgmSize;
PByte fontProgram;
/* the cvt program, if any */
ULong cvtPgmSize;
PByte cvtProgram;
/* the original, unscaled, control value table */
ULong cvtSize;
PShort cvt;
/* The following values _must_ be set by the */
/* maximum profile loader */
UShort numGlyphs; /* the face's total number of glyphs */
UShort maxPoints; /* max glyph points number, simple and composite */
UShort maxContours; /* max glyph contours numb, simple and composite */
UShort maxComponents; /* max components in a composite glyph */
/* the following are object caches to track active */
/* and recycled instances and execution contexts */
/* objects. See 'ttcache.h' */
TCache instances; /* current instances for this face */
TCache glyphs; /* current glyph containers for this face */
/* A typeless pointer to the face object extensions defined */
/* in the 'ttextend.*' files. */
void* extension;
Int n_extensions; /* number of extensions */
/* Use extensions to provide additional capabilities to the */
/* engine. Read the developer's guide in the documentation */
/* directory to know how to do that. */
/* a generic pointer for client use - see TT_Set/Get_Face_Pointer */
void* generic;
};
/***********************************************************************/
/* */
/* FreeType Instance Type */
/* */
/***********************************************************************/
struct TInstance_
{
PFace owner; /* face object */
Bool valid;
TIns_Metrics metrics;
UShort numFDefs; /* number of function definitions */
UShort maxFDefs;
PDefArray FDefs; /* table of FDefs entries */
UShort numIDefs; /* number of instruction definitions */
UShort maxIDefs;
PDefArray IDefs; /* table of IDefs entries */
Int maxFunc; /* maximum function definition id */
Int maxIns; /* maximum instruction definition id */
TCodeRangeTable codeRangeTable;
TGraphicsState GS;
TGraphicsState default_GS;
ULong cvtSize; /* the scaled control value table */
PLong cvt;
ULong storeSize; /* The storage area is now part of the */
PLong storage; /* instance */
TGlyph_Zone twilight; /* The instance's twilight zone */
/* debugging variables */
/* When using the debugger, we must keep the */
/* execution context tied to the instance */
/* object rather than asking it on demand */
Bool debug;
PExecution_Context context;
/* a generic pointer for client use - see TT_Set/Get_Instance_Pointer */
void* generic;
};
/***********************************************************************/
/* */
/* FreeType Execution Context Type */
/* */
/***********************************************************************/
struct TExecution_Context_
{
PFace face;
PInstance instance;
/* instructions state */
TT_Error error; /* last execution error */
Long top; /* top of exec. stack */
ULong stackSize; /* size of exec. stack */
PStorage stack; /* current exec. stack */
Long args;
ULong new_top; /* new top after exec. */
TGlyph_Zone zp0, /* zone records */
zp1,
zp2,
pts,
twilight;
TIns_Metrics metrics; /* instance metrics */
TGraphicsState GS; /* current graphics state */
Int curRange; /* current code range number */
PByte code; /* current code range */
ULong IP; /* current instruction pointer */
ULong codeSize; /* size of current range */
Byte opcode; /* current opcode */
Int length; /* length of current opcode */
Bool step_ins; /* true if the interpreter must */
/* increment IP after ins. exec */
ULong cvtSize;
PLong cvt;
ULong glyphSize; /* glyph instructions buffer size */
PByte glyphIns; /* glyph instructions buffer */
UShort numFDefs; /* number of function defs */
UShort maxFDefs; /* maximum number of function defs */
PDefRecord FDefs; /* table of FDefs entries */
UShort numIDefs; /* number of instruction defs */
UShort maxIDefs; /* maximum number of instruction defs */
PDefRecord IDefs; /* table of IDefs entries */
Int maxFunc;
Int maxIns;
Int callTop, /* top of call stack during execution */
callSize; /* size of call stack */
PCallStack callStack; /* call stack */
UShort maxPoints; /* capacity of this context's "pts" */
UShort maxContours; /* record, expressed in points and */
/* contours.. */
TCodeRangeTable codeRangeTable; /* table of valid coderanges */
/* useful for the debugger */
ULong storeSize; /* size of current storage */
PLong storage; /* storage area */
TT_F26Dot6 period; /* values used for the */
TT_F26Dot6 phase; /* 'SuperRounding' */
TT_F26Dot6 threshold;
/* this seems to be unused */
#if 0
Int cur_ppem; /* ppem along the current proj vector */
#endif
Long scale1; /* scaling values along the current */
Long scale2; /* projection vector too.. */
Bool cached_metrics; /* the ppem is computed lazily. used */
/* to trigger computation when needed */
Bool instruction_trap; /* If True, the interpreter will */
/* exit after each instruction */
TGraphicsState default_GS; /* graphics state resulting from */
/* the prep program */
Bool is_composite; /* ture if the glyph is composite */
Bool pedantic_hinting; /* if true, read and write array */
/* bounds faults halt the hinting */
/* latest interpreter additions */
Long F_dot_P; /* dot product of freedom and projection */
/* vectors */
TRound_Function func_round; /* current rounding function */
TProject_Function func_project, /* current projection function */
func_dualproj, /* current dual proj. function */
func_freeProj; /* current freedom proj. func */
TMove_Function func_move; /* current point move function */
TGet_CVT_Function func_read_cvt; /* read a cvt entry */
TSet_CVT_Function func_write_cvt; /* write a cvt entry (in pixels) */
TSet_CVT_Function func_move_cvt; /* incr a cvt entry (in pixels) */
ULong loadSize;
PSubglyph_Stack loadStack; /* loading subglyph stack */
};
/***********************************************************************/
/* */
/* FreeType Glyph Object Type */
/* */
/***********************************************************************/
struct TGlyph_
{
PFace face;
TT_Big_Glyph_Metrics metrics;
TT_Outline outline;
};
/* The following type is used to load a font from a collection. */
/* See Face_Create in ttobjs.c */
struct TFont_Input_
{
TT_Stream stream; /* input stream */
ULong fontIndex; /* index of font in collection */
PEngine_Instance engine; /* parent engine instance */
};
typedef struct TFont_Input_ TFont_Input;
/********************************************************************/
/* */
/* Code Range Functions */
/* */
/********************************************************************/
/* Goto a specified coderange */
LOCAL_DEF
TT_Error Goto_CodeRange( PExecution_Context exec,
Int range,
ULong IP );
#if 0
/* Return a pointer to a given coderange record. */
/* Used only by the debugger. */
LOCAL_DEF
PCodeRange Get_CodeRange( PExecution_Context exec,
Int range );
#endif
/* Set a given code range properties */
LOCAL_DEF
TT_Error Set_CodeRange( PExecution_Context exec,
Int range,
void* base,
ULong length );
/* Clear a given coderange */
LOCAL_DEF
TT_Error Clear_CodeRange( PExecution_Context exec, Int range );
LOCAL_DEF
PExecution_Context New_Context( PFace face );
LOCAL_DEF
TT_Error Done_Context( PExecution_Context exec );
LOCAL_DEF
TT_Error Context_Load( PExecution_Context exec,
PFace face,
PInstance ins );
LOCAL_DEF
TT_Error Context_Save( PExecution_Context exec,
PInstance ins );
LOCAL_DEF
TT_Error Context_Run( PExecution_Context exec,
Bool debug );
LOCAL_DEF
TT_Error Instance_Init( PInstance ins );
LOCAL_DEF
TT_Error Instance_Reset( PInstance ins );
/********************************************************************/
/* */
/* Handy scaling functions */
/* */
/********************************************************************/
LOCAL_DEF TT_Pos Scale_X( PIns_Metrics metrics, TT_Pos x );
LOCAL_DEF TT_Pos Scale_Y( PIns_Metrics metrics, TT_Pos y );
/********************************************************************/
/* */
/* Component Initializer/Finalizer */
/* */
/* Called from 'freetype.c' */
/* The component must create and register the face, instance and */
/* execution context cache classes before any object can be */
/* managed. */
/* */
/********************************************************************/
LOCAL_DEF TT_Error TTObjs_Init( PEngine_Instance engine );
LOCAL_DEF TT_Error TTObjs_Done( PEngine_Instance engine );
#ifdef __cplusplus
}
#endif
#endif /* TTOBJS_H */
/* END */
TTRASTER.C 、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
/*******************************************************************
*
* ttraster.c 1.5
*
* The FreeType glyph rasterizer (body).
*
* Copyright 1996-1999 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used
* modified and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
* NOTES:
*
* This version supports the following:
*
* - direct grayscaling
* - sub-banding
* - drop-out modes 4 and 5
* - second pass for complete drop-out control (bitmap only)
* - variable precision
*
* Changes between 1.5 and 1.4:
*
* Performance tuning.
*
* Changes between 1.4 and 1.3:
*
* Mainly performance tunings:
*
* - Line_Down() and Bezier_Down() now use the functions Line_Up()
* and Bezier_Up() to do their work.
* - optimized Split_Bezier()
* - optimized linked lists used during sweeps
*
******************************************************************/
#include "ttraster.h"
#include "ttdebug.h"
#include "tttypes.h"
#include "ttengine.h"
#include "ttcalc.h" /* for TT_MulDiv only */
#include "ttmemory.h" /* only used to allocate memory on engine init */
/* required by the tracing mode */
#undef TT_COMPONENT
#define TT_COMPONENT trace_raster
/* The default render pool size */
#define RASTER_RENDER_POOL 64000
/* The size of the two-lines intermediate bitmap used */
/* for anti-aliasing */
#define RASTER_GRAY_LINES 2048
#define Raster_Err_None TT_Err_Ok
#define Raster_Err_Not_Ini TT_Err_Raster_Not_Initialized
#define Raster_Err_Overflow TT_Err_Raster_Pool_Overflow
#define Raster_Err_Neg_Height TT_Err_Raster_Negative_Height
#define Raster_Err_Invalid TT_Err_Raster_Invalid_Value
#define Raster_Err_Gray_Unsupported TT_Err_Raster_Gray_Unsupported
/* FMulDiv means "Fast MulDiv", it is uses in case where 'b' is typically */
/* a small value and the result of (a*b) is known to fit in 32 bits. */
#define FMulDiv( a, b, c ) ( (a) * (b) / (c) )
/* On the other hand, SMulDiv is for "Slow MulDiv", and is used typically */
/* for clipping computations. It simply uses the TT_MulDiv() function */
/* defined in "ttcalc.h" */
/* */
/* So, the following definition fits the bill nicely, and we don't need */
/* to use the one in 'ttcalc' anymore, even for 16-bit systems... */
#define SMulDiv TT_MulDiv
/* Define DEBUG_RASTER if you want to generate a debug version of the */
/* rasterizer. This will progressively draw the glyphs while all the */
/* computation are done directly on the graphics screen (the glyphs */
/* will be inverted). */
/* Note that DEBUG_RASTER should only be used for debugging with b/w */
/* rendering, not with gray levels. */
/* The definition of DEBUG_RASTER should appear in the file */
/* "ttconfig.h". */
#ifdef DEBUG_RASTER
extern Char* Vio; /* A pointer to VRAM or display buffer */
#endif
/* The rasterizer is a very general purpose component, please leave */
/* the following redefinitions there (you never know your target */
/* environment). */
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef NULL
#define NULL (void*)0
#endif
#define MaxBezier 32 /* The maximum number of stacked Bezier curves. */
/* Setting this constant to more than 32 is a */
/* pure waste of space. */
#define Pixel_Bits 6 /* fractional bits of *input* coordinates */
/* States of each line, arc and profile */
enum TStates_
{
Unknown,
Ascending,
Descending,
Flat
};
typedef enum TStates_ TStates;
struct TProfile_;
typedef struct TProfile_ TProfile;
typedef TProfile* PProfile;
struct TProfile_
{
TT_F26Dot6 X; /* current coordinate during sweep */
PProfile link; /* link to next profile - various purpose */
PStorage offset; /* start of profile's data in render pool */
Int flow; /* Profile orientation: Asc/Descending */
Long height; /* profile's height in scanlines */
Long start; /* profile's starting scanline */
UShort countL; /* number of lines to step before this */
/* profile becomes drawable */
PProfile next; /* next profile in same contour, used */
/* during drop-out control */
};
typedef PProfile TProfileList;
typedef PProfile* PProfileList;
/* I use the classic trick of two dummy records for the head and tail */
/* of a linked list; this reduces tests in insertion/deletion/sorting. */
/* NOTE: used during sweeps only. */
/* Simple record used to implement a stack of bands, required */
/* by the sub-banding mechanism */
struct TBand_
{
Short y_min; /* band's minimum */
Short y_max; /* band's maximum */
};
typedef struct TBand_ TBand;
#define AlignProfileSize \
(( sizeof(TProfile)+sizeof(long)-1 ) / sizeof(long))
/* Left fill bitmask */
static const Byte LMask[8] =
{ 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01 };
/* Right fill bitmask */
static const Byte RMask[8] =
{ 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF };
/* prototypes used for sweep function dispatch */
typedef void Function_Sweep_Init( RAS_ARGS Short* min,
Short* max );
typedef void Function_Sweep_Span( RAS_ARGS Short y,
TT_F26Dot6 x1,
TT_F26Dot6 x2,
PProfile left,
PProfile right );
typedef void Function_Sweep_Step( RAS_ARG );
/* NOTE: These operations are only valid on 2's complement processors */
#define FLOOR( x ) ( (x) & -ras.precision )
#define CEILING( x ) ( ((x) + ras.precision - 1) & -ras.precision )
#define TRUNC( x ) ( (signed long)(x) >> ras.precision_bits )
#define FRAC( x ) ( (x) & (ras.precision - 1) )
#define SCALED( x ) ( ((x) << ras.scale_shift) - ras.precision_half )
#ifdef DEBUG_RASTER
#define DEBUG_PSET Pset()
#else
#define DEBUG_PSET
#endif
struct TPoint_
{
Long x, y;
};
typedef struct TPoint_ TPoint;
/* Note that I have moved the location of some fields in the */
/* structure to ensure that the most used variables are used */
/* at the top. Thus, their offset can be coded with less */
/* opcodes, and it results in a smaller executable. */
struct TRaster_Instance_
{
Int precision_bits; /* precision related variables */
Int precision;
Int precision_half;
Long precision_mask;
Int precision_shift;
Int precision_step;
Int precision_jitter;
Int scale_shift; /* == precision_shift for bitmaps */
/* == precision_shift+1 for pixmaps */
PStorage buff; /* The profiles buffer */
PStorage sizeBuff; /* Render pool size */
PStorage maxBuff; /* Profiles buffer size */
PStorage top; /* Current cursor in buffer */
TT_Error error;
PByte flags; /* current flags table */
PUShort outs; /* current outlines table */
UShort nPoints; /* number of points in current glyph */
Short nContours; /* number of contours in current glyph */
Int numTurns; /* number of Y-turns in outline */
TPoint* arc; /* current Bezier arc pointer */
UShort bWidth; /* target bitmap width */
PByte bTarget; /* target bitmap buffer */
PByte gTarget; /* target pixmap buffer */
Long lastX, lastY, minY, maxY;
UShort num_Profs; /* current number of profiles */
Bool fresh; /* signals a fresh new profile which */
/* 'start' field must be completed */
Bool joint; /* signals that the last arc ended */
/* exactly on a scanline. Allows */
/* removal of doublets */
PProfile cProfile; /* current profile */
PProfile fProfile; /* head of linked list of profiles */
PProfile gProfile; /* contour's first profile in case */
/* of impact */
TStates state; /* rendering state */
TT_Raster_Map target; /* description of target bit/pixmap */
Long traceOfs; /* current offset in target bitmap */
Long traceG; /* current offset in target pixmap */
Short traceIncr; /* sweep's increment in target bitmap */
Short gray_min_x; /* current min x during gray rendering */
Short gray_max_x; /* current max x during gray rendering */
/* dispatch variables */
Function_Sweep_Init* Proc_Sweep_Init;
Function_Sweep_Span* Proc_Sweep_Span;
Function_Sweep_Span* Proc_Sweep_Drop;
Function_Sweep_Step* Proc_Sweep_Step;
TT_Vector* coords;
Byte dropOutControl; /* current drop_out control method */
Byte grays[5]; /* Palette of gray levels used for render */
Byte* gray_lines; /* Intermediate table used to render the */
/* graylevels pixmaps. */
/* gray_lines is a buffer holding two */
/* monochrome scanlines */
Short gray_width; /* width in bytes of one monochrome */
/* intermediate scanline of gray_lines. */
/* Each gray pixel takes 2 bits long there */
/* The gray_lines must hold 2 lines, thus with size */
/* in bytes of at least 'gray_width*2' */
Bool second_pass; /* indicates wether a horizontal pass */
/* should be performed to control drop-out */
/* accurately when calling Render_Glyph. */
/* Note that there is no horizontal pass */
/* during gray rendering. */
TPoint arcs[2 * MaxBezier + 1]; /* The Bezier stack */
TBand band_stack[16]; /* band stack used for sub-banding */
Int band_top; /* band stack top */
Int count_table[256]; /* Look-up table used to quickly count */
/* set bits in a gray 2x2 cell */
};
#ifdef TT_CONFIG_OPTION_STATIC_RASTER
static TRaster_Instance cur_ras;
#define ras cur_ras
#else
#define ras (*raster)
#endif /* TT_STATIC_RASTER */
#ifdef DEBUG_RASTER
/************************************************/
/* */
/* Pset: */
/* */
/* Used for debugging only. Plots a point */
/* in VRAM during rendering (not afterwards). */
/* */
/* NOTE: This procedure relies on the value */
/* of cProfile->start, which may not */
/* be set when Pset is called sometimes. */
/* This will usually result in a dot */
/* plotted on the first screen scanline */
/* (far away its original position). */
/* */
/* This "bug" reflects nothing wrong */
/* in the current implementation, and */
/* the bitmap is rendered correctly, */
/* so don't panic if you see 'flying' */
/* dots in debugging mode. */
/* */
/* - David */
/* */
/************************************************/
static void Pset( RAS_ARG )
{
Long o;
Long x;
x = ras.top[-1];
switch ( ras.cProfile->flow )
{
case TT_Flow_Up:
o = Vio_ScanLineWidth *
( ras.top-ras.cProfile->offset + ras.cProfile->start ) +
( x / (ras.precision*8) );
break;
case TT_Flow_Down:
o = Vio_ScanLineWidth *
( ras.cProfile->start-ras.top + ras.cProfile->offset ) +
( x / (ras.precision*8) );
break;
}
if ( o > 0 )
Vio[o] |= (unsigned)0x80 >> ( (x/ras.precision) & 7 );
}
static void Clear_Band( RAS_ARGS Int y1, Int y2 )
{
MEM_Set( Vio + y1*Vio_ScanLineWidth, (y2-y1+1)*Vio_ScanLineWidth, 0 );
}
#endif /* DEBUG_RASTER */
/************************************************************************/
/* */
/* Function: Set_High_Precision */
/* */
/* Description: Sets precision variables according to param flag. */
/* */
/* Input: High set to True for high precision (typically for */
/* ppem < 18), false otherwise. */
/* */
/************************************************************************/
static void Set_High_Precision( RAS_ARGS Bool High )
{
if ( High )
{
ras.precision_bits = 10;
ras.precision_step = 128;
ras.precision_jitter = 24;
}
else
{
ras.precision_bits = 6;
ras.precision_step = 32;
ras.precision_jitter = 2;
}
PTRACE7(( "Set_High_Precision(%s)\n", High ? "true" : "false" ));
ras.precision = 1 << ras.precision_bits;
ras.precision_half = ras.precision / 2;
ras.precision_shift = ras.precision_bits - Pixel_Bits;
ras.precision_mask = -ras.precision;
}
/****************************************************************************/
/* */
/* Function: New_Profile */
/* */
/* Description: Creates a new Profile in the render pool. */
/* */
/* Input: aState state/orientation of the new Profile */
/* */
/* Returns: SUCCESS on success. */
/* FAILURE in case of overflow or of incoherent Profile. */
/* */
/****************************************************************************/
static Bool New_Profile( RAS_ARGS TStates aState )
{
if ( !ras.fProfile )
{
ras.cProfile = (PProfile)ras.top;
ras.fProfile = ras.cProfile;
ras.top += AlignProfileSize;
}
if ( ras.top >= ras.maxBuff )
{
ras.error = Raster_Err_Overflow;
return FAILURE;
}
switch ( aState )
{
case Ascending:
ras.cProfile->flow = TT_Flow_Up;
PTRACE7(( "New ascending profile = %lx\n", (long)ras.cProfile ));
break;
case Descending:
ras.cProfile->flow = TT_Flow_Down;
PTRACE7(( "New descending profile = %lx\n", (long)ras.cProfile ));
break;
default:
PTRACE0(( "Invalid profile direction in Raster:New_Profile !!\n" ));
ras.error = Raster_Err_Invalid;
return FAILURE;
}
ras.cProfile->start = 0;
ras.cProfile->height = 0;
ras.cProfile->offset = ras.top;
ras.cProfile->link = (PProfile)0;
ras.cProfile->next = (PProfile)0;
if ( !ras.gProfile )
ras.gProfile = ras.cProfile;
ras.state = aState;
ras.fresh = TRUE;
ras.joint = FALSE;
return SUCCESS_OK;
}
/****************************************************************************/
/* */
/* Function: End_Profile */
/* */
/* Description: Finalizes the current Profile. */
/* */
/* Input: None */
/* */
/* Returns: SUCCESS on success. */
/* FAILURE in case of overflow or incoherency. */
/* */
/****************************************************************************/
static Bool End_Profile( RAS_ARG )
{
Long h;
PProfile oldProfile;
h = ras.top - ras.cProfile->offset;
if ( h < 0 )
{
PTRACE0(( "Negative height encountered in End_Profile!\n" ));
ras.error = Raster_Err_Neg_Height;
return FAILURE;
}
if ( h > 0 )
{
PTRACE1(( "Ending profile %lx, start = %ld, height = %ld\n",
(long)ras.cProfile, ras.cProfile->start, h ));
oldProfile = ras.cProfile;
ras.cProfile->height = h;
ras.cProfile = (PProfile)ras.top;
ras.top += AlignProfileSize;
ras.cProfile->height = 0;
ras.cProfile->offset = ras.top;
oldProfile->next = ras.cProfile;
ras.num_Profs++;
}
if ( ras.top >= ras.maxBuff )
{
PTRACE1(( "overflow in End_Profile\n" ));
ras.error = Raster_Err_Overflow;
return FAILURE;
}
ras.joint = FALSE;
return SUCCESS_OK;
}
/****************************************************************************/
/* */
/* Function: Insert_Y_Turn */
/* */
/* Description: Insert a salient into the sorted list placed on top */
/* of the render pool */
/* */
/* Input: New y scanline position */
/* */
/****************************************************************************/
static
Bool Insert_Y_Turn( RAS_ARGS Int y )
{
PStorage y_turns;
Int y2, n;
n = ras.numTurns-1;
y_turns = ras.sizeBuff - ras.numTurns;
/* look for first y value that is <= */
while ( n >= 0 && y < y_turns[n] )
n--;
/* if it is <, simply insert it, ignore if == */
if ( n >= 0 && y > y_turns[n] )
while ( n >= 0 )
{
y2 = y_turns[n];
y_turns[n] = y;
y = y2;
n--;
}
if ( n < 0 )
{
if (ras.maxBuff <= ras.top)
{
ras.error = Raster_Err_Overflow;
return FAILURE;
}
ras.maxBuff--;
ras.numTurns++;
ras.sizeBuff[-ras.numTurns] = y;
}
return SUCCESS_OK;
}
/****************************************************************************/
/* */
/* Function: Finalize_Profile_Table */
/* */
/* Description: Adjusts all links in the Profiles list. */
/* */
/* Input: None */
/* */
/* Returns: None. */
/* */
/****************************************************************************/
static
Bool Finalize_Profile_Table( RAS_ARG )
{
Int bottom, top;
UShort n;
PProfile p;
n = ras.num_Profs;
if ( n > 1 )
{
p = ras.fProfile;
while ( n > 0 )
{
if ( n > 1 )
p->link = (PProfile)( p->offset + p->height );
else
p->link = NULL;
switch ( p->flow )
{
case TT_Flow_Down:
bottom = p->start - p->height+1;
top = p->start;
p->start = bottom;
p->offset += p->height-1;
break;
case TT_Flow_Up:
default:
bottom = p->start;
top = p->start + p->height-1;
}
if ( Insert_Y_Turn( RAS_VARS bottom ) ||
Insert_Y_Turn( RAS_VARS top+1 ) )
return FAILURE;
p = p->link;
n--;
}
}
else
ras.fProfile = NULL;
return SUCCESS_OK;
}
/****************************************************************************/
/* */
/* Function: Split_Bezier */
/* */
/* Description: Subdivides one Bezier arc into two joint */
/* sub-arcs in the Bezier stack. */
/* */
/* Input: None (subdivided bezier is taken from the top of the */
/* stack). */
/* */
/* Returns: None. */
/* */
/* */
/* Note: This routine is the 'beef' of this component. It is _the_ */
/* inner loop that should be optimized to hell to get the */
/* best performance. */
/* */
/****************************************************************************/
static void Split_Bezier( TPoint* base )
{
Long a, b;
base[4].x = base[2].x;
b = base[1].x;
a = base[3].x = ( base[2].x + b ) / 2;
b = base[1].x = ( base[0].x + b ) / 2;
base[2].x = ( a + b ) / 2;
base[4].y = base[2].y;
b = base[1].y;
a = base[3].y = ( base[2].y + b ) / 2;
b = base[1].y = ( base[0].y + b ) / 2;
base[2].y = ( a + b ) / 2;
/* hand optimized. gcc doesn't seem too good at common expression */
/* substitution and instruction scheduling ;-) */
}
/****************************************************************************/
/* */
/* Function: Push_Bezier */
/* */
/* Description: Clears the Bezier stack and pushes a new arc on top of it. */
/* */
/* Input: x1,y1 x2,y2 x3,y3 new Bezier arc */
/* */
/* Returns: None. */
/* */
/****************************************************************************/
static void Push_Bezier( RAS_ARGS Long x1, Long y1,
Long x2, Long y2,
Long x3, Long y3 )
{
ras.arc = ras.arcs;
ras.arc[2].x = x1; ras.arc[2].y = y1;
ras.arc[1].x = x2; ras.arc[1].y = y2;
ras.arc[0].x = x3; ras.arc[0].y = y3;
}
/****************************************************************************/
/* */
/* Function: Line_Up */
/* */
/* Description: Computes the x-coordinates of an ascending line segment */
/* and stores them in the render pool. */
/* */
/* Input: x1,y1,x2,y2 Segment start (x1,y1) and end (x2,y2) points */
/* */
/* Returns: SUCCESS on success. */
/* FAILURE on Render Pool overflow. */
/* */
/****************************************************************************/
static Bool Line_Up( RAS_ARGS Long x1, Long y1,
Long x2, Long y2,
Long miny, Long maxy )
{
Long Dx, Dy;
Int e1, e2, f1, f2, size; /* XXX: is `Short' sufficient? */
Long Ix, Rx, Ax;
PStorage top;
Dx = x2 - x1;
Dy = y2 - y1;
if ( Dy <= 0 || y2 < miny || y1 > maxy )
return SUCCESS_OK;
if ( y1 < miny )
{
/* Take care : miny-y1 can be a very large value, we use */
/* a slow MulDiv function to avoid clipping bugs */
x1 += SMulDiv( Dx, miny - y1, Dy );
e1 = TRUNC( miny );
f1 = 0;
}
else
{
e1 = TRUNC( y1 );
f1 = FRAC( y1 );
}
if ( y2 > maxy )
{
/* x2 += FMulDiv( Dx, maxy - y2, Dy ); UNNECESSARY */
e2 = TRUNC( maxy );
f2 = 0;
}
else
{
e2 = TRUNC( y2 );
f2 = FRAC( y2 );
}
if ( f1 > 0 )
{
if ( e1 == e2 ) return SUCCESS_OK;
else
{
x1 += FMulDiv( Dx, ras.precision - f1, Dy );
e1 += 1;
}
}
else
if ( ras.joint )
{
ras.top--;
ras.joint = FALSE;
}
ras.joint = ( f2 == 0 );
if ( ras.fresh )
{
ras.cProfile->start = e1;
ras.fresh = FALSE;
}
size = e2 - e1 + 1;
if ( ras.top + size >= ras.maxBuff )
{
ras.error = Raster_Err_Overflow;
return FAILURE;
}
if ( Dx > 0 )
{
Ix = (ras.precision*Dx) / Dy;
Rx = (ras.precision*Dx) % Dy;
Dx = 1;
}
else
{
Ix = -( (ras.precision*-Dx) / Dy );
Rx = (ras.precision*-Dx) % Dy;
Dx = -1;
}
Ax = -Dy;
top = ras.top;
while ( size > 0 )
{
*top++ = x1;
DEBUG_PSET;
x1 += Ix;
Ax += Rx;
if ( Ax >= 0 )
{
Ax -= Dy;
x1 += Dx;
}
size--;
}
ras.top = top;
return SUCCESS_OK;
}
static Bool Line_Down( RAS_ARGS Long x1, Long y1,
Long x2, Long y2,
Long miny, Long maxy )
{
Bool result, fresh;
fresh = ras.fresh;
result = Line_Up( RAS_VARS x1, -y1, x2, -y2, -maxy, -miny );
if ( fresh && !ras.fresh )
ras.cProfile->start = -ras.cProfile->start;
return result;
}
/****************************************************************************/
/* */
/* Function: Bezier_Up */
/* */
/* Description: Computes thes x-coordinates of an ascending bezier arc */
/* and stores them in the render pool. */
/* */
/* Input: None. The arc is taken from the top of the Bezier stack. */
/* */
/* Returns: SUCCESS on success. */
/* FAILURE on Render Pool overflow. */
/* */
/****************************************************************************/
static Bool Bezier_Up( RAS_ARGS Long miny, Long maxy )
{
Long y1, y2, e, e2, e0;
Short f1;
TPoint* arc;
TPoint* start_arc;
PStorage top;
arc = ras.arc;
y1 = arc[2].y;
y2 = arc[0].y;
top = ras.top;
if ( y2 < miny || y1 > maxy )
goto Fin;
e2 = FLOOR( y2 );
if ( e2 > maxy )
e2 = maxy;
e0 = miny;
if ( y1 < miny )
e = miny;
else
{
e = CEILING( y1 );
f1 = FRAC( y1 );
e0 = e;
if ( f1 == 0 )
{
if ( ras.joint )
{
top--;
ras.joint = FALSE;
}
*top++ = arc[2].x;
DEBUG_PSET;
e += ras.precision;
}
}
if ( ras.fresh )
{
ras.cProfile->start = TRUNC( e0 );
ras.fresh = FALSE;
}
if ( e2 < e )
goto Fin;
if ( ( top + TRUNC( e2 - e ) + 1 ) >= ras.maxBuff )
{
ras.top = top;
ras.error = Raster_Err_Overflow;
return FAILURE;
}
start_arc = arc;
while ( arc >= start_arc && e <= e2 )
{
ras.joint = FALSE;
y2 = arc[0].y;
if ( y2 > e )
{
y1 = arc[2].y;
if ( y2 - y1 >= ras.precision_step )
{
Split_Bezier( arc );
arc += 2;
}
else
{
*top++ = arc[2].x + FMulDiv( arc[0].x - arc[2].x,
e - y1,
y2 - y1 );
DEBUG_PSET;
arc -= 2;
e += ras.precision;
}
}
else
{
if ( y2 == e )
{
ras.joint = TRUE;
*top++ = arc[0].x;
DEBUG_PSET;
e += ras.precision;
}
arc -= 2;
}
}
Fin:
ras.top = top;
ras.arc -= 2;
return SUCCESS_OK;
}
/****************************************************************************/
/* */
/* Function: Bezier_Down */
/* */
/* Description: Computes the x-coordinates of a descending bezier arc */
/* and stores them in the render pool. */
/* */
/* Input: None. Arc is taken from the top of the Bezier stack. */
/* */
/* Returns: SUCCESS on success. */
/* FAILURE on Render Pool overflow. */
/* */
/****************************************************************************/
static Bool Bezier_Down( RAS_ARGS Long miny, Long maxy )
{
TPoint* arc = ras.arc;
Bool result, fresh;
arc[0].y = -arc[0].y;
arc[1].y = -arc[1].y;
arc[2].y = -arc[2].y;
fresh = ras.fresh;
result = Bezier_Up( RAS_VARS -maxy, -miny );
if ( fresh && !ras.fresh )
ras.cProfile->start = -ras.cProfile->start;
arc[0].y = -arc[0].y;
return result;
}
/****************************************************************************/
/* */
/* Function: Line_To */
/* */
/* Description: Injects a new line segment and adjusts Profiles list. */
/* */
/* Input: x, y : segment endpoint (start point in LastX,LastY) */
/* */
/* Returns: SUCCESS on success. */
/* FAILURE on Render Pool overflow or Incorrect Profile. */
/* */
/****************************************************************************/
static Bool Line_To( RAS_ARGS Long x, Long y )
{
/* First, detect a change of direction */
switch ( ras.state )
{
case Unknown:
if ( y > ras.lastY )
{
if ( New_Profile( RAS_VARS Ascending ) ) return FAILURE;
}
else
{
if ( y < ras.lastY )
if ( New_Profile( RAS_VARS Descending ) ) return FAILURE;
}
break;
case Ascending:
if ( y < ras.lastY )
{
if ( End_Profile( RAS_VAR ) ||
New_Profile( RAS_VARS Descending ) ) return FAILURE;
}
break;
case Descending:
if ( y > ras.lastY )
{
if ( End_Profile( RAS_VAR ) ||
New_Profile( RAS_VARS Ascending ) ) return FAILURE;
}
break;
default:
;
}
/* Then compute the lines */
switch ( ras.state )
{
case Ascending:
if ( Line_Up ( RAS_VARS ras.lastX, ras.lastY,
x, y, ras.minY, ras.maxY ) )
return FAILURE;
break;
case Descending:
if ( Line_Down( RAS_VARS ras.lastX, ras.lastY,
x, y, ras.minY, ras.maxY ) )
return FAILURE;
break;
default:
;
}
ras.lastX = x;
ras.lastY = y;
return SUCCESS_OK;
}
/****************************************************************************/
/* */
/* Function: Bezier_To */
/* */
/* Description: Injects a new bezier arc and adjusts the profile list. */
/* */
/* Input: x, y : arc endpoint (start point in LastX, LastY) */
/* Cx, Cy : control point */
/* */
/* Returns: SUCCESS on success. */
/* FAILURE on Render Pool overflow or Incorrect Profile. */
/* */
/****************************************************************************/
static Bool Bezier_To( RAS_ARGS Long x,
Long y,
Long cx,
Long cy )
{
Long y1, y2, y3, x3;
TStates state_bez;
Push_Bezier( RAS_VARS ras.lastX, ras.lastY, cx, cy, x, y );
do
{
y1 = ras.arc[2].y;
y2 = ras.arc[1].y;
y3 = ras.arc[0].y;
x3 = ras.arc[0].x;
/* first, categorize the bezier arc */
if ( y1 == y2 )
{
if ( y2 == y3 )
state_bez = Flat;
else if ( y2 > y3 )
state_bez = Descending;
else
state_bez = Ascending;
}
else if ( y1 > y2 )
{
if ( y2 >= y3 )
state_bez = Descending;
else
state_bez = Unknown;
}
else if ( y2 <= y3 )
state_bez = Ascending;
else
state_bez = Unknown;
/* split non-monotonic arcs, ignore flat ones, or */
/* computes the up and down ones */
switch ( state_bez )
{
case Flat:
ras.arc -= 2;
break;
case Unknown:
Split_Bezier( ras.arc );
ras.arc += 2;
break;
default:
/* detect a change of direction */
if ( ras.state != state_bez )
{
if ( ras.state != Unknown )
if ( End_Profile( RAS_VAR ) ) return FAILURE;
if ( New_Profile( RAS_VARS state_bez ) ) return FAILURE;
}
/* compute */
switch ( ras.state )
{
case Ascending:
if ( Bezier_Up ( RAS_VARS ras.minY, ras.maxY ) )
return FAILURE;
break;
case Descending:
if ( Bezier_Down( RAS_VARS ras.minY, ras.maxY ) )
return FAILURE;
break;
default:
;
}
}
} while ( ras.arc >= ras.arcs );
ras.lastX = x3;
ras.lastY = y3;
return SUCCESS_OK;
}
/****************************************************************************/
/* */
/* Function: Decompose_Curve */
/* */
/* Description: Scans the outline arays in order to emit individual */
/* segments and beziers by calling Line_To() and Bezier_To(). */
/* It handles all weird cases, like when the first point */
/* is off the curve, or when there are simply no 'on' */
/* points in the contour! */
/* */
/* Input: first, last : indexes of first and last point in */
/* contour. */
/* */
/* Returns: SUCCESS on success. */
/* FAILURE on error. */
/* */
/****************************************************************************/
#undef SWAP_
#define SWAP_(x,y) { Long swap = x; x = y; y = swap; }
static Bool Decompose_Curve( RAS_ARGS UShort first,
UShort last,
Bool flipped )
{
Long x, y; /* current point */
Long cx, cy; /* current Bezier control point */
Long mx, my; /* current middle point */
Long x_first, y_first; /* first point's coordinates */
Long x_last, y_last; /* last point's coordinates */
UShort index; /* current point's index */
Bool on_curve; /* current point's state */
x_first = SCALED( ras.coords[first].x );
y_first = SCALED( ras.coords[first].y );
if ( flipped ) SWAP_( x_first,y_first );
x_last = SCALED( ras.coords[last].x );
y_last = SCALED( ras.coords[last].y );
if ( flipped ) SWAP_( x_last,y_last );
ras.lastX = cx = x_first;
ras.lastY = cy = y_first;
on_curve = (ras.flags[first] & 1);
index = first;
/* check first point to determine origin */
if ( !on_curve )
{
/* first point is off the curve. Yes, this happens... */
if ( ras.flags[last] & 1 )
{
ras.lastX = x_last; /* start at last point if it */
ras.lastY = y_last; /* is on the curve */
}
else
{
/* if both first and last points are off the curve, */
/* start at their middle and record its position */
/* for closure */
ras.lastX = (ras.lastX + x_last)/2;
ras.lastY = (ras.lastY + y_last)/2;
x_last = ras.lastX;
y_last = ras.lastY;
}
}
/* now process each contour point individually */
while ( index < last )
{
index++;
x = SCALED( ras.coords[index].x );
y = SCALED( ras.coords[index].y );
if ( flipped ) SWAP_( x, y );
if ( on_curve )
{
/* the previous point was on the curve */
on_curve = ( ras.flags[index] & 1 );
if ( on_curve )
{
/* two successive on points => emit segment */
if ( Line_To( RAS_VARS x, y ) ) return FAILURE;
}
else
{
/* else, keep current control point for next bezier */
cx = x;
cy = y;
}
}
else
{
/* the previous point was off the curve */
on_curve = ( ras.flags[index] & 1 );
if ( on_curve )
{
/* reaching an `on' point */
if ( Bezier_To( RAS_VARS x, y, cx, cy ) ) return FAILURE;
}
else
{
/* two successive `off' points => create middle point */
mx = ( cx + x ) / 2;
my = ( cy + y ) / 2;
if ( Bezier_To( RAS_VARS mx, my, cx, cy ) ) return FAILURE;
cx = x;
cy = y;
}
}
}
/* end of contour, close curve cleanly */
if ( ras.flags[first] & 1 )
{
if ( on_curve )
return Line_To( RAS_VARS x_first, y_first );
else
return Bezier_To( RAS_VARS x_first, y_first, cx, cy );
}
else
if ( !on_curve )
return Bezier_To( RAS_VARS x_last, y_last, cx, cy );
return SUCCESS_OK;
}
/****************************************************************************/
/* */
/* Function: Convert_Glyph */
/* */
/* Description: Converts a glyph into a series of segments and arcs */
/* and makes a Profiles list with them. */
/* */
/* Input: _xCoord, _yCoord : coordinates tables. */
/* */
/* Uses the 'Flag' table too. */
/* */
/* Returns: SUCCESS on success. */
/* FAILURE if any error was encountered during rendering. */
/* */
/****************************************************************************/
static Bool Convert_Glyph( RAS_ARGS int flipped )
{
Short i;
UShort start;
PProfile lastProfile;
ras.fProfile = NULL;
ras.joint = FALSE;
ras.fresh = FALSE;
ras.maxBuff = ras.sizeBuff - AlignProfileSize;
ras.numTurns = 0;
ras.cProfile = (PProfile)ras.top;
ras.cProfile->offset = ras.top;
ras.num_Profs = 0;
start = 0;
for ( i = 0; i < ras.nContours; i++ )
{
ras.state = Unknown;
ras.gProfile = NULL;
if ( Decompose_Curve( RAS_VARS start, ras.outs[i], flipped ) )
return FAILURE;
start = ras.outs[i] + 1;
/* We must now see if the extreme arcs join or not */
if ( ( FRAC( ras.lastY ) == 0 &&
ras.lastY >= ras.minY &&
ras.lastY <= ras.maxY ) )
if ( ras.gProfile && ras.gProfile->flow == ras.cProfile->flow )
ras.top--;
/* Note that ras.gProfile can be nil if the contour was too small */
/* to be drawn. */
lastProfile = ras.cProfile;
if ( End_Profile( RAS_VAR ) ) return FAILURE;
/* close the 'next profile in contour' linked list */
if ( ras.gProfile )
lastProfile->next = ras.gProfile;
}
if (Finalize_Profile_Table( RAS_VAR ))
return FAILURE;
return (ras.top < ras.maxBuff ? SUCCESS_OK : FAILURE );
}
/************************************************/
/* */
/* Init_Linked */
/* */
/* Inits an empty linked list. */
/* */
/************************************************/
static void Init_Linked( TProfileList* l )
{
*l = NULL;
}
/************************************************/
/* */
/* InsNew : */
/* */
/* Inserts a new Profile in a linked list. */
/* */
/************************************************/
static void InsNew( PProfileList list,
PProfile profile )
{
PProfile *old, current;
Long x;
old = list;
current = *old;
x = profile->X;
while ( current )
{
if ( x < current->X )
break;
old = ¤t->link;
current = *old;
}
profile->link = current;
*old = profile;
}
/*************************************************/
/* */
/* DelOld : */
/* */
/* Removes an old Profile from a linked list. */
/* */
/*************************************************/
static void DelOld( PProfileList list,
PProfile profile )
{
PProfile *old, current;
old = list;
current = *old;
while ( current )
{
if ( current == profile )
{
*old = current->link;
return;
}
old = ¤t->link;
current = *old;
}
/* we should never get there, unless the Profile was not part of */
/* the list. */
}
/************************************************/
/* */
/* Update : */
/* */
/* Update all X offsets of a drawing list */
/* */
/************************************************/
static void Update( PProfile first )
{
PProfile current = first;
while ( current )
{
current->X = *current->offset;
current->offset += current->flow;
current->height--;
current = current->link;
}
}
/************************************************/
/* */
/* Sort : */
/* */
/* Sorts a trace list. In 95%, the list */
/* is already sorted. We need an algorithm */
/* which is fast in this case. Bubble sort */
/* is enough and simple. */
/* */
/************************************************/
static void Sort( PProfileList list )
{
PProfile *old, current, next;
/* First, set the new X coordinate of each profile */
Update( *list );
/* Then sort them */
old = list;
current = *old;
if ( !current )
return;
next = current->link;
while ( next )
{
if ( current->X <= next->X )
{
old = ¤t->link;
current = *old;
if ( !current )
return;
}
else
{
*old = next;
current->link = next->link;
next->link = current;
old = list;
current = *old;
}
next = current->link;
}
}
/***********************************************************************/
/* */
/* Vertical Sweep Procedure Set : */
/* */
/* These three routines are used during the vertical black/white */
/* sweep phase by the generic Draw_Sweep() function. */
/* */
/***********************************************************************/
static void Vertical_Sweep_Init( RAS_ARGS Short* min, Short* max )
{
switch ( ras.target.flow )
{
case TT_Flow_Up:
ras.traceOfs = *min * ras.target.cols;
ras.traceIncr = ras.target.cols;
break;
default:
ras.traceOfs = ( ras.target.rows - 1 - *min ) * ras.target.cols;
ras.traceIncr = -ras.target.cols;
}
ras.gray_min_x = 0;
ras.gray_max_x = 0;
}
static void Vertical_Sweep_Span( RAS_ARGS Short y,
TT_F26Dot6 x1,
TT_F26Dot6 x2,
PProfile left,
PProfile right )
{
Long e1, e2;
Short c1, c2;
Short f1, f2;
Byte* target;
/* Drop-out control */
e1 = TRUNC( CEILING( x1 ) );
if ( x2-x1-ras.precision <= ras.precision_jitter )
e2 = e1;
else
e2 = TRUNC( FLOOR( x2 ) );
if ( e2 >= 0 && e1 < ras.bWidth )
{
if ( e1 < 0 ) e1 = 0;
if ( e2 >= ras.bWidth ) e2 = ras.bWidth-1;
c1 = (Short)(e1 >> 3);
c2 = (Short)(e2 >> 3);
f1 = e1 & 7;
f2 = e2 & 7;
if ( ras.gray_min_x > c1 ) ras.gray_min_x = c1;
if ( ras.gray_max_x < c2 ) ras.gray_max_x = c2;
target = ras.bTarget + ras.traceOfs + c1;
if ( c1 != c2 )
{
*target |= LMask[f1];
if ( c2 > c1 + 1 )
MEM_Set( target + 1, 0xFF, c2 - c1 - 1 );
target[c2 - c1] |= RMask[f2];
}
else
*target |= ( LMask[f1] & RMask[f2] );
}
}
static void Vertical_Sweep_Drop( RAS_ARGS Short y,
TT_F26Dot6 x1,
TT_F26Dot6 x2,
PProfile left,
PProfile right )
{
Long e1, e2;
Short c1, f1;
/* Drop-out control */
e1 = CEILING( x1 );
e2 = FLOOR ( x2 );
if ( e1 > e2 )
{
if ( e1 == e2 + ras.precision )
{
switch ( ras.dropOutControl )
{
case 1:
e1 = e2;
break;
case 4:
e1 = CEILING( (x1 + x2 + 1) / 2 );
break;
case 2:
case 5:
/* Drop-out Control Rule #4 */
/* The spec is not very clear regarding rule #4. It */
/* presents a method that is way too costly to implement */
/* while the general idea seems to get rid of 'stubs'. */
/* */
/* Here, we only get rid of stubs recognized when: */
/* */
/* upper stub: */
/* */
/* - P_Left and P_Right are in the same contour */
/* - P_Right is the successor of P_Left in that contour */
/* - y is the top of P_Left and P_Right */
/* */
/* lower stub: */
/* */
/* - P_Left and P_Right are in the same contour */
/* - P_Left is the successor of P_Right in that contour */
/* - y is the bottom of P_Left */
/* */
/* FIXXXME : uncommenting this line solves the disappearing */
/* bit problem in the '7' of verdana 10pts, but */
/* makes a new one in the 'C' of arial 14pts */
/* if ( x2-x1 < ras.precision_half ) */
{
/* upper stub test */
if ( left->next == right && left->height <= 0 ) return;
/* lower stub test */
if ( right->next == left && left->start == y ) return;
}
/* check that the rightmost pixel isn't set */
e1 = TRUNC( e1 );
c1 = (Short)(e1 >> 3);
f1 = e1 & 7;
if ( e1 >= 0 && e1 < ras.bWidth &&
ras.bTarget[ras.traceOfs + c1] & (0x80 >> f1) )
return;
if ( ras.dropOutControl == 2 )
e1 = e2;
else
e1 = CEILING( (x1 + x2 + 1) / 2 );
break;
default:
return; /* unsupported mode */
}
}
else
return;
}
e1 = TRUNC( e1 );
if ( e1 >= 0 && e1 < ras.bWidth )
{
c1 = (Short)(e1 >> 3);
f1 = e1 & 7;
if ( ras.gray_min_x > c1 ) ras.gray_min_x = c1;
if ( ras.gray_max_x < c1 ) ras.gray_max_x = c1;
ras.bTarget[ras.traceOfs + c1] |= (Char)(0x80 >> f1);
}
}
static void Vertical_Sweep_Step( RAS_ARG )
{
ras.traceOfs += ras.traceIncr;
}
/***********************************************************************/
/* */
/* Horizontal Sweep Procedure Set : */
/* */
/* These three routines are used during the horizontal black/white */
/* sweep phase by the generic Draw_Sweep() function. */
/* */
/***********************************************************************/
static void Horizontal_Sweep_Init( RAS_ARGS Short* min, Short* max )
{
/* nothing, really */
}
static void Horizontal_Sweep_Span( RAS_ARGS Short y,
TT_F26Dot6 x1,
TT_F26Dot6 x2,
PProfile left,
PProfile right )
{
Long e1, e2;
PByte bits;
Byte f1;
if ( x2-x1 < ras.precision )
{
e1 = CEILING( x1 );
e2 = FLOOR ( x2 );
if ( e1 == e2 )
{
bits = ras.bTarget + (y >> 3);
f1 = (Byte)(0x80 >> (y & 7));
e1 = TRUNC( e1 );
if ( e1 >= 0 && e1 < ras.target.rows )
{
if ( ras.target.flow == TT_Flow_Down )
bits[(ras.target.rows-1 - e1) * ras.target.cols] |= f1;
else
bits[e1 * ras.target.cols] |= f1;
}
}
}
#if 0
e2 = TRUNC( e2 );
if ( e2 >= 0 && e2 < ras.target.rows )
if ( ras.target.flow == TT_Flow_Down )
bits[(ras.target.rows-1-e2) * ras.target.cols] |= f1;
else
bits[e2 * ras.target.cols] |= f1;
#endif
}
static void Horizontal_Sweep_Drop( RAS_ARGS Short y,
TT_F26Dot6 x1,
TT_F26Dot6 x2,
PProfile left,
PProfile right )
{
Long e1, e2;
PByte bits;
Byte f1;
/* During the horizontal sweep, we only take care of drop-outs */
e1 = CEILING( x1 );
e2 = FLOOR ( x2 );
if ( e1 > e2 )
{
if ( e1 == e2 + ras.precision )
{
switch ( ras.dropOutControl )
{
case 1:
e1 = e2;
break;
case 4:
e1 = CEILING( (x1 + x2 + 1) / 2 );
break;
case 2:
case 5:
/* Drop-out Control Rule #4 */
/* The spec is not very clear regarding rule #4. It */
/* presents a method that is way too costly to implement */
/* while the general idea seems to get rid of 'stubs'. */
/* */
/* rightmost stub test */
if ( left->next == right && left->height <= 0 ) return;
/* leftmost stub test */
if ( right->next == left && left->start == y ) return;
/* check that the rightmost pixel isn't set */
e1 = TRUNC( e1 );
bits = ras.bTarget + (y >> 3);
f1 = (Byte)(0x80 >> (y & 7));
if ( ras.target.flow == TT_Flow_Down )
bits += (ras.target.rows-1-e1) * ras.target.cols;
else
bits += e1 * ras.target.cols;
if ( e1 >= 0 &&
e1 < ras.target.rows &&
*bits & f1 )
return;
if ( ras.dropOutControl == 2 )
e1 = e2;
else
e1 = CEILING( (x1 + x2 + 1) / 2 );
break;
default:
return; /* unsupported mode */
}
}
else
return;
}
bits = ras.bTarget + (y >> 3);
f1 = (Byte)(0x80 >> (y & 7));
e1 = TRUNC( e1 );
if ( e1 >= 0 && e1 < ras.target.rows )
{
if (ras.target.flow==TT_Flow_Down)
bits[(ras.target.rows-1-e1) * ras.target.cols] |= f1;
else
bits[e1 * ras.target.cols] |= f1;
}
}
static void Horizontal_Sweep_Step( RAS_ARG )
{
/* Nothing, really */
}
#ifdef TT_CONFIG_OPTION_GRAY_SCALING
/***********************************************************************/
/* */
/* Vertical Gray Sweep Procedure Set: */
/* */
/* These two routines are used during the vertical gray-levels */
/* sweep phase by the generic Draw_Sweep() function. */
/* */
/* */
/* NOTES: */
/* */
/* - The target pixmap's width *must* be a multiple of 4. */
/* */
/* - you have to use the function Vertical_Sweep_Span() for */
/* the gray span call. */
/* */
/***********************************************************************/
static void Vertical_Gray_Sweep_Init( RAS_ARGS Short* min, Short* max )
{
*min = *min & -2;
*max = ( *max + 3 ) & -2;
ras.traceOfs = 0;
switch ( ras.target.flow )
{
case TT_Flow_Up:
ras.traceG = (*min / 2) * ras.target.cols;
ras.traceIncr = ras.target.cols;
break;
default:
ras.traceG = (ras.target.rows-1 - *min/2) * ras.target.cols;
ras.traceIncr = -ras.target.cols;
}
ras.gray_min_x = ras.target.cols;
ras.gray_max_x = -ras.target.cols;
}
static void Vertical_Gray_Sweep_Step( RAS_ARG )
{
Int c1, c2;
PByte pix, bit, bit2;
Int* count = ras.count_table;
Byte* grays;
ras.traceOfs += ras.gray_width;
if ( ras.traceOfs > ras.gray_width )
{
pix = ras.gTarget + ras.traceG + ras.gray_min_x * 4;
grays = ras.grays;
if ( ras.gray_max_x >= 0 )
{
if ( ras.gray_max_x >= ras.target.width )
ras.gray_max_x = ras.target.width-1;
if ( ras.gray_min_x < 0 )
ras.gray_min_x = 0;
bit = ras.bTarget + ras.gray_min_x;
bit2 = bit + ras.gray_width;
c1 = ras.gray_max_x - ras.gray_min_x;
while ( c1 >= 0 )
{
c2 = count[*bit] + count[*bit2];
if ( c2 )
{
pix[0] = grays[(c2 & 0xF000) >> 12];
pix[1] = grays[(c2 & 0x0F00) >> 8];
pix[2] = grays[(c2 & 0x00F0) >> 4];
pix[3] = grays[(c2 & 0x000F) ];
*bit = 0;
*bit2 = 0;
}
bit ++;
bit2++;
pix += 4;
c1 --;
}
}
ras.traceOfs = 0;
ras.traceG += ras.traceIncr;
ras.gray_min_x = ras.target.cols;
ras.gray_max_x = -ras.target.cols;
}
}
static void Horizontal_Gray_Sweep_Span( RAS_ARGS Short y,
TT_F26Dot6 x1,
TT_F26Dot6 x2,
PProfile left,
PProfile right )
{
/* nothing, really */
}
static void Horizontal_Gray_Sweep_Drop( RAS_ARGS Short y,
TT_F26Dot6 x1,
TT_F26Dot6 x2,
PProfile left,
PProfile right )
{
Long e1, e2;
PByte pixel;
Byte color;
/* During the horizontal sweep, we only take care of drop-outs */
e1 = CEILING( x1 );
e2 = FLOOR ( x2 );
if ( e1 > e2 )
{
if ( e1 == e2 + ras.precision )
{
switch ( ras.dropOutControl )
{
case 1:
e1 = e2;
break;
case 4:
e1 = CEILING( (x1 + x2 + 1) / 2 );
break;
case 2:
case 5:
/* Drop-out Control Rule #4 */
/* The spec is not very clear regarding rule #4. It */
/* presents a method that is way too costly to implement */
/* while the general idea seems to get rid of 'stubs'. */
/* */
/* rightmost stub test */
if ( left->next == right && left->height <= 0 ) return;
/* leftmost stub test */
if ( right->next == left && left->start == y ) return;
if ( ras.dropOutControl == 2 )
e1 = e2;
else
e1 = CEILING( (x1 + x2 + 1) / 2 );
break;
default:
return; /* unsupported mode */
}
}
else
return;
}
if ( e1 >= 0 )
{
if ( x2 - x1 >= ras.precision_half )
color = ras.grays[2];
else
color = ras.grays[1];
e1 = TRUNC( e1 ) / 2;
if ( e1 < ras.target.rows )
{
if ( ras.target.flow == TT_Flow_Down )
pixel = ras.gTarget +
(ras.target.rows - 1 - e1) * ras.target.cols + y / 2;
else
pixel = ras.gTarget +
e1 * ras.target.cols + y / 2;
if (pixel[0] == ras.grays[0])
pixel[0] = color;
}
}
}
#endif /* TT_CONFIG_OPTION_GRAY_SCALING */
/********************************************************************/
/* */
/* Generic Sweep Drawing routine */
/* */
/********************************************************************/
static Bool Draw_Sweep( RAS_ARG )
{
Short y, y_change, y_height;
PProfile P, Q, P_Left, P_Right;
Short min_Y, max_Y, top, bottom, dropouts;
Long x1, x2, xs, e1, e2;
TProfileList wait;
TProfileList draw_left, draw_right;
/* Init empty linked lists */
Init_Linked( &wait );
Init_Linked( &draw_left );
Init_Linked( &draw_right );
/* first, compute min and max Y */
P = ras.fProfile;
max_Y = (short)TRUNC( ras.minY );
min_Y = (short)TRUNC( ras.maxY );
while ( P )
{
Q = P->link;
bottom = P->start;
top = P->start + P->height-1;
if ( min_Y > bottom ) min_Y = bottom;
if ( max_Y < top ) max_Y = top;
P->X = 0;
InsNew( &wait, P );
P = Q;
}
/* Check the Y-turns */
if ( ras.numTurns == 0 )
{
ras.error = Raster_Err_Invalid;
return FAILURE;
}
/* Now inits the sweep */
ras.Proc_Sweep_Init( RAS_VARS &min_Y, &max_Y );
/* Then compute the distance of each profile from min_Y */
P = wait;
while ( P )
{
P->countL = P->start - min_Y;
P = P->link;
}
/* Let's go */
y = min_Y;
y_height = 0;
if ( ras.numTurns > 0 &&
ras.sizeBuff[-ras.numTurns] == min_Y )
ras.numTurns--;
while ( ras.numTurns > 0 )
{
/* look in the wait list for new activations */
P = wait;
while ( P )
{
Q = P->link;
P->countL -= y_height;
if ( P->countL == 0 )
{
DelOld( &wait, P );
switch ( P->flow )
{
case TT_Flow_Up: InsNew( &draw_left, P ); break;
case TT_Flow_Down: InsNew( &draw_right, P ); break;
}
}
P = Q;
}
/* Sort the drawing lists */
Sort( &draw_left );
Sort( &draw_right );
y_change = (Short)ras.sizeBuff[-ras.numTurns--];
y_height = y_change - y;
while ( y < y_change )
{
/* Let's trace */
dropouts = 0;
P_Left = draw_left;
P_Right = draw_right;
while ( P_Left )
{
x1 = P_Left ->X;
x2 = P_Right->X;
if ( x1 > x2 )
{
xs = x1;
x1 = x2;
x2 = xs;
}
if ( x2-x1 <= ras.precision )
{
e1 = FLOOR( x1 );
e2 = CEILING( x2 );
if ( ras.dropOutControl != 0 &&
(e1 > e2 || e2 == e1 + ras.precision) )
{
/* a drop out was detected */
P_Left ->X = x1;
P_Right->X = x2;
/* mark profile for drop-out processing */
P_Left->countL = 1;
dropouts++;
goto Skip_To_Next;
}
}
ras.Proc_Sweep_Span( RAS_VARS y, x1, x2, P_Left, P_Right );
Skip_To_Next:
P_Left = P_Left->link;
P_Right = P_Right->link;
}
/* now perform the dropouts _after_ the span drawing */
/* drop-outs processing has been moved out of the loop */
/* for performance tuning */
if (dropouts > 0)
goto Scan_DropOuts;
Next_Line:
ras.Proc_Sweep_Step( RAS_VAR );
y++;
if ( y < y_change )
{
Sort( &draw_left );
Sort( &draw_right );
}
}
/* Now finalize the profiles that needs it */
{
PProfile Q, P;
P = draw_left;
while ( P )
{
Q = P->link;
if ( P->height == 0 )
DelOld( &draw_left, P );
P = Q;
}
}
{
PProfile Q, P = draw_right;
while ( P )
{
Q = P->link;
if ( P->height == 0 )
DelOld( &draw_right, P );
P = Q;
}
}
}
/* for gray-scaling, flushes the bitmap scanline cache */
while ( y <= max_Y )
{
ras.Proc_Sweep_Step( RAS_VAR );
y++;
}
return SUCCESS_OK;
Scan_DropOuts :
P_Left = draw_left;
P_Right = draw_right;
while ( P_Left )
{
if ( P_Left->countL )
{
P_Left->countL = 0;
/* dropouts--; -- this is useful when debugging only */
ras.Proc_Sweep_Drop( RAS_VARS y,
P_Left->X,
P_Right->X,
P_Left,
P_Right );
}
P_Left = P_Left->link;
P_Right = P_Right->link;
}
goto Next_Line;
}
/****************************************************************************/
/* */
/* Function: Render_Single_Pass */
/* */
/* Description: Performs one sweep with sub-banding. */
/* */
/* Input: _XCoord, _YCoord : x and y coordinates arrays */
/* */
/* Returns: SUCCESS on success */
/* FAILURE if any error was encountered during render. */
/* */
/****************************************************************************/
static TT_Error Render_Single_Pass( RAS_ARGS Bool flipped )
{
Short i, j, k;
while ( ras.band_top >= 0 )
{
ras.maxY = (Long)ras.band_stack[ras.band_top].y_max * ras.precision;
ras.minY = (Long)ras.band_stack[ras.band_top].y_min * ras.precision;
ras.top = ras.buff;
ras.error = Raster_Err_None;
if ( Convert_Glyph( RAS_VARS flipped ) )
{
if ( ras.error != Raster_Err_Overflow ) return FAILURE;
ras.error = Raster_Err_None;
/* sub-banding */
#ifdef DEBUG_RASTER
ClearBand( RAS_VARS TRUNC( ras.minY ), TRUNC( ras.maxY ) );
#endif
i = ras.band_stack[ras.band_top].y_min;
j = ras.band_stack[ras.band_top].y_max;
k = ( i + j ) / 2;
if ( ras.band_top >= 7 || k < i )
{
ras.band_top = 0;
ras.error = Raster_Err_Invalid;
return ras.error;
}
ras.band_stack[ras.band_top+1].y_min = k;
ras.band_stack[ras.band_top+1].y_max = j;
ras.band_stack[ras.band_top].y_max = k - 1;
ras.band_top++;
}
else
{
if ( ras.fProfile )
if ( Draw_Sweep( RAS_VAR ) ) return ras.error;
ras.band_top--;
}
}
return TT_Err_Ok;
}
/****************************************************************************/
/* */
/* Function: Render_Glyph */
/* */
/* Description: Renders a glyph in a bitmap. Sub-banding if needed. */
/* */
/* Input: AGlyph Glyph record */
/* */
/* Returns: SUCCESS on success. */
/* FAILURE if any error was encountered during rendering. */
/* */
/****************************************************************************/
LOCAL_FUNC
TT_Error Render_Glyph( RAS_ARGS TT_Outline* glyph,
TT_Raster_Map* target_map )
{
TT_Error error;
if ( glyph->n_points == 0 || glyph->n_contours <= 0 )
return TT_Err_Ok;
if ( !ras.buff )
{
ras.error = Raster_Err_Not_Ini;
return ras.error;
}
if ( glyph->n_points < glyph->contours[glyph->n_contours - 1] )
{
ras.error = TT_Err_Too_Many_Points;
return ras.error;
}
if ( target_map )
ras.target = *target_map;
ras.outs = glyph->contours;
ras.flags = glyph->flags;
ras.nPoints = glyph->n_points;
ras.nContours = glyph->n_contours;
ras.coords = glyph->points;
Set_High_Precision( RAS_VARS glyph->high_precision );
ras.scale_shift = ras.precision_shift;
ras.dropOutControl = glyph->dropout_mode;
ras.second_pass = glyph->second_pass;
/* Vertical Sweep */
ras.Proc_Sweep_Init = Vertical_Sweep_Init;
ras.Proc_Sweep_Span = Vertical_Sweep_Span;
ras.Proc_Sweep_Drop = Vertical_Sweep_Drop;
ras.Proc_Sweep_Step = Vertical_Sweep_Step;
ras.band_top = 0;
ras.band_stack[0].y_min = 0;
ras.band_stack[0].y_max = ras.target.rows - 1;
ras.bWidth = ras.target.width;
ras.bTarget = (Byte*)ras.target.bitmap;
if ( (error = Render_Single_Pass( RAS_VARS 0 )) != 0 )
return error;
/* Horizontal Sweep */
if ( ras.second_pass && ras.dropOutControl != 0 )
{
ras.Proc_Sweep_Init = Horizontal_Sweep_Init;
ras.Proc_Sweep_Span = Horizontal_Sweep_Span;
ras.Proc_Sweep_Drop = Horizontal_Sweep_Drop;
ras.Proc_Sweep_Step = Horizontal_Sweep_Step;
ras.band_top = 0;
ras.band_stack[0].y_min = 0;
ras.band_stack[0].y_max = ras.target.width - 1;
if ( (error = Render_Single_Pass( RAS_VARS 1 )) != 0 )
return error;
}
return TT_Err_Ok;
}
#ifdef TT_CONFIG_OPTION_GRAY_SCALING
/****************************************************************************/
/* */
/* Function: Render_Gray_Glyph */
/* */
/* Description: Renders a glyph with grayscaling. Sub-banding if needed. */
/* */
/* Input: AGlyph Glyph record */
/* */
/* Returns: SUCCESS on success */
/* FAILURE if any error was encountered during rendering. */
/* */
/****************************************************************************/
LOCAL_FUNC
TT_Error Render_Gray_Glyph( RAS_ARGS TT_Outline* glyph,
TT_Raster_Map* target_map,
Byte* palette )
{
Int i;
TT_Error error;
if ( !ras.buff )
{
ras.error = Raster_Err_Not_Ini;
return ras.error;
}
if ( glyph->n_points == 0 || glyph->n_contours <= 0 )
return TT_Err_Ok;
if ( glyph->n_points < glyph->contours[glyph->n_contours - 1] )
{
ras.error = TT_Err_Too_Many_Points;
return ras.error;
}
if ( palette )
{
for ( i = 0; i < 5; i++ )
ras.grays[i] = palette[i];
}
if ( target_map )
ras.target = *target_map;
ras.outs = glyph->contours;
ras.flags = glyph->flags;
ras.nPoints = glyph->n_points;
ras.nContours = glyph->n_contours;
ras.coords = glyph->points;
Set_High_Precision( RAS_VARS glyph->high_precision );
ras.scale_shift = ras.precision_shift+1;
ras.dropOutControl = glyph->dropout_mode;
ras.second_pass = glyph->second_pass;
/* Vertical Sweep */
ras.band_top = 0;
ras.band_stack[0].y_min = 0;
ras.band_stack[0].y_max = 2 * ras.target.rows - 1;
ras.bWidth = ras.gray_width;
if ( ras.bWidth > ras.target.cols/4 )
ras.bWidth = ras.target.cols/4;
ras.bWidth = ras.bWidth * 8;
ras.bTarget = (Byte*)ras.gray_lines;
ras.gTarget = (Byte*)ras.target.bitmap;
ras.Proc_Sweep_Init = Vertical_Gray_Sweep_Init;
ras.Proc_Sweep_Span = Vertical_Sweep_Span;
ras.Proc_Sweep_Drop = Vertical_Sweep_Drop;
ras.Proc_Sweep_Step = Vertical_Gray_Sweep_Step;
error = Render_Single_Pass( RAS_VARS 0 );
if (error)
return error;
/* Horizontal Sweep */
if ( ras.second_pass && ras.dropOutControl != 0 )
{
ras.Proc_Sweep_Init = Horizontal_Sweep_Init;
ras.Proc_Sweep_Span = Horizontal_Gray_Sweep_Span;
ras.Proc_Sweep_Drop = Horizontal_Gray_Sweep_Drop;
ras.Proc_Sweep_Step = Horizontal_Sweep_Step;
ras.band_top = 0;
ras.band_stack[0].y_min = 0;
ras.band_stack[0].y_max = ras.target.width * 2 - 1;
error = Render_Single_Pass( RAS_VARS 1 );
if (error)
return error;
}
return TT_Err_Ok;
}
#endif /* TT_CONFIG_OPTION_GRAY_SCALING */
/************************************************/
/* */
/* InitRasterizer */
/* */
/* Raster Initialization. */
/* Gets the bitmap description and render pool */
/* addresses. */
/* */
/************************************************/
#undef ras
LOCAL_FUNC
TT_Error TTRaster_Done( PEngine_Instance engine )
{
TRaster_Instance* ras = (TRaster_Instance*)engine->raster_component;
if ( !ras )
return TT_Err_Ok;
FREE( ras->buff );
FREE( ras->gray_lines );
#ifndef TT_CONFIG_OPTION_STATIC_RASTER
FREE( engine->raster_component );
#endif
return TT_Err_Ok;
}
LOCAL_FUNC
TT_Error TTRaster_Init( PEngine_Instance engine )
{
TT_Error error;
Int i, l, j, c;
TRaster_Instance* ras;
#ifdef TT_CONFIG_OPTION_STATIC_RASTER
ras = engine->raster_component = &cur_ras;
#else
if ( ALLOC( engine->raster_component, sizeof ( TRaster_Instance ) ) )
return error;
ras = (TRaster_Instance*)engine->raster_component;
#endif
if ( ALLOC( ras->buff, RASTER_RENDER_POOL ) ||
ALLOC( ras->gray_lines, RASTER_GRAY_LINES ) )
return error;
ras->sizeBuff = ras->buff + ( RASTER_RENDER_POOL/sizeof(long) );
ras->gray_width = RASTER_GRAY_LINES/2;
/* Initialization of Count_Table */
for ( i = 0; i < 256; i++ )
{
l = 0;
j = i;
for ( c = 0; c < 4; c++ )
{
l <<= 4;
if ( j & 0x80 ) l++;
if ( j & 0x40 ) l++;
j = ( j << 2 ) & 0xFF;
}
ras->count_table[i] = l;
}
ras->dropOutControl = 2;
ras->error = Raster_Err_None;
return TT_Err_Ok;
}
/* END */
TTRASTER.H 、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
/*******************************************************************
*
* ttraster.h v 1.4
*
* The FreeType glyph rasterizer.
*
* Copyright 1996-1999 by
* David Turner, Robert Wilhelm, and Werner Lemberg
*
* This file is part of the FreeType project, and may only be used
* modified and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
* NOTES:
*
* This version supports the following:
*
* - direct grayscaling
* - sub-banding
* - drop-out modes 4 and 5
* - second pass for complete drop-out control (bitmap only)
* - variable precision
*
*
* Changes between 1.4 and 1.3:
*
* Mainly performance tunings:
*
* - Line_Down() and Bezier_Down() now use the functions Line_Up()
* and Bezier_Up() to do their work.
* - optimized Split_Bezier()
* - optimized linked lists used during sweeps
*
* Changes between 1.2 and 1.3:
*
* - made the engine optionaly re-entrant. Saves a lot
* of code for a moderate performance hit.
*
******************************************************************/
#ifndef TTRASTER_H
#define TTRASTER_H
#include "ttconfig.h"
#include "freetype.h" /* for TT_Outline */
#include "ttengine.h"
#ifdef __cplusplus
extern "C" {
#endif
/* We provide two different builds of the scan-line converter */
/* The static build uses global variables and isn't */
/* re-entrant. */
/* The indirect build is re-entrant but accesses all variables */
/* indirectly. */
/* */
/* As a consequence, the indirect build is about 10% slower */
/* than the static one on a _Pentium_ (this could get worse */
/* on older processors), but the code size is reduced by */
/* more than 30% ! */
/* */
/* The indirect build is now the default, defined in */
/* ttconfig.h. Be careful if you experiment with this. */
/* Note also that, though its code can be re-entrant, the */
/* component is always used in thread-safe mode. This is */
/* simply due to the fact that we want to use a single */
/* render pool (of 64 Kb), and not to waste memory. */
#ifdef TT_STATIC_RASTER
#define RAS_ARGS /* void */
#define RAS_ARG /* void */
#define RAS_VARS /* void */
#define RAS_VAR /* void */
#else
#define RAS_ARGS TRaster_Instance* raster,
#define RAS_ARG TRaster_Instance* raster
#define RAS_VARS raster,
#define RAS_VAR raster
#endif
struct TRaster_Instance_;
typedef struct TRaster_Instance_ TRaster_Instance;
/* Render one glyph in the target bitmap, using drop-out control */
/* mode 'scan'. */
LOCAL_DEF
TT_Error Render_Glyph( RAS_ARGS TT_Outline* glyph,
TT_Raster_Map* target );
#ifdef TT_CONFIG_OPTION_GRAY_SCALING
/* Render one gray-level glyph in the target pixmap. */
/* Palette points to an array of 5 colors used for the rendering. */
/* Use NULL to reuse the last palette. Default is VGA graylevels. */
LOCAL_DEF
TT_Error Render_Gray_Glyph( RAS_ARGS TT_Outline* glyph,
TT_Raster_Map* target,
Byte* palette );
#endif
/* Initialize rasterizer */
LOCAL_DEF
TT_Error TTRaster_Init( PEngine_Instance engine );
/* Finalize it */
LOCAL_DEF
TT_Error TTRaster_Done( PEngine_Instance engine );
#ifdef __cplusplus
}
#endif
#endif /* TTRASTER_H */
/* END */
TTTABLES.H 、、、、、、、、、、、、、、、、 、、、、、、
/*******************************************************************
*
* tttables.h 1.1
*
* TrueType Tables structures and handling (specification).
*
* Copyright 1996-1999 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used
* modified and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
******************************************************************/
#ifndef TTTABLES_H
#define TTTABLES_H
#include "ttconfig.h"
#include "tttypes.h"
#ifdef __cplusplus
extern "C" {
#endif
/***********************************************************************/
/* */
/* TrueType Table Types */
/* */
/***********************************************************************/
/* TrueType Collection Header */
struct TTTCHeader_
{
ULong Tag;
TT_Fixed version;
ULong DirCount;
PULong TableDirectory;
};
typedef struct TTTCHeader_ TTTCHeader;
typedef TTTCHeader* PTTCHeader;
/* TrueType Table Directory type */
struct TTableDir_
{
TT_Fixed version; /* should be 0x10000 */
UShort numTables; /* number of tables */
UShort searchRange; /* These parameters are only used */
UShort entrySelector; /* for a dichotomy search in the */
UShort rangeShift; /* directory. We ignore them. */
};
typedef struct TTableDir_ TTableDir;
typedef TTableDir* PTableDir;
/* The 'TableDir' is followed by 'numTables' TableDirEntries */
struct TTableDirEntry_
{
ULong Tag; /* table type */
ULong CheckSum; /* table checksum */
ULong Offset; /* table file offset */
ULong Length; /* table length */
};
typedef struct TTableDirEntry_ TTableDirEntry;
typedef TTableDirEntry* PTableDirEntry;
/* 'cmap' tables */
struct TCMapDir_
{
UShort tableVersionNumber;
UShort numCMaps;
};
typedef struct TCMapDir_ TCMapDir;
typedef TCMapDir* PCMapDir;
struct TCMapDirEntry_
{
UShort platformID;
UShort platformEncodingID;
Long offset;
};
typedef struct TCMapDirEntry_ TCMapDirEntry;
typedef TCMapDirEntry* PCMapDirEntries;
/* 'maxp' Maximum Profiles table */
struct TMaxProfile_
{
TT_Fixed version;
UShort numGlyphs,
maxPoints,
maxContours,
maxCompositePoints,
maxCompositeContours,
maxZones,
maxTwilightPoints,
maxStorage,
maxFunctionDefs,
maxInstructionDefs,
maxStackElements,
maxSizeOfInstructions,
maxComponentElements,
maxComponentDepth;
};
typedef struct TMaxProfile_ TMaxProfile;
typedef TMaxProfile* PMaxProfile;
/* table "gasp" */
#define GASP_GRIDFIT 0x01
#define GASP_DOGRAY 0x02
struct GaspRange_
{
UShort maxPPEM;
UShort gaspFlag;
};
typedef struct GaspRange_ GaspRange;
struct TGasp_
{
UShort version;
UShort numRanges;
GaspRange* gaspRanges;
};
typedef struct TGasp_ TGasp;
/* table "head" - now defined in freetype.h */
/* table "hhea" - now defined in freetype.h */
/* tables "HMTX" and "VMTX" */
struct TLongMetrics_
{
UShort advance;
Short bearing;
};
typedef struct TLongMetrics_ TLongMetrics, *PLongMetrics;
typedef Short TShortMetrics, *PShortMetrics;
/* 'loca' location table type */
struct TLoca_
{
UShort Size;
PStorage Table;
};
typedef struct TLoca_ TLoca;
/* table "name" */
struct TNameRec_
{
UShort platformID;
UShort encodingID;
UShort languageID;
UShort nameID;
UShort stringLength;
UShort stringOffset;
/* this last field is not defined in the spec */
/* but used by the FreeType engine */
PByte string;
};
typedef struct TNameRec_ TNameRec;
struct TName_Table_
{
UShort format;
UShort numNameRecords;
UShort storageOffset;
TNameRec* names;
PByte storage;
};
typedef struct TName_Table_ TName_Table;
#ifdef __cplusplus
}
#endif
#endif /* TTTABLES_H */
/* END */
TTTAGS.H 、、、、、、、、、、、、、、、、 、、、、、、、、
/*******************************************************************
*
* tttags.h
*
* tags for TrueType tables (specification only).
*
* Copyright 1996-1999 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used
* modified and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
******************************************************************/
#ifndef TTAGS_H
#define TTAGS_H
#include "ttconfig.h"
#include "freetype.h" /* for MAKE_TT_TAG() */
#define TTAG_BASE MAKE_TT_TAG( 'B', 'A', 'S', 'E' )
#define TTAG_bloc MAKE_TT_TAG( 'b', 'l', 'o', 'c' )
#define TTAG_bdat MAKE_TT_TAG( 'b', 'd', 'a', 't' )
#define TTAG_cmap MAKE_TT_TAG( 'c', 'm', 'a', 'p' )
#define TTAG_cvt MAKE_TT_TAG( 'c', 'v', 't', ' ' )
#define TTAG_EBDT MAKE_TT_TAG( 'E', 'B', 'D', 'T' )
#define TTAG_EBLC MAKE_TT_TAG( 'E', 'B', 'L', 'C' )
#define TTAG_EBSC MAKE_TT_TAG( 'E', 'B', 'S', 'C' )
#define TTAG_fpgm MAKE_TT_TAG( 'f', 'p', 'g', 'm' )
#define TTAG_gasp MAKE_TT_TAG( 'g', 'a', 's', 'p' )
#define TTAG_glyf MAKE_TT_TAG( 'g', 'l', 'y', 'f' )
#define TTAG_GDEF MAKE_TT_TAG( 'G', 'D', 'E', 'F' )
#define TTAG_GPOS MAKE_TT_TAG( 'G', 'P', 'O', 'S' )
#define TTAG_GSUB MAKE_TT_TAG( 'G', 'S', 'U', 'B' )
#define TTAG_hdmx MAKE_TT_TAG( 'h', 'd', 'm', 'x' )
#define TTAG_head MAKE_TT_TAG( 'h', 'e', 'a', 'd' )
#define TTAG_hhea MAKE_TT_TAG( 'h', 'h', 'e', 'a' )
#define TTAG_hmtx MAKE_TT_TAG( 'h', 'm', 't', 'x' )
#define TTAG_JSTF MAKE_TT_TAG( 'J', 'S', 'T', 'F' )
#define TTAG_kern MAKE_TT_TAG( 'k', 'e', 'r', 'n' )
#define TTAG_loca MAKE_TT_TAG( 'l', 'o', 'c', 'a' )
#define TTAG_LTSH MAKE_TT_TAG( 'L', 'T', 'S', 'H' )
#define TTAG_maxp MAKE_TT_TAG( 'm', 'a', 'x', 'p' )
#define TTAG_name MAKE_TT_TAG( 'n', 'a', 'm', 'e' )
#define TTAG_OS2 MAKE_TT_TAG( 'O', 'S', '/', '2' )
#define TTAG_PCLT MAKE_TT_TAG( 'P', 'C', 'L', 'T' )
#define TTAG_post MAKE_TT_TAG( 'p', 'o', 's', 't' )
#define TTAG_prep MAKE_TT_TAG( 'p', 'r', 'e', 'p' )
#define TTAG_ttc MAKE_TT_TAG( 't', 't', 'c', ' ' )
#define TTAG_ttcf MAKE_TT_TAG( 't', 't', 'c', 'f' )
#define TTAG_VDMX MAKE_TT_TAG( 'V', 'D', 'M', 'X' )
#define TTAG_vhea MAKE_TT_TAG( 'v', 'h', 'e', 'a' )
#define TTAG_vmtx MAKE_TT_TAG( 'v', 'm', 't', 'x' )
#endif /* TTAGS_H */
/* END */
TTTYPES.H 、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
/*******************************************************************
*
* tttypes.h
*
* Freetype engine's common types specification
* (this spec has no associated body).
*
* Copyright 1996-1999 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used
* modified and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
* NOTE:
*
* All these declarations are library internals, and *not* part
* of the high-level interface. See also 'freetype.h'.
*
******************************************************************/
#ifndef TTTYPES_H
#define TTTYPES_H
#include "ttconfig.h"
#include "freetype.h"
#ifdef __MACTYPES__
#error "<MacTypes.h> have been included, and this prevents the proper\
compilation of this library. Please remove the precompiled headers."
#endif
typedef char String;
typedef signed char Char;
typedef unsigned char Byte;
typedef unsigned short UShort;
typedef signed short Short;
typedef unsigned long ULong;
typedef signed long Long;
typedef TT_Int32 Fixed;
typedef int Int;
/* Simple access types: pointers and tables */
typedef Byte* PByte;
typedef UShort* PUShort;
typedef Short* PShort;
typedef ULong* PULong;
typedef Long* PLong;
typedef Fixed* PFixed;
typedef Int* PInt;
typedef void* Pointer;
typedef TT_F26Dot6* PCoordinates;
typedef unsigned char* PTouchTable;
#ifndef Bool
typedef int Bool; /* No boolean type in C */
#endif
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef NULL
#define NULL (void*)0
#endif
typedef Long Storage;
typedef Storage* PStorage;
/* Rounding mode constants */
#define TT_Round_Off 5
#define TT_Round_To_Half_Grid 0
#define TT_Round_To_Grid 1
#define TT_Round_To_Double_Grid 2
#define TT_Round_Up_To_Grid 4
#define TT_Round_Down_To_Grid 3
#define TT_Round_Super 6
#define TT_Round_Super_45 7
/* Touch flag masks */
#define TT_Flag_On_Curve 1
#define TT_Flag_Touched_X 2
#define TT_Flag_Touched_Y 4
#define TT_Flag_Touched_Both 6
/* Error management constants :) */
#define SUCCESS_OK 0
#define FAILURE -1
/* The min and max functions missing in C. As usual, be careful not to */
/* write things like MIN( a++, b++ ) to avoid side effects. */
#ifndef MIN
#define MIN( a, b ) ( (a) < (b) ? (a) : (b) )
#endif
#ifndef MAX
#define MAX( a, b ) ( (a) > (b) ? (a) : (b) )
#endif
#ifndef ABS
#define ABS( a ) ( (a) < 0 ? -(a) : (a) )
#endif
/* conversion macros for the handles defined in freetype.h */
#define HANDLE_Val( handle ) ((handle).z)
#define HANDLE_Engine( handle ) ((PEngine_Instance)HANDLE_Val( handle ))
#define HANDLE_Face( handle ) ((PFace)HANDLE_Val( handle ))
#define HANDLE_Instance( handle ) ((PInstance)HANDLE_Val( handle ))
/* HANDLE_Stream( handle ) must be defined in ttfile.c */
#define HANDLE_Glyph( handle ) ((PGlyph)HANDLE_Val( handle ))
#define HANDLE_CharMap( handle ) ((PCMapTable)HANDLE_Val( handle ))
#define HANDLE_Set( handle, val ) ((handle).z = (void*)(val))
#endif /* TTTYPES_H */
/* END */