diff options
author | Karl Berry <karl@freefriends.org> | 2006-01-16 00:09:26 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2006-01-16 00:09:26 +0000 |
commit | 6c0eafbb1395d426a72a74538e0b2a95e8344ca6 (patch) | |
tree | 2a5f80b80fc76086a2602b812c2a182d00f961b7 /Build/source/libs/libttf/ttload.c | |
parent | 70f7efeb5c9965a63a4143ad1c1f473585dc364c (diff) |
libs 1
git-svn-id: svn://tug.org/texlive/trunk@1483 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/libs/libttf/ttload.c')
-rw-r--r-- | Build/source/libs/libttf/ttload.c | 1574 |
1 files changed, 1574 insertions, 0 deletions
diff --git a/Build/source/libs/libttf/ttload.c b/Build/source/libs/libttf/ttload.c new file mode 100644 index 00000000000..282828fdeec --- /dev/null +++ b/Build/source/libs/libttf/ttload.c @@ -0,0 +1,1574 @@ + +/******************************************************************* + * + * 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; + + 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 */ + + /* 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; + + /* 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(); + + FORGET_Frame(); + + off = FILE_Pos(); + + 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(); + + 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 */ |