1489 lines
52 KiB
C
1489 lines
52 KiB
C
/***************************************************************************/
|
|
/* */
|
|
/* ttload.c */
|
|
/* */
|
|
/* TrueType tables loader (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. */
|
|
/* */
|
|
/* */
|
|
/* WARNING: This file should not be compiled directly; it is meant to be */
|
|
/* included in the source of several font drivers (i.e., the TTF */
|
|
/* and OTF drivers). */
|
|
/* */
|
|
/***************************************************************************/
|
|
|
|
|
|
#include <ftdebug.h>
|
|
|
|
#include <ttload.h>
|
|
#include <tttags.h>
|
|
#include <ttcmap.h>
|
|
|
|
|
|
/* required by the tracing mode */
|
|
#undef FT_COMPONENT
|
|
#define FT_COMPONENT trace_ttload
|
|
|
|
|
|
/*************************************************************************/
|
|
/* */
|
|
/* <Function> */
|
|
/* TT_LookUp_Table */
|
|
/* */
|
|
/* <Description> */
|
|
/* Looks for a TrueType table by name. */
|
|
/* */
|
|
/* <Input> */
|
|
/* face :: A face object handle. */
|
|
/* tag :: The searched tag. */
|
|
/* */
|
|
/* <Return> */
|
|
/* Index of table if found, -1 otherwise. */
|
|
/* */
|
|
EXPORT_FUNC
|
|
FT_Long TT_LookUp_Table( TT_Face face,
|
|
TT_ULong tag )
|
|
{
|
|
TT_Long i, found;
|
|
|
|
|
|
FT_TRACE4(( "TT_LookUp_Table( %08lx, %c%c%c%c )\n",
|
|
(TT_Long)face,
|
|
(TT_Char)(tag >> 24),
|
|
(TT_Char)(tag >> 16),
|
|
(TT_Char)(tag >> 8),
|
|
(TT_Char)(tag) ));
|
|
|
|
found = -1;
|
|
for ( i = 0; i < face->num_tables; i++ )
|
|
if ( face->dir_tables[i].Tag == tag )
|
|
{
|
|
found = i;
|
|
break;
|
|
}
|
|
|
|
if ( found == -1 )
|
|
{
|
|
FT_TRACE4(( " Could not find table!\n" ));
|
|
}
|
|
|
|
return found;
|
|
}
|
|
|
|
|
|
/*************************************************************************/
|
|
/* */
|
|
/* <Function> */
|
|
/* TT_Load_Collection */
|
|
/* */
|
|
/* <Description> */
|
|
/* Loads the TTC table directory into face table. */
|
|
/* */
|
|
/* <Input> */
|
|
/* face :: A face object handle. */
|
|
/* stream :: The input stream. */
|
|
/* */
|
|
/* <Return> */
|
|
/* TrueType error code. 0 means success. */
|
|
/* */
|
|
static
|
|
TT_Error TT_Load_Collection( TT_Face face,
|
|
FT_Stream stream )
|
|
{
|
|
TT_Long n;
|
|
TT_Error error;
|
|
FT_Memory memory = stream->memory;
|
|
|
|
|
|
FT_TRACE3(( "TT_Load_Collection( %08lx )\n", (TT_Long)face ));
|
|
|
|
if ( FILE_Seek ( 0L ) ||
|
|
ACCESS_Frame( 12L ) )
|
|
goto Exit;
|
|
|
|
face->ttc_header.Tag = GET_Tag4();
|
|
face->ttc_header.version = GET_Long();
|
|
face->ttc_header.DirCount = GET_Long(); /* see comment in tttypes.h */
|
|
|
|
FORGET_Frame();
|
|
|
|
if ( face->ttc_header.Tag != TTAG_ttcf )
|
|
{
|
|
face->ttc_header.Tag = 0;
|
|
face->ttc_header.version = 0;
|
|
face->ttc_header.DirCount = 0;
|
|
|
|
face->ttc_header.TableDirectory = NULL;
|
|
|
|
FT_TRACE3(( "skipped.\n" ));
|
|
|
|
error = TT_Err_File_Is_Not_Collection;
|
|
goto Exit;
|
|
}
|
|
|
|
if ( ALLOC_ARRAY( face->ttc_header.TableDirectory,
|
|
face->ttc_header.DirCount,
|
|
TT_ULong ) ||
|
|
ACCESS_Frame( face->ttc_header.DirCount * 4L ) )
|
|
goto Exit;
|
|
|
|
for ( n = 0; n < face->ttc_header.DirCount; n++ )
|
|
face->ttc_header.TableDirectory[n] = GET_ULong();
|
|
|
|
FORGET_Frame();
|
|
|
|
FT_TRACE3(( "collections directory loaded.\n" ));
|
|
|
|
Exit:
|
|
return error;
|
|
}
|
|
|
|
|
|
/*************************************************************************/
|
|
/* */
|
|
/* <Function> */
|
|
/* TT_Load_Directory */
|
|
/* */
|
|
/* <Description> */
|
|
/* Loads the table directory into a face object. */
|
|
/* */
|
|
/* <Input> */
|
|
/* face :: A handle to the target face object. */
|
|
/* stream :: The input stream. */
|
|
/* faceIndex :: The index of the TrueType font, if we're opening a */
|
|
/* collection. */
|
|
/* */
|
|
/* <Return> */
|
|
/* TrueType error code. 0 means success. */
|
|
/* */
|
|
LOCAL_FUNC
|
|
TT_Error TT_Load_Directory( TT_Face face,
|
|
FT_Stream stream,
|
|
TT_Long faceIndex )
|
|
{
|
|
TT_Error error;
|
|
FT_Memory memory = stream->memory;
|
|
|
|
TT_UShort n, limit;
|
|
TT_TableDir tableDir;
|
|
|
|
TT_TableDirEntry* entry;
|
|
|
|
|
|
FT_TRACE2(( "TT_Load_Directory( %08lx, %ld )\n",
|
|
(TT_Long)face, faceIndex ));
|
|
|
|
error = TT_Load_Collection( face, stream );
|
|
if ( error )
|
|
{
|
|
/* if this is a `traditional' error, exit now */
|
|
if ( error != TT_Err_File_Is_Not_Collection )
|
|
goto Exit;
|
|
|
|
/* the file isn't a collection, exit if we're asking */
|
|
/* for a collected font */
|
|
|
|
/* Note that we don't exit during font format checking (i.e., */
|
|
/* faceIndex is -1) */
|
|
if ( faceIndex > 0 )
|
|
goto Exit;
|
|
|
|
/* Now skip to the beginning of the file */
|
|
if ( FILE_Seek( 0 ) )
|
|
goto Exit;
|
|
}
|
|
else
|
|
{
|
|
/* The file is a collection. Check the font index */
|
|
if ( faceIndex >= face->ttc_header.DirCount )
|
|
{
|
|
error = TT_Err_Bad_Argument;
|
|
goto Exit;
|
|
}
|
|
|
|
/* if we're checking the font format, exit immediately */
|
|
if ( faceIndex < 0 )
|
|
goto Exit;
|
|
|
|
/* select a TrueType font in the ttc file */
|
|
if ( FILE_Seek( face->ttc_header.TableDirectory[faceIndex] ) )
|
|
goto Exit;
|
|
}
|
|
|
|
if ( ACCESS_Frame( 12L ) )
|
|
goto Exit;
|
|
|
|
tableDir.version = GET_Long();
|
|
tableDir.numTables = GET_UShort();
|
|
|
|
tableDir.searchRange = GET_UShort();
|
|
tableDir.entrySelector = GET_UShort();
|
|
tableDir.rangeShift = GET_UShort();
|
|
|
|
FORGET_Frame();
|
|
|
|
FT_TRACE2(( "-- Tables count : %12u\n", tableDir.numTables ));
|
|
FT_TRACE2(( "-- Format version : %08lx\n", tableDir.version ));
|
|
|
|
/* Check that we have a `sfnt' format there */
|
|
/* We must also be able to accept Mac/GX fonts, as well as OT ones */
|
|
|
|
if ( tableDir.version != 0x00010000 &&
|
|
tableDir.version != TTAG_true &&
|
|
tableDir.version != TTAG_OTTO )
|
|
{
|
|
FT_TRACE2(( "[not a valid TTF or OTF font]" ));
|
|
error = TT_Err_Invalid_File_Format;
|
|
goto Exit;
|
|
}
|
|
|
|
/* if we're performing a font format check, exit immediately */
|
|
/* with success */
|
|
if ( faceIndex < 0 )
|
|
goto Exit;
|
|
|
|
face->num_tables = tableDir.numTables;
|
|
|
|
if ( ALLOC_ARRAY( face->dir_tables,
|
|
face->num_tables,
|
|
TT_TableDirEntry ) )
|
|
goto Exit;
|
|
|
|
if ( ACCESS_Frame( face->num_tables * 16L ) )
|
|
goto Exit;
|
|
|
|
limit = face->num_tables;
|
|
entry = face->dir_tables;
|
|
|
|
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();
|
|
|
|
FT_TRACE2(( " %c%c%c%c - %08lx - %08lx\n",
|
|
(TT_Char)(entry->Tag >> 24),
|
|
(TT_Char)(entry->Tag >> 16),
|
|
(TT_Char)(entry->Tag >> 8 ),
|
|
(TT_Char)(entry->Tag),
|
|
entry->Offset,
|
|
entry->Length ));
|
|
entry++;
|
|
}
|
|
|
|
FORGET_Frame();
|
|
|
|
FT_TRACE2(( "Directory loaded\n\n" ));
|
|
|
|
Exit:
|
|
return error;
|
|
}
|
|
|
|
|
|
/*************************************************************************/
|
|
/* */
|
|
/* <Function> */
|
|
/* TT_Load_Any */
|
|
/* */
|
|
/* <Description> */
|
|
/* Loads any font table into client memory. Used by the */
|
|
/* TT_Get_Font_Data() API function. */
|
|
/* */
|
|
/* <Input> */
|
|
/* face :: The face object to look for. */
|
|
/* */
|
|
/* tag :: The 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 :: The starting offset in the table (or the file if */
|
|
/* tag == 0). */
|
|
/* */
|
|
/* length :: The address of the decision variable: */
|
|
/* */
|
|
/* If length == NULL: */
|
|
/* Loads the whole table. Returns an error if */
|
|
/* `offset' == 0! */
|
|
/* */
|
|
/* If *length == 0: */
|
|
/* Exits immediately; returning the length of the given */
|
|
/* table or of the font file, depending on the value of */
|
|
/* `tag'. */
|
|
/* */
|
|
/* If *length != 0: */
|
|
/* Loads the next `length' bytes of table or font, */
|
|
/* starting at offset `offset' (in table or font too). */
|
|
/* */
|
|
/* <Output> */
|
|
/* buffer :: The address of target buffer. */
|
|
/* */
|
|
/* <Return> */
|
|
/* TrueType error code. 0 means success. */
|
|
/* */
|
|
LOCAL_FUNC
|
|
TT_Error TT_Load_Any( TT_Face face,
|
|
TT_ULong tag,
|
|
TT_Long offset,
|
|
void* buffer,
|
|
TT_Long* length )
|
|
{
|
|
TT_Error error;
|
|
FT_Stream stream;
|
|
TT_Long table;
|
|
TT_ULong size;
|
|
|
|
|
|
if ( tag != 0 )
|
|
{
|
|
/* look for tag in font directory */
|
|
table = TT_LookUp_Table( face, tag );
|
|
if ( table < 0 )
|
|
{
|
|
error = TT_Err_Table_Missing;
|
|
goto Exit;
|
|
}
|
|
|
|
offset += face->dir_tables[table].Offset;
|
|
size = face->dir_tables[table].Length;
|
|
}
|
|
else
|
|
/* tag = 0 -- the use want to access the font file directly */
|
|
{
|
|
size = face->root.stream->size;
|
|
}
|
|
|
|
if ( length && *length == 0 )
|
|
{
|
|
*length = size;
|
|
|
|
return TT_Err_Ok;
|
|
}
|
|
|
|
if ( length )
|
|
size = *length;
|
|
|
|
stream = face->root.stream;
|
|
(void)FILE_Read_At( offset, buffer, size );
|
|
|
|
Exit:
|
|
return error;
|
|
}
|
|
|
|
|
|
/*************************************************************************/
|
|
/* */
|
|
/* <Function> */
|
|
/* TT_Load_Header */
|
|
/* */
|
|
/* <Description> */
|
|
/* Loads the TrueType font header. */
|
|
/* */
|
|
/* <Input> */
|
|
/* face :: A handle to the target face object. */
|
|
/* stream :: The input stream. */
|
|
/* */
|
|
/* <Return> */
|
|
/* TrueType error code. 0 means success. */
|
|
/* */
|
|
LOCAL_FUNC
|
|
TT_Error TT_Load_Header( TT_Face face,
|
|
FT_Stream stream )
|
|
{
|
|
TT_Error error;
|
|
|
|
TT_Long table;
|
|
TT_Header* header;
|
|
|
|
|
|
FT_TRACE2(( "Load_TT_Header( %08lx )\n", (TT_Long)face ));
|
|
|
|
if ( ( table = TT_LookUp_Table( face, TTAG_head ) ) < 0 )
|
|
{
|
|
FT_TRACE0(( "Font Header is missing!\n" ));
|
|
error = TT_Err_Header_Table_Missing;
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
if ( FILE_Seek( face->dir_tables[table].Offset ) ||
|
|
ACCESS_Frame( 54L ) )
|
|
goto Exit;
|
|
|
|
header = &face->header;
|
|
|
|
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();
|
|
|
|
FT_TRACE2(( " Units per EM : %8u\n", header->Units_Per_EM ));
|
|
FT_TRACE2(( " IndexToLoc : %8d\n", header->Index_To_Loc_Format ));
|
|
FT_TRACE2(( "Font Header Loaded.\n" ));
|
|
|
|
Exit:
|
|
return error;
|
|
}
|
|
|
|
|
|
/*************************************************************************/
|
|
/* */
|
|
/* <Function> */
|
|
/* TT_Load_MaxProfile */
|
|
/* */
|
|
/* <Description> */
|
|
/* Loads the maximum profile into a face object. */
|
|
/* */
|
|
/* <Input> */
|
|
/* face :: A handle to the target face object. */
|
|
/* stream :: The input stream. */
|
|
/* */
|
|
/* <Return> */
|
|
/* TrueType error code. 0 means success. */
|
|
/* */
|
|
LOCAL_FUNC
|
|
TT_Error TT_Load_MaxProfile( TT_Face face,
|
|
FT_Stream stream )
|
|
{
|
|
TT_Error error;
|
|
|
|
TT_Long i;
|
|
TT_MaxProfile* maxProfile = &face->max_profile;
|
|
|
|
|
|
FT_TRACE2(( "Load_TT_MaxProfile( %08lx )\n", (TT_Long)face ));
|
|
|
|
if ( ( i = TT_LookUp_Table( face, TTAG_maxp ) ) < 0 )
|
|
{
|
|
error = TT_Err_Max_Profile_Missing;
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
if ( FILE_Seek( face->dir_tables[i].Offset ) ||
|
|
ACCESS_Frame( 32L ) )
|
|
goto Exit;
|
|
|
|
/* 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 adjustment 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->root.num_glyphs = maxProfile->numGlyphs;
|
|
|
|
face->root.max_points = MAX( maxProfile->maxCompositePoints,
|
|
maxProfile->maxPoints );
|
|
|
|
face->root.max_contours = MAX( maxProfile->maxCompositeContours,
|
|
maxProfile->maxContours );
|
|
|
|
face->max_components = (TT_ULong)maxProfile->maxComponentElements +
|
|
maxProfile->maxComponentDepth;
|
|
|
|
FT_TRACE2(( "GASP loaded.\n" ));
|
|
|
|
Exit:
|
|
return error;
|
|
}
|
|
|
|
|
|
/*************************************************************************/
|
|
/* */
|
|
/* <Function> */
|
|
/* TT_Load_Metrics */
|
|
/* */
|
|
/* <Description> */
|
|
/* Loads the horizontal or vertical metrics table into a face object. */
|
|
/* */
|
|
/* <Input> */
|
|
/* face :: A handle to the target face object. */
|
|
/* stream :: The input stream. */
|
|
/* vertical :: A boolean flag. If set, load vertical metrics. */
|
|
/* */
|
|
/* <Return> */
|
|
/* TrueType error code. 0 means success. */
|
|
/* */
|
|
static
|
|
TT_Error TT_Load_Metrics( TT_Face face,
|
|
FT_Stream stream,
|
|
TT_Bool vertical )
|
|
{
|
|
TT_Error error;
|
|
FT_Memory memory = stream->memory;
|
|
|
|
TT_UShort n, num_shorts, num_longs;
|
|
TT_Long table;
|
|
|
|
TT_LongMetrics** longs;
|
|
TT_ShortMetrics** shorts;
|
|
|
|
TT_LongMetrics* long_metric;
|
|
|
|
FT_TRACE2(( "TT_Load_%s_Metrics( %08lx )\n",
|
|
vertical ? "Vertical" : "Horizontal", (TT_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! */
|
|
/* */
|
|
table = TT_LookUp_Table( face, TTAG_vmtx );
|
|
if ( table < 0 )
|
|
{
|
|
/* Set the number_Of_VMetrics to 0! */
|
|
FT_TRACE2(( " no vertical header in file.\n" ));
|
|
face->vertical.number_Of_VMetrics = 0;
|
|
error = TT_Err_Ok;
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
num_longs = face->vertical.number_Of_VMetrics;
|
|
longs = (TT_LongMetrics**)&face->vertical.long_metrics;
|
|
shorts = (TT_ShortMetrics**)&face->vertical.short_metrics;
|
|
}
|
|
else
|
|
{
|
|
if ( ( table = TT_LookUp_Table( face, TTAG_hmtx ) ) < 0 )
|
|
{
|
|
FT_ERROR(( " no horizontal metrics in file!\n" ));
|
|
error = TT_Err_Hmtx_Table_Missing;
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
num_longs = face->horizontal.number_Of_HMetrics;
|
|
longs = (TT_LongMetrics**)&face->horizontal.long_metrics;
|
|
shorts = (TT_ShortMetrics**)&face->horizontal.short_metrics;
|
|
}
|
|
|
|
num_shorts = face->max_profile.numGlyphs - num_longs;
|
|
|
|
if ( num_longs > face->max_profile.numGlyphs ) /* sanity check */
|
|
{
|
|
FT_ERROR(( " more metrics than glyphs!\n" ));
|
|
error = TT_Err_Invalid_Horiz_Metrics;
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
if ( ALLOC_ARRAY( *longs, num_longs, TT_LongMetrics ) ||
|
|
ALLOC_ARRAY( *shorts, num_shorts, TT_ShortMetrics ) )
|
|
goto Exit;
|
|
|
|
if ( FILE_Seek( face->dir_tables[table].Offset ) ||
|
|
ACCESS_Frame( face->dir_tables[table].Length ) )
|
|
goto Exit;
|
|
|
|
long_metric = *longs;
|
|
for ( n = 0; n < num_longs; n++ )
|
|
{
|
|
long_metric->advance = GET_UShort();
|
|
long_metric->bearing = GET_Short();
|
|
long_metric++;
|
|
}
|
|
|
|
for ( n = 0; n < num_shorts; n++ )
|
|
(*shorts)[n] = GET_Short();
|
|
|
|
FORGET_Frame();
|
|
|
|
FT_TRACE2(( "loaded\n" ));
|
|
|
|
Exit:
|
|
return error;
|
|
}
|
|
|
|
|
|
/*************************************************************************/
|
|
/* */
|
|
/* <Function> */
|
|
/* TT_Load_Metrics_Header */
|
|
/* */
|
|
/* <Description> */
|
|
/* Loads the horizontal or vertical header in a face object. */
|
|
/* */
|
|
/* <Input> */
|
|
/* face :: A handle to the target face object. */
|
|
/* stream :: The input stream. */
|
|
/* vertical :: A boolean flag. If set, load vertical metrics. */
|
|
/* */
|
|
/* <Return> */
|
|
/* TrueType error code. 0 means success. */
|
|
/* */
|
|
LOCAL_FUNC
|
|
TT_Error TT_Load_Metrics_Header( TT_Face face,
|
|
FT_Stream stream,
|
|
TT_Bool vertical )
|
|
{
|
|
TT_Error error;
|
|
|
|
TT_Long table;
|
|
TT_HoriHeader* header;
|
|
|
|
|
|
FT_TRACE2(( vertical ? "Vertical header " : "Horizontal header " ));
|
|
|
|
if ( vertical )
|
|
{
|
|
face->vertical_info = 0;
|
|
|
|
/* The vertical header table is optional, so return quietly if */
|
|
/* we don't find it. */
|
|
if ( ( table = TT_LookUp_Table( face, TTAG_vhea ) ) < 0 )
|
|
{
|
|
error = TT_Err_Ok;
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
face->vertical_info = 1;
|
|
header = (TT_HoriHeader*)&face->vertical;
|
|
}
|
|
else
|
|
{
|
|
/* The horizontal header is mandatory, return an error if we */
|
|
/* don't find it. */
|
|
if ( ( table = TT_LookUp_Table( face, TTAG_hhea ) ) < 0 )
|
|
{
|
|
error = TT_Err_Horiz_Header_Missing;
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
header = &face->horizontal;
|
|
}
|
|
|
|
if ( FILE_Seek( face->dir_tables[table].Offset ) ||
|
|
ACCESS_Frame( 36L ) )
|
|
goto Exit;
|
|
|
|
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->Reserved[0] = GET_Short();
|
|
header->Reserved[1] = GET_Short();
|
|
header->Reserved[2] = GET_Short();
|
|
header->Reserved[3] = GET_Short();
|
|
header->Reserved[4] = GET_Short();
|
|
|
|
header->metric_Data_Format = GET_Short();
|
|
header->number_Of_HMetrics = GET_UShort();
|
|
|
|
FORGET_Frame();
|
|
|
|
header->long_metrics = NULL;
|
|
header->short_metrics = NULL;
|
|
|
|
FT_TRACE2(( "loaded\n" ));
|
|
|
|
/* Now try to load the corresponding metrics */
|
|
|
|
error = TT_Load_Metrics( face, stream, vertical );
|
|
|
|
Exit:
|
|
return error;
|
|
}
|
|
|
|
|
|
/*************************************************************************/
|
|
/* */
|
|
/* <Function> */
|
|
/* TT_Load_Names */
|
|
/* */
|
|
/* <Description> */
|
|
/* Loads the name records. */
|
|
/* */
|
|
/* <Input> */
|
|
/* face :: A handle to the target face object. */
|
|
/* stream :: The input stream. */
|
|
/* */
|
|
/* <Return> */
|
|
/* TrueType error code. 0 means success. */
|
|
/* */
|
|
LOCAL_FUNC
|
|
TT_Error TT_Load_Names( TT_Face face, FT_Stream stream )
|
|
{
|
|
TT_Error error;
|
|
FT_Memory memory = stream->memory;
|
|
|
|
TT_UShort i;
|
|
TT_Long table;
|
|
TT_Long storageSize;
|
|
|
|
TT_NameTable* names;
|
|
TT_NameRec* namerec;
|
|
|
|
|
|
FT_TRACE2(( "Names " ));
|
|
|
|
if ( ( table = TT_LookUp_Table( face, TTAG_name ) ) < 0 )
|
|
{
|
|
/* The name table is required so indicate failure. */
|
|
FT_TRACE2(( "is missing!\n" ));
|
|
error = TT_Err_Name_Table_Missing;
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
/* Seek to the beginning of the table and check the frame access. */
|
|
/* The names table has a 6 byte header. */
|
|
if ( FILE_Seek( face->dir_tables[table].Offset ) ||
|
|
ACCESS_Frame( 6L ) )
|
|
goto Exit;
|
|
|
|
names = &face->name_table;
|
|
|
|
/* 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,
|
|
TT_NameRec ) ||
|
|
ACCESS_Frame( names->numNameRecords * 12L ) )
|
|
goto Exit;
|
|
|
|
/* Load the name records and determine how much storage is needed */
|
|
/* to hold the strings themselves. */
|
|
namerec = names->names;
|
|
storageSize = 0;
|
|
|
|
for ( i = 0; i < names->numNameRecords; i++, namerec++ )
|
|
{
|
|
TT_Long upper;
|
|
|
|
|
|
namerec->platformID = GET_UShort();
|
|
namerec->encodingID = GET_UShort();
|
|
namerec->languageID = GET_UShort();
|
|
namerec->nameID = GET_UShort();
|
|
namerec->stringLength = GET_UShort();
|
|
namerec->stringOffset = GET_UShort();
|
|
|
|
upper = namerec->stringOffset + namerec->stringLength;
|
|
if ( upper > storageSize ) storageSize = upper;
|
|
}
|
|
|
|
FORGET_Frame();
|
|
|
|
if ( ALLOC( names->storage, storageSize ) ||
|
|
FILE_Read_At( face->dir_tables[table].Offset + names->storageOffset,
|
|
(void*)names->storage, storageSize ) )
|
|
goto Exit;
|
|
|
|
/* Go through and assign the string pointers to the name records. */
|
|
namerec = names->names;
|
|
for ( i = 0; i < names->numNameRecords; i++, namerec++ )
|
|
namerec->string = names->storage + namerec->stringOffset;
|
|
|
|
/* Print Name Record Table in case of debugging */
|
|
#if 0
|
|
namerec = names->names;
|
|
for ( i = 0; i < names->numNameRecords; i++, namerec++ )
|
|
{
|
|
TT_UShort j;
|
|
|
|
|
|
FT_TRACE2(( "%d %d %x %d ",
|
|
namerec->platformID,
|
|
namerec->encodingID,
|
|
namerec->languageID,
|
|
namerec->nameID ));
|
|
|
|
/* I know that M$ encoded strings are Unicode, */
|
|
/* but this works reasonable well for debugging purposes. */
|
|
if ( namerec->string )
|
|
for ( j = 0; j < namerec->stringLength; j++ )
|
|
{
|
|
TT_Char c = *(namerec->string + j);
|
|
|
|
if ( (TT_Byte)c < 128 )
|
|
FT_TRACE2(( "%c", c ));
|
|
}
|
|
}
|
|
FT_TRACE2(( "\n" ));
|
|
#endif
|
|
|
|
FT_TRACE2(( "loaded\n" ));
|
|
|
|
Exit:
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
/*************************************************************************/
|
|
/* */
|
|
/* <Function> */
|
|
/* TT_Free_Names */
|
|
/* */
|
|
/* <Description> */
|
|
/* Frees the name records. */
|
|
/* */
|
|
/* <Input> */
|
|
/* face :: A handle to the target face object. */
|
|
/* */
|
|
/* <Return> */
|
|
/* TrueType error code. 0 means success. */
|
|
/* */
|
|
LOCAL_FUNC
|
|
TT_Error TT_Free_Names( TT_Face face )
|
|
{
|
|
FT_Memory memory = face->root.driver->memory;
|
|
TT_NameTable* names = &face->name_table;
|
|
|
|
|
|
/* 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> */
|
|
/* TT_Load_CMap */
|
|
/* */
|
|
/* <Description> */
|
|
/* Loads the cmap directory in a face object. The cmaps itselves are */
|
|
/* loaded on demand in the `ttcmap.c' module. */
|
|
/* */
|
|
/* <Input> */
|
|
/* face :: A handle to the target face object. */
|
|
/* stream :: A handle to the input stream. */
|
|
/* */
|
|
/* <Return> */
|
|
/* TrueType error code. 0 means success. */
|
|
/* */
|
|
LOCAL_FUNC
|
|
TT_Error TT_Load_CMap( TT_Face face,
|
|
FT_Stream stream )
|
|
{
|
|
TT_Error error;
|
|
FT_Memory memory = stream->memory;
|
|
|
|
TT_Long i, off, cur_off, table_start;
|
|
TT_UShort n, limit;
|
|
|
|
TT_CMapDir cmap_dir;
|
|
TT_CharMap charmap;
|
|
TT_CMapTable* cmap;
|
|
|
|
|
|
FT_TRACE2(( "CMaps " ));
|
|
|
|
if ( ( i = TT_LookUp_Table( face, TTAG_cmap ) ) < 0 )
|
|
{
|
|
error = TT_Err_CMap_Table_Missing;
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
table_start = face->dir_tables[i].Offset;
|
|
|
|
if ( ( FILE_Seek( table_start ) ) ||
|
|
( ACCESS_Frame( 4L ) ) ) /* 4 bytes cmap header */
|
|
goto Exit;
|
|
|
|
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->charmaps,
|
|
cmap_dir.numCMaps,
|
|
TT_CharMapRec ) )
|
|
goto Exit;
|
|
|
|
face->num_charmaps = cmap_dir.numCMaps;
|
|
|
|
limit = face->num_charmaps;
|
|
charmap = face->charmaps;
|
|
|
|
for ( n = 0; n < limit; n++ )
|
|
{
|
|
charmap->root.face = (FT_Face)face;
|
|
cmap = &charmap->cmap;
|
|
|
|
if ( FILE_Seek( off ) ||
|
|
ACCESS_Frame( 8L ) )
|
|
goto Exit;
|
|
|
|
cmap->loaded = FALSE;
|
|
cmap->platformID = GET_UShort();
|
|
cmap->platformEncodingID = GET_UShort();
|
|
|
|
cur_off = GET_Long();
|
|
|
|
FORGET_Frame();
|
|
|
|
off = FILE_Pos();
|
|
|
|
if ( FILE_Seek( table_start + cur_off ) ||
|
|
ACCESS_Frame( 6L ) )
|
|
goto Exit;
|
|
|
|
cmap->format = GET_UShort();
|
|
cmap->length = GET_UShort();
|
|
cmap->version = GET_UShort();
|
|
|
|
FORGET_Frame();
|
|
|
|
cmap->offset = FILE_Pos();
|
|
|
|
charmap++;
|
|
}
|
|
|
|
FT_TRACE2(( "loaded\n" ));
|
|
|
|
Exit:
|
|
return error;
|
|
}
|
|
|
|
|
|
/*************************************************************************/
|
|
/* */
|
|
/* <Function> */
|
|
/* TT_Load_OS2 */
|
|
/* */
|
|
/* <Description> */
|
|
/* Loads the OS2 table. */
|
|
/* */
|
|
/* <Input> */
|
|
/* face :: A handle to the target face object. */
|
|
/* stream :: A handle to the input stream. */
|
|
/* */
|
|
/* <Return> */
|
|
/* TrueType error code. 0 means success. */
|
|
/* */
|
|
LOCAL_FUNC
|
|
TT_Error TT_Load_OS2( TT_Face face,
|
|
FT_Stream stream )
|
|
{
|
|
TT_Error error;
|
|
|
|
TT_Long i;
|
|
TT_Int j;
|
|
TT_OS2* os2;
|
|
|
|
|
|
FT_TRACE2(( "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 )
|
|
{
|
|
FT_TRACE2(( "is missing\n!" ));
|
|
face->os2.version = 0xFFFF;
|
|
error = TT_Err_Ok;
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
if ( FILE_Seek( face->dir_tables[i].Offset ) ||
|
|
ACCESS_Frame( 78L ) )
|
|
goto Exit;
|
|
|
|
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 ( j = 0; j < 10; j++ )
|
|
os2->panose[j] = GET_Byte();
|
|
|
|
os2->ulUnicodeRange1 = GET_ULong();
|
|
os2->ulUnicodeRange2 = GET_ULong();
|
|
os2->ulUnicodeRange3 = GET_ULong();
|
|
os2->ulUnicodeRange4 = GET_ULong();
|
|
|
|
for ( j = 0; j < 4; j++ )
|
|
os2->achVendID[j] = 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 */
|
|
goto Exit;
|
|
|
|
os2->ulCodePageRange1 = GET_ULong();
|
|
os2->ulCodePageRange2 = GET_ULong();
|
|
|
|
FORGET_Frame();
|
|
}
|
|
else
|
|
{
|
|
os2->ulCodePageRange1 = 0;
|
|
os2->ulCodePageRange2 = 0;
|
|
}
|
|
|
|
FT_TRACE2(( "loaded\n" ));
|
|
|
|
Exit:
|
|
return error;
|
|
}
|
|
|
|
|
|
/*************************************************************************/
|
|
/* */
|
|
/* <Function> */
|
|
/* TT_Load_Postscript */
|
|
/* */
|
|
/* <Description> */
|
|
/* Loads the Postscript table. */
|
|
/* */
|
|
/* <Input> */
|
|
/* face :: A handle to the target face object. */
|
|
/* stream :: A handle to the input stream. */
|
|
/* */
|
|
/* <Return> */
|
|
/* TrueType error code. 0 means success. */
|
|
/* */
|
|
LOCAL_FUNC
|
|
TT_Error TT_Load_PostScript( TT_Face face,
|
|
FT_Stream stream )
|
|
{
|
|
TT_Error error;
|
|
TT_Long i;
|
|
TT_Postscript* post = &face->postscript;
|
|
|
|
|
|
FT_TRACE2(( "PostScript " ));
|
|
|
|
if ( ( i = TT_LookUp_Table( face, TTAG_post ) ) < 0 )
|
|
return TT_Err_Post_Table_Missing;
|
|
|
|
if ( FILE_Seek( face->dir_tables[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 another */
|
|
/* module (ttpost). */
|
|
|
|
FT_TRACE2(( "loaded\n" ));
|
|
|
|
return TT_Err_Ok;
|
|
}
|
|
|
|
|
|
/*************************************************************************/
|
|
/* */
|
|
/* <Function> */
|
|
/* TT_Load_Gasp */
|
|
/* */
|
|
/* <Description> */
|
|
/* Loads the `GASP' table into a face object. */
|
|
/* */
|
|
/* <Input> */
|
|
/* face :: A handle to the target face object. */
|
|
/* stream :: The input stream. */
|
|
/* */
|
|
/* <Return> */
|
|
/* TrueType error code. 0 means success. */
|
|
/* */
|
|
LOCAL_FUNC
|
|
TT_Error TT_Load_Gasp( TT_Face face,
|
|
FT_Stream stream )
|
|
{
|
|
TT_Error error;
|
|
FT_Memory memory = stream->memory;
|
|
|
|
TT_Long table;
|
|
TT_UShort num_ranges;
|
|
TT_UShort j;
|
|
TT_GaspRange* gaspranges;
|
|
|
|
|
|
FT_TRACE2(( "TT_Load_Gasp( %08lx )\n", (TT_Long)face ));
|
|
|
|
error = TT_Err_Ok;
|
|
|
|
/* the gasp table is optional */
|
|
if ( ( table = TT_LookUp_Table( face, TTAG_gasp ) ) < 0 )
|
|
goto Exit;
|
|
|
|
if ( FILE_Seek( face->dir_tables[table].Offset ) ||
|
|
ACCESS_Frame( 4L ) )
|
|
goto Exit;
|
|
|
|
face->gasp.version = GET_UShort();
|
|
face->gasp.numRanges = GET_UShort();
|
|
|
|
FORGET_Frame();
|
|
|
|
num_ranges = face->gasp.numRanges;
|
|
FT_TRACE3(( "number of ranges = %d\n", num_ranges ));
|
|
|
|
if ( ALLOC_ARRAY( gaspranges, num_ranges, TT_GaspRange ) ||
|
|
ACCESS_Frame( num_ranges * 4L ) )
|
|
goto Exit;
|
|
|
|
face->gasp.gaspRanges = gaspranges;
|
|
|
|
for ( j = 0; j < num_ranges; j++ )
|
|
{
|
|
gaspranges[j].maxPPEM = GET_UShort();
|
|
gaspranges[j].gaspFlag = GET_UShort();
|
|
|
|
FT_TRACE3(( " [max:%d flag:%d]",
|
|
gaspranges[j].maxPPEM,
|
|
gaspranges[j].gaspFlag ));
|
|
}
|
|
FT_TRACE3(( "\n" ));
|
|
|
|
FORGET_Frame();
|
|
|
|
FT_TRACE2(( "GASP loaded\n" ));
|
|
|
|
Exit:
|
|
return error;
|
|
}
|
|
|
|
|
|
/*************************************************************************/
|
|
/* */
|
|
/* <Function> */
|
|
/* TT_Load_Kern */
|
|
/* */
|
|
/* <Description> */
|
|
/* Loads the first kerning table with format 0 in the font. Only */
|
|
/* accepts the first horizontal kerning table. Developers should use */
|
|
/* the `ftxkern' extension to access other kerning tables in the font */
|
|
/* file, if they really want to. */
|
|
/* */
|
|
/* <Input> */
|
|
/* face :: A handle to the target face object. */
|
|
/* stream :: The input stream. */
|
|
/* */
|
|
/* <Return> */
|
|
/* TrueType error code. 0 means success. */
|
|
/* */
|
|
LOCAL_FUNC
|
|
TT_Error TT_Load_Kern( TT_Face face,
|
|
FT_Stream stream )
|
|
{
|
|
TT_Error error;
|
|
FT_Memory memory = stream->memory;
|
|
|
|
TT_Long table;
|
|
TT_UShort n, num_tables, version;
|
|
|
|
|
|
error = TT_Err_Ok;
|
|
table = TT_LookUp_Table( face, TTAG_kern );
|
|
if ( table < 0 )
|
|
goto Exit;
|
|
|
|
if ( FILE_Seek( face->dir_tables[table].Offset ) ||
|
|
READ_UShort( version ) ||
|
|
READ_UShort( num_tables ) )
|
|
goto Exit;
|
|
|
|
for ( n = 0; n < num_tables; n++ )
|
|
{
|
|
TT_UShort coverage;
|
|
|
|
|
|
if ( FILE_Skip( 4L ) ||
|
|
READ_UShort( coverage ) )
|
|
goto Exit;
|
|
|
|
if ( coverage == 0x0001 )
|
|
{
|
|
TT_UShort num_pairs, m;
|
|
TT_Kern_0_Pair* pair;
|
|
|
|
|
|
/* found a horizontal format 0 kerning table ! */
|
|
if ( READ_UShort( num_pairs ) ||
|
|
FILE_Skip( 6 ) )
|
|
goto Exit;
|
|
|
|
/* allocate array of kerning pairs */
|
|
if ( ALLOC_ARRAY( face->kern_pairs, num_pairs, TT_Kern_0_Pair ) )
|
|
goto Exit;
|
|
|
|
/* read the kerning pairs */
|
|
if ( ACCESS_Frame( 6L * num_pairs ) )
|
|
goto Exit;
|
|
|
|
pair = face->kern_pairs;
|
|
for ( m = 0; m < num_pairs; m++ )
|
|
{
|
|
pair->left = GET_UShort();
|
|
pair->right = GET_UShort();
|
|
pair->value = GET_UShort();
|
|
pair++;
|
|
}
|
|
|
|
FORGET_Frame();
|
|
|
|
face->num_kern_pairs = num_pairs;
|
|
face->kern_table_index = n;
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
/* no kern table found -- doesn't matter */
|
|
face->kern_table_index = -1;
|
|
face->num_kern_pairs = 0;
|
|
face->kern_pairs = NULL;
|
|
|
|
Exit:
|
|
return error;
|
|
}
|
|
|
|
|
|
/*************************************************************************/
|
|
/* */
|
|
/* <Function> */
|
|
/* TT_Load_Hdmx */
|
|
/* */
|
|
/* <Description> */
|
|
/* Loads the horizontal device metrics table. */
|
|
/* */
|
|
/* <Input> */
|
|
/* face :: A handle to the target face object. */
|
|
/* stream :: A handle to the input stream. */
|
|
/* */
|
|
/* <Return> */
|
|
/* TrueType error code. 0 means success. */
|
|
/* */
|
|
LOCAL_FUNC
|
|
TT_Error TT_Load_Hdmx( TT_Face face,
|
|
FT_Stream stream )
|
|
{
|
|
TT_Error error;
|
|
FT_Memory memory = stream->memory;
|
|
|
|
TT_HdmxRec* rec;
|
|
TT_Hdmx hdmx;
|
|
TT_Long table;
|
|
TT_UShort n;
|
|
TT_Long num_glyphs;
|
|
TT_Long record_size;
|
|
|
|
hdmx.version = 0;
|
|
hdmx.num_records = 0;
|
|
hdmx.records = 0;
|
|
|
|
face->hdmx = hdmx;
|
|
|
|
error = TT_Err_Ok;
|
|
|
|
/* ths table is optional */
|
|
if ( ( table = TT_LookUp_Table( face, TTAG_hdmx ) ) < 0 )
|
|
return error;
|
|
|
|
if ( FILE_Seek( face->dir_tables[table].Offset ) ||
|
|
ACCESS_Frame( 8L ) )
|
|
goto Exit;
|
|
|
|
hdmx.version = GET_UShort();
|
|
hdmx.num_records = GET_Short();
|
|
record_size = GET_Long();
|
|
|
|
FORGET_Frame();
|
|
|
|
/* Only recognize format 0 */
|
|
if ( hdmx.version != 0 )
|
|
goto Exit;
|
|
|
|
if ( ALLOC( hdmx.records, sizeof ( TT_HdmxRec ) * hdmx.num_records ) )
|
|
goto Exit;
|
|
|
|
num_glyphs = face->root.num_glyphs;
|
|
record_size -= num_glyphs + 2;
|
|
rec = hdmx.records;
|
|
|
|
for ( n = 0; n < hdmx.num_records; n++ )
|
|
{
|
|
/* read record */
|
|
if ( READ_Byte( rec->ppem ) ||
|
|
READ_Byte( rec->max_width ) )
|
|
goto Exit;
|
|
|
|
if ( ALLOC( rec->widths, num_glyphs ) ||
|
|
FILE_Read( rec->widths, num_glyphs ) )
|
|
goto Exit;
|
|
|
|
/* skip padding bytes */
|
|
if ( record_size > 0 )
|
|
if ( FILE_Skip( record_size ) )
|
|
goto Exit;
|
|
|
|
rec++;
|
|
}
|
|
|
|
face->hdmx = hdmx;
|
|
|
|
Exit:
|
|
return error;
|
|
}
|
|
|
|
|
|
/*************************************************************************/
|
|
/* */
|
|
/* <Function> */
|
|
/* TT_Free_Hdmx */
|
|
/* */
|
|
/* <Description> */
|
|
/* Frees the horizontal device metrics table. */
|
|
/* */
|
|
/* <Input> */
|
|
/* face :: A handle to the target face object. */
|
|
/* */
|
|
/* <Return> */
|
|
/* TrueType error code. 0 means success. */
|
|
/* */
|
|
LOCAL_FUNC
|
|
TT_Error TT_Free_Hdmx( TT_Face face )
|
|
{
|
|
if ( face )
|
|
{
|
|
TT_UShort n;
|
|
FT_Memory memory = face->root.driver->memory;
|
|
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
/* END */
|