1999-12-17 00:11:37 +01:00
|
|
|
/***************************************************************************/
|
|
|
|
/* */
|
|
|
|
/* ttload.c */
|
|
|
|
/* */
|
2000-06-05 07:26:15 +02:00
|
|
|
/* Load the basic TrueType tables, i.e., tables that can be either in */
|
|
|
|
/* TTF or OTF fonts (body). */
|
1999-12-17 00:11:37 +01:00
|
|
|
/* */
|
2000-06-05 07:26:15 +02:00
|
|
|
/* Copyright 1996-2000 by */
|
1999-12-17 00:11:37 +01:00
|
|
|
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
|
|
|
|
/* */
|
2000-06-05 07:26:15 +02:00
|
|
|
/* This file is part of the FreeType project, and may only be used, */
|
|
|
|
/* modified, and distributed under the terms of the FreeType project */
|
1999-12-17 00:11:37 +01:00
|
|
|
/* 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. */
|
|
|
|
/* */
|
|
|
|
/***************************************************************************/
|
|
|
|
|
|
|
|
|
2000-05-11 20:23:52 +02:00
|
|
|
#include <freetype/internal/ftdebug.h>
|
|
|
|
#include <freetype/internal/tterrors.h>
|
|
|
|
#include <freetype/tttags.h>
|
1999-12-17 00:11:37 +01:00
|
|
|
|
|
|
|
#include <ttload.h>
|
|
|
|
#include <ttcmap.h>
|
|
|
|
|
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
/*************************************************************************/
|
|
|
|
/* */
|
|
|
|
/* The macro FT_COMPONENT is used in trace mode. It is an implicit */
|
|
|
|
/* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
|
|
|
|
/* messages during execution. */
|
|
|
|
/* */
|
|
|
|
#undef FT_COMPONENT
|
|
|
|
#define FT_COMPONENT trace_ttload
|
2000-02-13 14:41:56 +01:00
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
|
|
|
|
/*************************************************************************/
|
|
|
|
/* */
|
|
|
|
/* <Function> */
|
|
|
|
/* TT_LookUp_Table */
|
|
|
|
/* */
|
|
|
|
/* <Description> */
|
|
|
|
/* Looks for a TrueType table by name. */
|
|
|
|
/* */
|
|
|
|
/* <Input> */
|
|
|
|
/* face :: A face object handle. */
|
2000-06-05 07:26:15 +02:00
|
|
|
/* tag :: The searched tag. */
|
1999-12-17 00:11:37 +01:00
|
|
|
/* */
|
|
|
|
/* <Return> */
|
2000-06-05 07:26:15 +02:00
|
|
|
/* A pointer to the table directory entry. 0 if not found. */
|
1999-12-17 00:11:37 +01:00
|
|
|
/* */
|
2000-05-12 14:17:15 +02:00
|
|
|
LOCAL_FUNC
|
1999-12-17 00:11:37 +01:00
|
|
|
TT_Table* TT_LookUp_Table( TT_Face face,
|
|
|
|
TT_ULong tag )
|
|
|
|
{
|
|
|
|
TT_Table* entry;
|
|
|
|
TT_Table* limit;
|
2000-05-17 01:44:38 +02:00
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
|
|
|
|
FT_TRACE3(( "TT_LookUp_Table: %08p, `%c%c%c%c' )\n",
|
2000-05-18 18:18:05 +02:00
|
|
|
face,
|
2000-06-05 07:26:15 +02:00
|
|
|
(TT_Char)( tag >> 24 ),
|
|
|
|
(TT_Char)( tag >> 16 ),
|
|
|
|
(TT_Char)( tag >> 8 ),
|
|
|
|
(TT_Char)( tag ) ));
|
1999-12-17 00:11:37 +01:00
|
|
|
|
|
|
|
entry = face->dir_tables;
|
|
|
|
limit = entry + face->num_tables;
|
2000-06-05 07:26:15 +02:00
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
for ( ; entry < limit; entry++ )
|
|
|
|
{
|
|
|
|
if ( entry->Tag == tag )
|
|
|
|
return entry;
|
2000-05-17 01:44:38 +02:00
|
|
|
}
|
2000-06-05 07:26:15 +02:00
|
|
|
|
|
|
|
FT_TRACE3(( " Could not find table!\n" ));
|
1999-12-17 00:11:37 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
/*************************************************************************/
|
|
|
|
/* */
|
|
|
|
/* <Function> */
|
|
|
|
/* TT_Goto_Table */
|
|
|
|
/* */
|
|
|
|
/* <Description> */
|
|
|
|
/* Looks for a TrueType table by name, then seek a stream to it. */
|
|
|
|
/* */
|
|
|
|
/* <Input> */
|
2000-06-05 07:26:15 +02:00
|
|
|
/* face :: A face object handle. */
|
|
|
|
/* tag :: The searched tag. */
|
|
|
|
/* stream :: The stream to seek when the table is found. */
|
|
|
|
/* */
|
|
|
|
/* <Output> */
|
|
|
|
/* length :: The length of the table if found, undefined otherwise. */
|
1999-12-17 00:11:37 +01:00
|
|
|
/* */
|
|
|
|
/* <Return> */
|
2000-06-05 07:26:15 +02:00
|
|
|
/* TrueType error code. 0 means success. */
|
1999-12-17 00:11:37 +01:00
|
|
|
/* */
|
2000-05-12 14:17:15 +02:00
|
|
|
LOCAL_FUNC
|
2000-06-05 07:26:15 +02:00
|
|
|
TT_Error TT_Goto_Table( TT_Face face,
|
|
|
|
TT_ULong tag,
|
|
|
|
FT_Stream stream,
|
|
|
|
TT_ULong* length )
|
1999-12-17 00:11:37 +01:00
|
|
|
{
|
|
|
|
TT_Table* table;
|
|
|
|
TT_Error error;
|
2000-05-17 01:44:38 +02:00
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
table = TT_LookUp_Table( face, tag );
|
2000-06-05 07:26:15 +02:00
|
|
|
if ( table )
|
1999-12-17 00:11:37 +01:00
|
|
|
{
|
2000-06-05 07:26:15 +02:00
|
|
|
if ( length )
|
1999-12-17 00:11:37 +01:00
|
|
|
*length = table->Length;
|
2000-05-17 01:44:38 +02:00
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
(void)FILE_Seek( table->Offset );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
error = TT_Err_Table_Missing;
|
2000-05-17 01:44:38 +02:00
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*************************************************************************/
|
|
|
|
/* */
|
2000-06-05 07:26:15 +02:00
|
|
|
/* <Function> */
|
2000-05-29 22:37:41 +02:00
|
|
|
/* TT_Load_SFNT_Header */
|
1999-12-17 00:11:37 +01:00
|
|
|
/* */
|
|
|
|
/* <Description> */
|
2000-06-05 07:26:15 +02:00
|
|
|
/* Loads the header of a SFNT font file. Supports collections. */
|
1999-12-17 00:11:37 +01:00
|
|
|
/* */
|
|
|
|
/* <Input> */
|
2000-06-05 07:26:15 +02:00
|
|
|
/* face :: A handle to the target face object. */
|
|
|
|
/* stream :: The input stream. */
|
|
|
|
/* face_index :: If the font is a collection, the number of the font */
|
|
|
|
/* in the collection, ignored otherwise. */
|
2000-05-29 22:37:41 +02:00
|
|
|
/* */
|
2000-01-27 14:56:02 +01:00
|
|
|
/* <Output> */
|
2000-06-05 07:26:15 +02:00
|
|
|
/* sfnt :: The SFNT header. */
|
1999-12-17 00:11:37 +01:00
|
|
|
/* */
|
|
|
|
/* <Return> */
|
|
|
|
/* TrueType error code. 0 means success. */
|
|
|
|
/* */
|
|
|
|
/* <Note> */
|
2000-06-05 07:26:15 +02:00
|
|
|
/* The stream cursor must be at the font file's origin. */
|
1999-12-17 00:11:37 +01:00
|
|
|
/* */
|
2000-06-05 07:26:15 +02:00
|
|
|
/* This function recognizes fonts embedded in a `TrueType collection' */
|
|
|
|
/* */
|
|
|
|
/* The header will be checked whether it is valid by looking at the */
|
|
|
|
/* values of `search_range', `entry_selector', and `range_shift'. */
|
2000-05-29 22:37:41 +02:00
|
|
|
/* */
|
1999-12-17 00:11:37 +01:00
|
|
|
LOCAL_FUNC
|
2000-06-05 07:26:15 +02:00
|
|
|
TT_Error TT_Load_SFNT_Header( TT_Face face,
|
|
|
|
FT_Stream stream,
|
|
|
|
TT_Long face_index,
|
|
|
|
SFNT_Header* sfnt )
|
1999-12-17 00:11:37 +01:00
|
|
|
{
|
2000-05-29 22:37:41 +02:00
|
|
|
TT_Error error;
|
|
|
|
TT_ULong format_tag;
|
|
|
|
FT_Memory memory = stream->memory;
|
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
const FT_Frame_Field sfnt_header_fields[] =
|
|
|
|
{
|
|
|
|
FT_FRAME_START( 8 ),
|
|
|
|
FT_FRAME_USHORT( SFNT_Header, num_tables ),
|
|
|
|
FT_FRAME_USHORT( SFNT_Header, search_range ),
|
|
|
|
FT_FRAME_USHORT( SFNT_Header, entry_selector ),
|
|
|
|
FT_FRAME_USHORT( SFNT_Header, range_shift ),
|
|
|
|
FT_FRAME_END
|
|
|
|
};
|
2000-05-29 22:37:41 +02:00
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
const FT_Frame_Field ttc_header_fields[] =
|
|
|
|
{
|
|
|
|
FT_FRAME_START( 8 ),
|
|
|
|
FT_FRAME_LONG( TTC_Header, version ),
|
|
|
|
FT_FRAME_LONG( TTC_Header, DirCount ),
|
|
|
|
FT_FRAME_END };
|
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
FT_TRACE2(( "TT_Load_SFNT_Header: %08p, %ld\n",
|
2000-06-01 05:26:58 +02:00
|
|
|
face, face_index ));
|
1999-12-17 00:11:37 +01:00
|
|
|
|
|
|
|
face->ttc_header.Tag = 0;
|
|
|
|
face->ttc_header.version = 0;
|
|
|
|
face->ttc_header.DirCount = 0;
|
|
|
|
|
|
|
|
face->num_tables = 0;
|
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
/* first of all, read the first 4 bytes. If it's `ttcf', then the */
|
2000-01-27 14:56:02 +01:00
|
|
|
/* file is a TrueType collection, otherwise it can be any other */
|
2000-06-05 07:26:15 +02:00
|
|
|
/* kind of font. */
|
|
|
|
if ( READ_ULong( format_tag ) )
|
|
|
|
goto Exit;
|
1999-12-17 00:11:37 +01:00
|
|
|
|
2000-05-29 22:37:41 +02:00
|
|
|
if ( format_tag == TTAG_ttcf )
|
1999-12-17 00:11:37 +01:00
|
|
|
{
|
|
|
|
TT_Int n;
|
2000-05-17 01:44:38 +02:00
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
|
|
|
|
FT_TRACE3(( "TT_Load_SFNT_Header: file is a collection\n" ));
|
2000-05-17 01:44:38 +02:00
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
/* it's a TrueType collection, i.e. a file containing several */
|
2000-06-05 07:26:15 +02:00
|
|
|
/* font files. Read the font directory now */
|
2000-02-13 14:41:56 +01:00
|
|
|
if ( READ_Fields( ttc_header_fields, &face->ttc_header ) )
|
|
|
|
goto Exit;
|
1999-12-17 00:11:37 +01:00
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
/* now read the offsets of each font in the file */
|
1999-12-17 00:11:37 +01:00
|
|
|
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();
|
|
|
|
|
|
|
|
/* check face index */
|
2000-06-05 07:26:15 +02:00
|
|
|
if ( face_index >= face->ttc_header.DirCount )
|
1999-12-17 00:11:37 +01:00
|
|
|
{
|
|
|
|
error = TT_Err_Bad_Argument;
|
|
|
|
goto Exit;
|
2000-05-17 01:44:38 +02:00
|
|
|
}
|
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
/* seek to the appropriate TrueType file, then read tag */
|
2000-05-29 22:37:41 +02:00
|
|
|
if ( FILE_Seek( face->ttc_header.TableDirectory[face_index] ) ||
|
|
|
|
READ_Long( format_tag ) )
|
1999-12-17 00:11:37 +01:00
|
|
|
goto Exit;
|
|
|
|
}
|
|
|
|
|
2000-05-29 22:37:41 +02:00
|
|
|
/* the format tag was read, now check the rest of the header */
|
|
|
|
sfnt->format_tag = format_tag;
|
|
|
|
if ( READ_Fields( sfnt_header_fields, sfnt ) )
|
|
|
|
goto Exit;
|
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
/* now, check the values of `num_tables', `seach_range', etc. */
|
2000-05-29 22:37:41 +02:00
|
|
|
{
|
|
|
|
TT_UInt num_tables = sfnt->num_tables;
|
|
|
|
TT_ULong entry_selector = 1L << sfnt->entry_selector;
|
2000-06-01 05:26:58 +02:00
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
|
|
|
|
/* IMPORTANT: Many fonts have an incorrect `search_range' value, so */
|
|
|
|
/* we only check the `entry_selector' correctness here. */
|
|
|
|
/* */
|
|
|
|
if ( num_tables == 0 ||
|
|
|
|
entry_selector > num_tables ||
|
|
|
|
entry_selector * 2 <= num_tables )
|
2000-06-01 05:26:58 +02:00
|
|
|
{
|
2000-06-05 07:26:15 +02:00
|
|
|
FT_TRACE2(( "TT_Load_SFNT_Header: file is not SFNT!\n" ));
|
2000-05-29 22:37:41 +02:00
|
|
|
error = FT_Err_Unknown_File_Format;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-01-27 14:56:02 +01:00
|
|
|
Exit:
|
|
|
|
return error;
|
2000-05-29 22:37:41 +02:00
|
|
|
}
|
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
|
2000-01-27 14:56:02 +01:00
|
|
|
/*************************************************************************/
|
|
|
|
/* */
|
|
|
|
/* <Function> */
|
|
|
|
/* TT_Load_Directory */
|
|
|
|
/* */
|
|
|
|
/* <Description> */
|
|
|
|
/* Loads the table directory into a face object. */
|
|
|
|
/* */
|
2000-06-05 07:26:15 +02:00
|
|
|
/* <InOut> */
|
|
|
|
/* face :: A handle to the target face object. */
|
|
|
|
/* */
|
2000-01-27 14:56:02 +01:00
|
|
|
/* <Input> */
|
2000-06-05 07:26:15 +02:00
|
|
|
/* stream :: The input stream. */
|
|
|
|
/* sfnt :: The SFNT directory header. */
|
2000-01-27 14:56:02 +01:00
|
|
|
/* */
|
|
|
|
/* <Return> */
|
|
|
|
/* TrueType error code. 0 means success. */
|
|
|
|
/* */
|
|
|
|
/* <Note> */
|
2000-06-05 07:26:15 +02:00
|
|
|
/* The stream cursor must be at the font file's origin. */
|
2000-01-27 14:56:02 +01:00
|
|
|
/* */
|
|
|
|
LOCAL_FUNC
|
2000-05-29 22:37:41 +02:00
|
|
|
TT_Error TT_Load_Directory( TT_Face face,
|
|
|
|
FT_Stream stream,
|
|
|
|
SFNT_Header* sfnt )
|
2000-01-27 14:56:02 +01:00
|
|
|
{
|
|
|
|
TT_Error error;
|
|
|
|
FT_Memory memory = stream->memory;
|
|
|
|
|
|
|
|
TT_Table *entry, *limit;
|
|
|
|
|
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
FT_TRACE2(( "TT_Load_Directory: %08p\n", face ));
|
|
|
|
|
|
|
|
FT_TRACE2(( "-- Tables count: %12u\n", sfnt->num_tables ));
|
|
|
|
FT_TRACE2(( "-- Format version: %08lx\n", sfnt->format_tag ));
|
2000-01-27 14:56:02 +01:00
|
|
|
|
2000-05-29 22:37:41 +02:00
|
|
|
face->num_tables = sfnt->num_tables;
|
1999-12-17 00:11:37 +01:00
|
|
|
|
|
|
|
if ( ALLOC_ARRAY( face->dir_tables,
|
|
|
|
face->num_tables,
|
|
|
|
TT_Table ) )
|
|
|
|
goto Exit;
|
|
|
|
|
|
|
|
if ( ACCESS_Frame( face->num_tables * 16L ) )
|
|
|
|
goto Exit;
|
|
|
|
|
|
|
|
entry = face->dir_tables;
|
|
|
|
limit = entry + face->num_tables;
|
|
|
|
|
|
|
|
for ( ; entry < limit; entry++ )
|
2000-01-27 14:56:02 +01:00
|
|
|
{ /* loop through the tables and get all entries */
|
1999-12-17 00:11:37 +01:00
|
|
|
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",
|
2000-06-05 07:26:15 +02:00
|
|
|
(TT_Char)( entry->Tag >> 24 ),
|
|
|
|
(TT_Char)( entry->Tag >> 16 ),
|
|
|
|
(TT_Char)( entry->Tag >> 8 ),
|
|
|
|
(TT_Char)( entry->Tag ),
|
|
|
|
entry->Offset,
|
|
|
|
entry->Length ));
|
1999-12-17 00:11:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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. */
|
|
|
|
/* */
|
2000-06-05 07:26:15 +02:00
|
|
|
/* tag :: The tag of table to load. Use the value 0 if you want */
|
1999-12-17 00:11:37 +01:00
|
|
|
/* 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_Table* table;
|
|
|
|
TT_ULong size;
|
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
if ( tag != 0 )
|
|
|
|
{
|
|
|
|
/* look for tag in font directory */
|
|
|
|
table = TT_LookUp_Table( face, tag );
|
|
|
|
if ( !table )
|
|
|
|
{
|
|
|
|
error = TT_Err_Table_Missing;
|
|
|
|
goto Exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
offset += table->Offset;
|
|
|
|
size = table->Length;
|
|
|
|
}
|
|
|
|
else
|
2000-06-05 07:26:15 +02:00
|
|
|
/* tag == 0 -- the user wants to access the font file directly */
|
1999-12-17 00:11:37 +01:00
|
|
|
size = face->root.stream->size;
|
|
|
|
|
|
|
|
if ( length && *length == 0 )
|
|
|
|
{
|
|
|
|
*length = size;
|
2000-06-05 07:26:15 +02:00
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
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_Header* header;
|
2000-05-29 22:37:41 +02:00
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
static const FT_Frame_Field header_fields[] =
|
|
|
|
{
|
|
|
|
FT_FRAME_START( 54 ),
|
|
|
|
FT_FRAME_ULONG( TT_Header, Table_Version ),
|
|
|
|
FT_FRAME_ULONG( TT_Header, Font_Revision ),
|
|
|
|
FT_FRAME_LONG( TT_Header, CheckSum_Adjust ),
|
|
|
|
FT_FRAME_LONG( TT_Header, Magic_Number ),
|
|
|
|
FT_FRAME_USHORT( TT_Header, Flags ),
|
|
|
|
FT_FRAME_USHORT( TT_Header, Units_Per_EM ),
|
|
|
|
FT_FRAME_LONG( TT_Header, Created[0] ),
|
|
|
|
FT_FRAME_LONG( TT_Header, Created[1] ),
|
|
|
|
FT_FRAME_LONG( TT_Header, Modified[0] ),
|
|
|
|
FT_FRAME_LONG( TT_Header, Modified[1] ),
|
|
|
|
FT_FRAME_SHORT( TT_Header, xMin ),
|
|
|
|
FT_FRAME_SHORT( TT_Header, yMin ),
|
|
|
|
FT_FRAME_SHORT( TT_Header, xMax ),
|
|
|
|
FT_FRAME_SHORT( TT_Header, yMax ),
|
|
|
|
FT_FRAME_USHORT( TT_Header, Mac_Style ),
|
|
|
|
FT_FRAME_USHORT( TT_Header, Lowest_Rec_PPEM ),
|
|
|
|
FT_FRAME_SHORT( TT_Header, Font_Direction ),
|
|
|
|
FT_FRAME_SHORT( TT_Header, Index_To_Loc_Format ),
|
|
|
|
FT_FRAME_SHORT( TT_Header, Glyph_Data_Format ),
|
|
|
|
FT_FRAME_END
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
FT_TRACE2(( "Load_TT_Header: %08p\n", face ));
|
1999-12-17 00:11:37 +01:00
|
|
|
|
|
|
|
error = face->goto_table( face, TTAG_head, stream, 0 );
|
|
|
|
if ( error )
|
|
|
|
{
|
|
|
|
FT_TRACE0(( "Font Header is missing!\n" ));
|
|
|
|
goto Exit;
|
|
|
|
}
|
|
|
|
|
2000-02-13 14:41:56 +01:00
|
|
|
header = &face->header;
|
|
|
|
|
2000-05-29 22:37:41 +02:00
|
|
|
if ( READ_Fields( header_fields, header ) )
|
1999-12-17 00:11:37 +01:00
|
|
|
goto Exit;
|
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
FT_TRACE2(( " Units per EM: %8u\n", header->Units_Per_EM ));
|
|
|
|
FT_TRACE2(( " IndexToLoc: %8d\n", header->Index_To_Loc_Format ));
|
1999-12-17 00:11:37 +01:00
|
|
|
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_MaxProfile* maxProfile = &face->max_profile;
|
2000-05-29 22:37:41 +02:00
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
const FT_Frame_Field maxp_fields[] =
|
|
|
|
{
|
|
|
|
FT_FRAME_START( 32 ),
|
|
|
|
FT_FRAME_ULONG( TT_MaxProfile, version ),
|
|
|
|
FT_FRAME_USHORT( TT_MaxProfile, numGlyphs ),
|
|
|
|
FT_FRAME_USHORT( TT_MaxProfile, maxPoints ),
|
|
|
|
FT_FRAME_USHORT( TT_MaxProfile, maxContours ),
|
|
|
|
FT_FRAME_USHORT( TT_MaxProfile, maxCompositePoints ),
|
|
|
|
FT_FRAME_USHORT( TT_MaxProfile, maxCompositeContours ),
|
|
|
|
FT_FRAME_USHORT( TT_MaxProfile, maxZones ),
|
|
|
|
FT_FRAME_USHORT( TT_MaxProfile, maxTwilightPoints ),
|
|
|
|
FT_FRAME_USHORT( TT_MaxProfile, maxStorage ),
|
|
|
|
FT_FRAME_USHORT( TT_MaxProfile, maxFunctionDefs ),
|
|
|
|
FT_FRAME_USHORT( TT_MaxProfile, maxInstructionDefs ),
|
|
|
|
FT_FRAME_USHORT( TT_MaxProfile, maxStackElements ),
|
|
|
|
FT_FRAME_USHORT( TT_MaxProfile, maxSizeOfInstructions ),
|
|
|
|
FT_FRAME_USHORT( TT_MaxProfile, maxComponentElements ),
|
|
|
|
FT_FRAME_USHORT( TT_MaxProfile, maxComponentDepth ),
|
|
|
|
FT_FRAME_END };
|
|
|
|
|
|
|
|
|
|
|
|
FT_TRACE2(( "Load_TT_MaxProfile: %08p\n", face ));
|
1999-12-17 00:11:37 +01:00
|
|
|
|
|
|
|
error = face->goto_table( face, TTAG_maxp, stream, 0 );
|
2000-06-05 07:26:15 +02:00
|
|
|
if ( error )
|
|
|
|
goto Exit;
|
1999-12-17 00:11:37 +01:00
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
if ( READ_Fields( maxp_fields, maxProfile ) )
|
|
|
|
goto Exit;
|
1999-12-17 00:11:37 +01:00
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
|
|
|
/* XXX: some fonts have maxComponents set to 0; we will */
|
|
|
|
/* then use 16 of them by default. */
|
|
|
|
if ( face->max_components == 0 )
|
|
|
|
face->max_components = 16;
|
|
|
|
|
|
|
|
/* We also increase maxPoints and maxContours in order to support */
|
|
|
|
/* some broken fonts. */
|
|
|
|
face->root.max_points += 8;
|
|
|
|
face->root.max_contours += 4;
|
|
|
|
|
|
|
|
FT_TRACE2(( "MAXP loaded.\n" ));
|
2000-06-05 07:26:15 +02:00
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
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_ULong table_len;
|
|
|
|
TT_Long num_shorts, num_longs, num_shorts_checked;
|
|
|
|
|
|
|
|
TT_LongMetrics** longs;
|
|
|
|
TT_ShortMetrics** shorts;
|
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
FT_TRACE2(( "TT_Load_%s_Metrics: %08p\n",
|
|
|
|
vertical ? "Vertical" : "Horizontal", face ));
|
1999-12-17 00:11:37 +01:00
|
|
|
|
|
|
|
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! */
|
|
|
|
/* */
|
|
|
|
error = face->goto_table( face, TTAG_vmtx, stream, &table_len );
|
|
|
|
if ( error )
|
|
|
|
{
|
2000-06-05 07:26:15 +02:00
|
|
|
/* Set number_Of_VMetrics to 0! */
|
1999-12-17 00:11:37 +01:00
|
|
|
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
|
|
|
|
{
|
|
|
|
error = face->goto_table( face, TTAG_hmtx, stream, &table_len );
|
2000-06-05 07:26:15 +02:00
|
|
|
if ( error )
|
1999-12-17 00:11:37 +01:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* never trust derived values */
|
|
|
|
|
|
|
|
num_shorts = face->max_profile.numGlyphs - num_longs;
|
2000-06-05 07:26:15 +02:00
|
|
|
num_shorts_checked = ( table_len - num_longs * 4L ) / 2;
|
1999-12-17 00:11:37 +01:00
|
|
|
|
|
|
|
if ( num_shorts < 0 )
|
|
|
|
{
|
|
|
|
FT_ERROR(( "!! more metrics than glyphs!\n" ));
|
2000-06-05 07:26:15 +02:00
|
|
|
|
|
|
|
error = vertical ? TT_Err_Invalid_Vert_Metrics
|
|
|
|
: TT_Err_Invalid_Horiz_Metrics;
|
1999-12-17 00:11:37 +01:00
|
|
|
goto Exit;
|
|
|
|
}
|
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
if ( ALLOC_ARRAY( *longs, num_longs, TT_LongMetrics ) ||
|
1999-12-17 00:11:37 +01:00
|
|
|
ALLOC_ARRAY( *shorts, num_shorts, TT_ShortMetrics ) )
|
|
|
|
goto Exit;
|
|
|
|
|
|
|
|
if ( ACCESS_Frame( table_len ) )
|
|
|
|
goto Exit;
|
|
|
|
|
|
|
|
{
|
|
|
|
TT_LongMetrics* cur = *longs;
|
|
|
|
TT_LongMetrics* limit = cur + num_longs;
|
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
for ( ; cur < limit; cur++ )
|
|
|
|
{
|
|
|
|
cur->advance = GET_UShort();
|
|
|
|
cur->bearing = GET_Short();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
/* do we have an inconsistent number of metric values? */
|
1999-12-17 00:11:37 +01:00
|
|
|
{
|
|
|
|
TT_ShortMetrics* cur = *shorts;
|
|
|
|
TT_ShortMetrics* limit = cur + MIN( num_shorts, num_shorts_checked );
|
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
for ( ; cur < limit; cur++ )
|
|
|
|
*cur = GET_Short();
|
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
/* we fill up the missing left side bearings with the */
|
|
|
|
/* last valid value. Since this will occur for buggy CJK */
|
|
|
|
/* fonts usually only, nothing serious will happen */
|
1999-12-17 00:11:37 +01:00
|
|
|
if ( num_shorts > num_shorts_checked && num_shorts_checked > 0 )
|
|
|
|
{
|
2000-06-05 07:26:15 +02:00
|
|
|
TT_Short val = *(shorts)[num_shorts_checked - 1];
|
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
|
|
|
|
limit = *shorts + num_shorts;
|
|
|
|
for ( ; cur < limit; cur++ )
|
|
|
|
*cur = val;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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_HoriHeader* header;
|
2000-05-29 22:37:41 +02:00
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
const FT_Frame_Field metrics_header_fields[] =
|
|
|
|
{
|
|
|
|
FT_FRAME_START( 36 ),
|
|
|
|
FT_FRAME_ULONG( TT_HoriHeader, Version ),
|
|
|
|
FT_FRAME_SHORT( TT_HoriHeader, Ascender ),
|
|
|
|
FT_FRAME_SHORT( TT_HoriHeader, Descender ),
|
|
|
|
FT_FRAME_SHORT( TT_HoriHeader, Line_Gap ),
|
|
|
|
FT_FRAME_USHORT( TT_HoriHeader, advance_Width_Max ),
|
|
|
|
FT_FRAME_SHORT( TT_HoriHeader, min_Left_Side_Bearing ),
|
|
|
|
FT_FRAME_SHORT( TT_HoriHeader, min_Right_Side_Bearing ),
|
|
|
|
FT_FRAME_SHORT( TT_HoriHeader, xMax_Extent ),
|
|
|
|
FT_FRAME_SHORT( TT_HoriHeader, caret_Slope_Rise ),
|
|
|
|
FT_FRAME_SHORT( TT_HoriHeader, caret_Slope_Run ),
|
|
|
|
FT_FRAME_SHORT( TT_HoriHeader, Reserved[0] ),
|
|
|
|
FT_FRAME_SHORT( TT_HoriHeader, Reserved[1] ),
|
|
|
|
FT_FRAME_SHORT( TT_HoriHeader, Reserved[2] ),
|
|
|
|
FT_FRAME_SHORT( TT_HoriHeader, Reserved[3] ),
|
|
|
|
FT_FRAME_SHORT( TT_HoriHeader, Reserved[4] ),
|
|
|
|
FT_FRAME_SHORT( TT_HoriHeader, metric_Data_Format ),
|
|
|
|
FT_FRAME_USHORT( TT_HoriHeader, number_Of_HMetrics ),
|
|
|
|
FT_FRAME_END
|
|
|
|
};
|
|
|
|
|
2000-05-29 22:37:41 +02:00
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
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. */
|
|
|
|
error = face->goto_table( face, TTAG_vhea, stream, 0 );
|
2000-06-05 07:26:15 +02:00
|
|
|
if ( error )
|
1999-12-17 00:11:37 +01:00
|
|
|
{
|
|
|
|
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. */
|
|
|
|
error = face->goto_table( face, TTAG_hhea, stream, 0 );
|
2000-06-05 07:26:15 +02:00
|
|
|
if ( error )
|
1999-12-17 00:11:37 +01:00
|
|
|
{
|
|
|
|
error = TT_Err_Horiz_Header_Missing;
|
|
|
|
goto Exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
header = &face->horizontal;
|
|
|
|
}
|
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
if ( READ_Fields( metrics_header_fields, header ) )
|
|
|
|
goto Exit;
|
1999-12-17 00:11:37 +01:00
|
|
|
|
|
|
|
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 );
|
2000-06-05 07:26:15 +02:00
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
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
|
2000-06-05 07:26:15 +02:00
|
|
|
TT_Error TT_Load_Names( TT_Face face,
|
|
|
|
FT_Stream stream )
|
1999-12-17 00:11:37 +01:00
|
|
|
{
|
|
|
|
TT_Error error;
|
|
|
|
FT_Memory memory = stream->memory;
|
|
|
|
|
|
|
|
TT_ULong table_pos, table_len;
|
|
|
|
TT_ULong storageSize;
|
|
|
|
|
|
|
|
TT_NameTable* names;
|
2000-05-29 22:37:41 +02:00
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
const FT_Frame_Field name_table_fields[] =
|
|
|
|
{
|
|
|
|
FT_FRAME_START( 6 ),
|
|
|
|
FT_FRAME_USHORT( TT_NameTable, format ),
|
|
|
|
FT_FRAME_USHORT( TT_NameTable, numNameRecords ),
|
|
|
|
FT_FRAME_USHORT( TT_NameTable, storageOffset ),
|
|
|
|
FT_FRAME_END
|
|
|
|
};
|
|
|
|
|
|
|
|
const FT_Frame_Field name_record_fields[] =
|
|
|
|
{
|
|
|
|
/* no FT_FRAME_START */
|
|
|
|
FT_FRAME_USHORT( TT_NameRec, platformID ),
|
|
|
|
FT_FRAME_USHORT( TT_NameRec, encodingID ),
|
|
|
|
FT_FRAME_USHORT( TT_NameRec, languageID ),
|
|
|
|
FT_FRAME_USHORT( TT_NameRec, nameID ),
|
|
|
|
FT_FRAME_USHORT( TT_NameRec, stringLength ),
|
|
|
|
FT_FRAME_USHORT( TT_NameRec, stringOffset ),
|
|
|
|
FT_FRAME_END
|
|
|
|
};
|
1999-12-17 00:11:37 +01:00
|
|
|
|
|
|
|
|
|
|
|
FT_TRACE2(( "Names " ));
|
|
|
|
|
|
|
|
error = face->goto_table( face, TTAG_name, stream, &table_len );
|
2000-06-05 07:26:15 +02:00
|
|
|
if ( error )
|
1999-12-17 00:11:37 +01:00
|
|
|
{
|
|
|
|
/* The name table is required so indicate failure. */
|
|
|
|
FT_TRACE2(( "is missing!\n" ));
|
|
|
|
error = TT_Err_Name_Table_Missing;
|
|
|
|
goto Exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
table_pos = FILE_Pos();
|
|
|
|
|
2000-02-13 14:41:56 +01:00
|
|
|
names = &face->name_table;
|
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
if ( READ_Fields( name_table_fields, names ) )
|
|
|
|
goto Exit;
|
1999-12-17 00:11:37 +01:00
|
|
|
|
|
|
|
/* 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. */
|
|
|
|
{
|
2000-06-05 07:26:15 +02:00
|
|
|
TT_NameRec* cur = names->names;
|
|
|
|
TT_NameRec* limit = cur + names->numNameRecords;
|
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
|
|
|
|
storageSize = 0;
|
|
|
|
|
|
|
|
for ( ; cur < limit; cur ++ )
|
|
|
|
{
|
|
|
|
TT_ULong upper;
|
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
|
2000-02-13 14:41:56 +01:00
|
|
|
(void)READ_Fields( name_record_fields, cur );
|
2000-05-29 22:37:41 +02:00
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
upper = (TT_ULong)( cur->stringOffset + cur->stringLength );
|
|
|
|
if ( upper > storageSize )
|
|
|
|
storageSize = upper;
|
1999-12-17 00:11:37 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
FORGET_Frame();
|
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
if ( storageSize > 0 )
|
1999-12-17 00:11:37 +01:00
|
|
|
{
|
|
|
|
/* allocate the name storage area in memory, then read it */
|
2000-06-05 07:26:15 +02:00
|
|
|
if ( ALLOC( names->storage, storageSize ) ||
|
1999-12-17 00:11:37 +01:00
|
|
|
FILE_Read_At( table_pos + names->storageOffset,
|
|
|
|
(void*)names->storage, storageSize ) )
|
|
|
|
goto Exit;
|
2000-05-17 01:44:38 +02:00
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
/* Go through and assign the string pointers to the name records. */
|
|
|
|
{
|
|
|
|
TT_NameRec* cur = names->names;
|
|
|
|
TT_NameRec* limit = cur + names->numNameRecords;
|
2000-05-17 01:44:38 +02:00
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
for ( ; cur < limit; cur++ )
|
|
|
|
cur->string = names->storage + cur->stringOffset;
|
|
|
|
}
|
|
|
|
|
2000-05-17 01:44:38 +02:00
|
|
|
#ifdef FT_DEBUG_LEVEL_TRACE
|
2000-06-05 07:26:15 +02:00
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
/* Print Name Record Table in case of debugging */
|
|
|
|
{
|
|
|
|
TT_NameRec* cur = names->names;
|
|
|
|
TT_NameRec* limit = cur + names->numNameRecords;
|
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
for ( ; cur < limit; cur++ )
|
|
|
|
{
|
|
|
|
TT_UInt j;
|
2000-05-17 01:44:38 +02:00
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
|
|
|
|
FT_TRACE3(( "%d %d %x %d\n ",
|
1999-12-17 00:11:37 +01:00
|
|
|
cur->platformID,
|
|
|
|
cur->encodingID,
|
|
|
|
cur->languageID,
|
|
|
|
cur->nameID ));
|
2000-05-17 01:44:38 +02:00
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
/* I know that M$ encoded strings are Unicode, */
|
|
|
|
/* but this works reasonable well for debugging purposes. */
|
|
|
|
if ( cur->string )
|
|
|
|
for ( j = 0; j < cur->stringLength; j++ )
|
|
|
|
{
|
|
|
|
TT_Char c = *(cur->string + j);
|
2000-05-17 01:44:38 +02:00
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
if ( (TT_Byte)c < 128 )
|
2000-06-05 07:26:15 +02:00
|
|
|
FT_TRACE3(( "%c", c ));
|
1999-12-17 00:11:37 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2000-06-05 07:26:15 +02:00
|
|
|
FT_TRACE3(( "\n" ));
|
|
|
|
|
|
|
|
#endif /* FT_DEBUG_LEVEL_TRACE */
|
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
}
|
|
|
|
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. */
|
|
|
|
/* */
|
|
|
|
LOCAL_FUNC
|
|
|
|
void 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*************************************************************************/
|
|
|
|
/* */
|
|
|
|
/* <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> */
|
2000-06-05 07:26:15 +02:00
|
|
|
/* face :: A handle to the target face object. */
|
|
|
|
/* stream :: A handle to the input stream. */
|
1999-12-17 00:11:37 +01:00
|
|
|
/* */
|
|
|
|
/* <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;
|
2000-02-13 14:41:56 +01:00
|
|
|
TT_Long table_start;
|
1999-12-17 00:11:37 +01:00
|
|
|
TT_CMapDir cmap_dir;
|
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
const FT_Frame_Field cmap_fields[] =
|
|
|
|
{
|
|
|
|
FT_FRAME_START( 4 ),
|
|
|
|
FT_FRAME_USHORT( TT_CMapDir, tableVersionNumber ),
|
|
|
|
FT_FRAME_USHORT( TT_CMapDir, numCMaps ),
|
|
|
|
FT_FRAME_END
|
|
|
|
};
|
|
|
|
|
|
|
|
const FT_Frame_Field cmap_rec_fields[] =
|
|
|
|
{
|
|
|
|
FT_FRAME_START( 6 ),
|
|
|
|
FT_FRAME_USHORT( TT_CMapTable, format ),
|
|
|
|
FT_FRAME_USHORT( TT_CMapTable, length ),
|
|
|
|
FT_FRAME_USHORT( TT_CMapTable, version ),
|
|
|
|
FT_FRAME_END
|
|
|
|
};
|
2000-02-13 14:41:56 +01:00
|
|
|
|
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
FT_TRACE2(( "CMaps " ));
|
|
|
|
|
|
|
|
error = face->goto_table( face, TTAG_cmap, stream, 0 );
|
2000-06-05 07:26:15 +02:00
|
|
|
if ( error )
|
1999-12-17 00:11:37 +01:00
|
|
|
{
|
|
|
|
error = TT_Err_CMap_Table_Missing;
|
|
|
|
goto Exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
table_start = FILE_Pos();
|
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
if ( READ_Fields( cmap_fields, &cmap_dir ) )
|
|
|
|
goto Exit;
|
1999-12-17 00:11:37 +01:00
|
|
|
|
|
|
|
/* 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;
|
|
|
|
{
|
|
|
|
TT_CharMap charmap = face->charmaps;
|
|
|
|
TT_CharMap limit = charmap + face->num_charmaps;
|
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
|
2000-02-13 14:41:56 +01:00
|
|
|
/* read the header of each charmap first */
|
2000-06-05 07:26:15 +02:00
|
|
|
if ( ACCESS_Frame( face->num_charmaps * 8L ) )
|
|
|
|
goto Exit;
|
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
for ( ; charmap < limit; charmap++ )
|
|
|
|
{
|
|
|
|
TT_CMapTable* cmap;
|
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
charmap->root.face = (FT_Face)face;
|
|
|
|
cmap = &charmap->cmap;
|
|
|
|
|
|
|
|
cmap->loaded = FALSE;
|
|
|
|
cmap->platformID = GET_UShort();
|
|
|
|
cmap->platformEncodingID = GET_UShort();
|
2000-02-13 14:41:56 +01:00
|
|
|
cmap->offset = (TT_ULong)GET_Long();
|
|
|
|
}
|
2000-06-05 07:26:15 +02:00
|
|
|
|
2000-02-13 14:41:56 +01:00
|
|
|
FORGET_Frame();
|
2000-05-17 01:44:38 +02:00
|
|
|
|
2000-02-13 14:41:56 +01:00
|
|
|
/* now read the rest of each table */
|
|
|
|
for ( charmap = face->charmaps; charmap < limit; charmap++ )
|
|
|
|
{
|
|
|
|
TT_CMapTable* cmap = &charmap->cmap;
|
2000-05-17 01:44:38 +02:00
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
|
2000-02-13 14:41:56 +01:00
|
|
|
if ( FILE_Seek( table_start + (TT_Long)cmap->offset ) ||
|
|
|
|
READ_Fields( cmap_rec_fields, cmap ) )
|
1999-12-17 00:11:37 +01:00
|
|
|
goto Exit;
|
2000-05-17 01:44:38 +02:00
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
cmap->offset = FILE_Pos();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
FT_TRACE2(( "loaded\n" ));
|
2000-06-05 07:26:15 +02:00
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
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_OS2* os2;
|
2000-05-29 22:37:41 +02:00
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
const FT_Frame_Field os2_fields[] =
|
|
|
|
{
|
|
|
|
FT_FRAME_START( 78 ),
|
|
|
|
FT_FRAME_USHORT( TT_OS2, version ),
|
|
|
|
FT_FRAME_SHORT( TT_OS2, xAvgCharWidth ),
|
|
|
|
FT_FRAME_USHORT( TT_OS2, usWeightClass ),
|
|
|
|
FT_FRAME_USHORT( TT_OS2, usWidthClass ),
|
|
|
|
FT_FRAME_SHORT( TT_OS2, fsType ),
|
|
|
|
FT_FRAME_SHORT( TT_OS2, ySubscriptXSize ),
|
|
|
|
FT_FRAME_SHORT( TT_OS2, ySubscriptYSize ),
|
|
|
|
FT_FRAME_SHORT( TT_OS2, ySubscriptXOffset ),
|
|
|
|
FT_FRAME_SHORT( TT_OS2, ySubscriptYOffset ),
|
|
|
|
FT_FRAME_SHORT( TT_OS2, ySuperscriptXSize ),
|
|
|
|
FT_FRAME_SHORT( TT_OS2, ySuperscriptYSize ),
|
|
|
|
FT_FRAME_SHORT( TT_OS2, ySuperscriptXOffset ),
|
|
|
|
FT_FRAME_SHORT( TT_OS2, ySuperscriptYOffset ),
|
|
|
|
FT_FRAME_SHORT( TT_OS2, yStrikeoutSize ),
|
|
|
|
FT_FRAME_SHORT( TT_OS2, yStrikeoutPosition ),
|
|
|
|
FT_FRAME_SHORT( TT_OS2, sFamilyClass ),
|
|
|
|
FT_FRAME_BYTE( TT_OS2, panose[0] ),
|
|
|
|
FT_FRAME_BYTE( TT_OS2, panose[1] ),
|
|
|
|
FT_FRAME_BYTE( TT_OS2, panose[2] ),
|
|
|
|
FT_FRAME_BYTE( TT_OS2, panose[3] ),
|
|
|
|
FT_FRAME_BYTE( TT_OS2, panose[4] ),
|
|
|
|
FT_FRAME_BYTE( TT_OS2, panose[5] ),
|
|
|
|
FT_FRAME_BYTE( TT_OS2, panose[6] ),
|
|
|
|
FT_FRAME_BYTE( TT_OS2, panose[7] ),
|
|
|
|
FT_FRAME_BYTE( TT_OS2, panose[8] ),
|
|
|
|
FT_FRAME_BYTE( TT_OS2, panose[9] ),
|
|
|
|
FT_FRAME_ULONG( TT_OS2, ulUnicodeRange1 ),
|
|
|
|
FT_FRAME_ULONG( TT_OS2, ulUnicodeRange2 ),
|
|
|
|
FT_FRAME_ULONG( TT_OS2, ulUnicodeRange3 ),
|
|
|
|
FT_FRAME_ULONG( TT_OS2, ulUnicodeRange4 ),
|
|
|
|
FT_FRAME_BYTE( TT_OS2, achVendID[0] ),
|
|
|
|
FT_FRAME_BYTE( TT_OS2, achVendID[1] ),
|
|
|
|
FT_FRAME_BYTE( TT_OS2, achVendID[2] ),
|
|
|
|
FT_FRAME_BYTE( TT_OS2, achVendID[3] ),
|
|
|
|
|
|
|
|
FT_FRAME_USHORT( TT_OS2, fsSelection ),
|
|
|
|
FT_FRAME_USHORT( TT_OS2, usFirstCharIndex ),
|
|
|
|
FT_FRAME_USHORT( TT_OS2, usLastCharIndex ),
|
|
|
|
FT_FRAME_SHORT( TT_OS2, sTypoAscender ),
|
|
|
|
FT_FRAME_SHORT( TT_OS2, sTypoDescender ),
|
|
|
|
FT_FRAME_SHORT( TT_OS2, sTypoLineGap ),
|
|
|
|
FT_FRAME_USHORT( TT_OS2, usWinAscent ),
|
|
|
|
FT_FRAME_USHORT( TT_OS2, usWinDescent ),
|
|
|
|
FT_FRAME_END
|
|
|
|
};
|
|
|
|
|
|
|
|
const FT_Frame_Field os2_fields_extra[] =
|
|
|
|
{
|
|
|
|
FT_FRAME_START( 8 ),
|
|
|
|
FT_FRAME_ULONG( TT_OS2, ulCodePageRange1 ),
|
|
|
|
FT_FRAME_ULONG( TT_OS2, ulCodePageRange2 ),
|
|
|
|
FT_FRAME_END
|
|
|
|
};
|
|
|
|
|
|
|
|
const FT_Frame_Field os2_fields_extra2[] =
|
|
|
|
{
|
|
|
|
FT_FRAME_START( 10 ),
|
|
|
|
FT_FRAME_SHORT( TT_OS2, sxHeight ),
|
|
|
|
FT_FRAME_SHORT( TT_OS2, sCapHeight ),
|
|
|
|
FT_FRAME_USHORT( TT_OS2, usDefaultChar ),
|
|
|
|
FT_FRAME_USHORT( TT_OS2, usBreakChar ),
|
|
|
|
FT_FRAME_USHORT( TT_OS2, usMaxContext ),
|
|
|
|
FT_FRAME_END
|
|
|
|
};
|
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
|
|
|
|
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. */
|
|
|
|
error = face->goto_table( face, TTAG_OS2, stream, 0 );
|
2000-06-05 07:26:15 +02:00
|
|
|
if ( error )
|
1999-12-17 00:11:37 +01:00
|
|
|
{
|
|
|
|
FT_TRACE2(( "is missing\n!" ));
|
|
|
|
face->os2.version = 0xFFFF;
|
|
|
|
error = TT_Err_Ok;
|
|
|
|
goto Exit;
|
|
|
|
}
|
|
|
|
|
2000-02-13 14:41:56 +01:00
|
|
|
os2 = &face->os2;
|
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
if ( READ_Fields( os2_fields, os2 ) )
|
|
|
|
goto Exit;
|
1999-12-17 00:11:37 +01:00
|
|
|
|
|
|
|
os2->ulCodePageRange1 = 0;
|
|
|
|
os2->ulCodePageRange2 = 0;
|
|
|
|
|
|
|
|
if ( os2->version >= 0x0001 )
|
|
|
|
{
|
|
|
|
/* only version 1 tables */
|
2000-06-05 07:26:15 +02:00
|
|
|
if ( READ_Fields( os2_fields_extra, os2 ) )
|
|
|
|
goto Exit;
|
2000-05-02 13:01:49 +02:00
|
|
|
|
|
|
|
if ( os2->version >= 0x0002 )
|
|
|
|
{
|
|
|
|
/* only version 2 tables */
|
2000-06-05 07:26:15 +02:00
|
|
|
if ( READ_Fields( os2_fields_extra2, os2 ) )
|
|
|
|
goto Exit;
|
2000-05-02 13:01:49 +02:00
|
|
|
}
|
1999-12-17 00:11:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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_Postscript* post = &face->postscript;
|
2000-05-29 22:37:41 +02:00
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
static const FT_Frame_Field post_fields[] =
|
|
|
|
{
|
|
|
|
FT_FRAME_START( 32 ),
|
|
|
|
FT_FRAME_ULONG( TT_Postscript, FormatType ),
|
|
|
|
FT_FRAME_ULONG( TT_Postscript, italicAngle ),
|
|
|
|
FT_FRAME_SHORT( TT_Postscript, underlinePosition ),
|
|
|
|
FT_FRAME_SHORT( TT_Postscript, underlineThickness ),
|
|
|
|
FT_FRAME_ULONG( TT_Postscript, isFixedPitch ),
|
|
|
|
FT_FRAME_ULONG( TT_Postscript, minMemType42 ),
|
|
|
|
FT_FRAME_ULONG( TT_Postscript, maxMemType42 ),
|
|
|
|
FT_FRAME_ULONG( TT_Postscript, minMemType1 ),
|
|
|
|
FT_FRAME_ULONG( TT_Postscript, maxMemType1 ),
|
|
|
|
FT_FRAME_END
|
|
|
|
};
|
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
|
|
|
|
FT_TRACE2(( "PostScript " ));
|
|
|
|
|
|
|
|
error = face->goto_table( face, TTAG_post, stream, 0 );
|
2000-06-05 07:26:15 +02:00
|
|
|
if ( error )
|
1999-12-17 00:11:37 +01:00
|
|
|
return TT_Err_Post_Table_Missing;
|
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
if ( READ_Fields( post_fields, post ) )
|
|
|
|
return error;
|
1999-12-17 00:11:37 +01:00
|
|
|
|
|
|
|
/* we don't load the glyph names, we do that in another */
|
|
|
|
/* module (ttpost). */
|
|
|
|
FT_TRACE2(( "loaded\n" ));
|
|
|
|
|
|
|
|
return TT_Err_Ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-05-18 18:18:05 +02:00
|
|
|
/*************************************************************************/
|
|
|
|
/* */
|
|
|
|
/* <Function> */
|
|
|
|
/* TT_Load_PCLT */
|
|
|
|
/* */
|
|
|
|
/* <Description> */
|
|
|
|
/* Loads the PCL 5 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_PCLT( TT_Face face,
|
|
|
|
FT_Stream stream )
|
|
|
|
{
|
2000-06-05 07:26:15 +02:00
|
|
|
static const FT_Frame_Field pclt_fields[] =
|
|
|
|
{
|
|
|
|
FT_FRAME_START( 20 ),
|
|
|
|
FT_FRAME_ULONG ( TT_PCLT, Version ),
|
|
|
|
FT_FRAME_ULONG ( TT_PCLT, FontNumber ),
|
|
|
|
FT_FRAME_USHORT( TT_PCLT, Pitch ),
|
|
|
|
FT_FRAME_USHORT( TT_PCLT, xHeight ),
|
|
|
|
FT_FRAME_USHORT( TT_PCLT, Style ),
|
|
|
|
FT_FRAME_USHORT( TT_PCLT, TypeFamily ),
|
|
|
|
FT_FRAME_USHORT( TT_PCLT, CapHeight ),
|
|
|
|
FT_FRAME_END
|
|
|
|
};
|
2000-05-18 18:18:05 +02:00
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
static const FT_Frame_Field pclt_fields2[] =
|
|
|
|
{
|
|
|
|
FT_FRAME_START( 4 ),
|
|
|
|
FT_FRAME_CHAR( TT_PCLT, StrokeWeight ),
|
|
|
|
FT_FRAME_CHAR( TT_PCLT, WidthType ),
|
|
|
|
FT_FRAME_BYTE( TT_PCLT, SerifStyle ),
|
|
|
|
FT_FRAME_BYTE( TT_PCLT, Reserved ),
|
|
|
|
FT_FRAME_END
|
|
|
|
};
|
2000-05-18 18:18:05 +02:00
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
TT_Error error;
|
|
|
|
TT_PCLT* pclt = &face->pclt;
|
|
|
|
|
|
|
|
|
2000-05-18 18:18:05 +02:00
|
|
|
FT_TRACE2(( "PCLT " ));
|
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
/* optional table */
|
|
|
|
error = face->goto_table( face, TTAG_PCLT, stream, 0 );
|
|
|
|
if ( error )
|
|
|
|
{
|
|
|
|
FT_TRACE2(( "missing (optional)\n" ));
|
|
|
|
pclt->Version = 0;
|
|
|
|
return TT_Err_Ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( READ_Fields( pclt_fields, pclt ) ||
|
|
|
|
FILE_Read ( pclt->TypeFace, 16 ) ||
|
|
|
|
FILE_Read ( pclt->CharacterComplement, 8 ) ||
|
|
|
|
FILE_Read ( pclt->FileName, 6 ) ||
|
|
|
|
READ_Fields( pclt_fields2, pclt ) )
|
2000-05-18 18:18:05 +02:00
|
|
|
goto Exit;
|
2000-06-05 07:26:15 +02:00
|
|
|
|
|
|
|
FT_TRACE2(( "loaded\n" ));
|
|
|
|
|
|
|
|
Exit:
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2000-05-18 18:18:05 +02:00
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
/*************************************************************************/
|
|
|
|
/* */
|
|
|
|
/* <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_UInt j,num_ranges;
|
|
|
|
TT_GaspRange* gaspranges;
|
|
|
|
|
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
FT_TRACE2(( "TT_Load_Gasp: %08p\n", face ));
|
1999-12-17 00:11:37 +01:00
|
|
|
|
|
|
|
/* the gasp table is optional */
|
|
|
|
error = face->goto_table( face, TTAG_gasp, stream, 0 );
|
2000-06-05 07:26:15 +02:00
|
|
|
if ( error )
|
|
|
|
return TT_Err_Ok;
|
1999-12-17 00:11:37 +01:00
|
|
|
|
|
|
|
if ( 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 ) ||
|
2000-06-05 07:26:15 +02:00
|
|
|
ACCESS_Frame( num_ranges * 4L ) )
|
1999-12-17 00:11:37 +01:00
|
|
|
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]",
|
2000-06-05 07:26:15 +02:00
|
|
|
gaspranges[j].maxPPEM,
|
|
|
|
gaspranges[j].gaspFlag ));
|
1999-12-17 00:11:37 +01:00
|
|
|
}
|
|
|
|
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_UInt n, num_tables, version;
|
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
|
|
|
|
/* the kern table is optional. exit silently if it is missing */
|
1999-12-17 00:11:37 +01:00
|
|
|
error = face->goto_table( face, TTAG_kern, stream, 0 );
|
2000-06-05 07:26:15 +02:00
|
|
|
if ( error )
|
|
|
|
return TT_Err_Ok;
|
1999-12-17 00:11:37 +01:00
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
if ( ACCESS_Frame( 4L ) )
|
|
|
|
goto Exit;
|
1999-12-17 00:11:37 +01:00
|
|
|
|
|
|
|
version = GET_UShort();
|
|
|
|
num_tables = GET_UShort();
|
|
|
|
|
|
|
|
FORGET_Frame();
|
|
|
|
|
|
|
|
for ( n = 0; n < num_tables; n++ )
|
|
|
|
{
|
|
|
|
TT_UInt coverage;
|
|
|
|
TT_UInt length;
|
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
|
|
|
|
if ( ACCESS_Frame( 6L ) )
|
|
|
|
goto Exit;
|
1999-12-17 00:11:37 +01:00
|
|
|
|
|
|
|
version = GET_UShort(); /* version */
|
|
|
|
length = GET_UShort() - 6; /* substract header length */
|
|
|
|
coverage = GET_UShort();
|
|
|
|
|
|
|
|
FORGET_Frame();
|
2000-05-17 01:44:38 +02:00
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
if ( coverage == 0x0001 )
|
|
|
|
{
|
|
|
|
TT_UInt num_pairs;
|
|
|
|
TT_Kern_0_Pair* pair;
|
|
|
|
TT_Kern_0_Pair* limit;
|
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
|
|
|
|
/* found a horizontal format 0 kerning table! */
|
|
|
|
if ( ACCESS_Frame( 8L ) )
|
1999-12-17 00:11:37 +01:00
|
|
|
goto Exit;
|
|
|
|
|
|
|
|
num_pairs = GET_UShort();
|
2000-06-05 07:26:15 +02:00
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
/* skip the rest */
|
|
|
|
|
|
|
|
FORGET_Frame();
|
|
|
|
|
|
|
|
/* allocate array of kerning pairs */
|
|
|
|
if ( ALLOC_ARRAY( face->kern_pairs, num_pairs, TT_Kern_0_Pair ) ||
|
|
|
|
ACCESS_Frame( 6L * num_pairs ) )
|
|
|
|
goto Exit;
|
|
|
|
|
|
|
|
pair = face->kern_pairs;
|
|
|
|
limit = pair + num_pairs;
|
|
|
|
for ( ; pair < limit; pair++ )
|
|
|
|
{
|
|
|
|
pair->left = GET_UShort();
|
|
|
|
pair->right = GET_UShort();
|
|
|
|
pair->value = GET_UShort();
|
|
|
|
}
|
|
|
|
|
|
|
|
FORGET_Frame();
|
|
|
|
|
|
|
|
face->num_kern_pairs = num_pairs;
|
|
|
|
face->kern_table_index = n;
|
|
|
|
goto Exit;
|
|
|
|
}
|
2000-05-17 01:44:38 +02:00
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
if ( FILE_Skip( length ) )
|
|
|
|
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
|
2000-05-17 01:44:38 +02:00
|
|
|
TT_Error TT_Load_Hdmx( TT_Face face,
|
1999-12-17 00:11:37 +01:00
|
|
|
FT_Stream stream )
|
|
|
|
{
|
|
|
|
TT_Error error;
|
|
|
|
FT_Memory memory = stream->memory;
|
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
TT_Hdmx* hdmx = &face->hdmx;
|
|
|
|
TT_Long num_glyphs;
|
|
|
|
TT_Long record_size;
|
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
|
|
|
|
hdmx->version = 0;
|
|
|
|
hdmx->num_records = 0;
|
|
|
|
hdmx->records = 0;
|
|
|
|
|
|
|
|
/* this table is optional */
|
|
|
|
error = face->goto_table( face, TTAG_hdmx, stream, 0 );
|
2000-06-05 07:26:15 +02:00
|
|
|
if ( error )
|
|
|
|
return TT_Err_Ok;
|
1999-12-17 00:11:37 +01:00
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
if ( ACCESS_Frame( 8L ) )
|
|
|
|
goto Exit;
|
1999-12-17 00:11:37 +01:00
|
|
|
|
|
|
|
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_ARRAY( hdmx->records, hdmx->num_records, TT_HdmxRec ) )
|
|
|
|
goto Exit;
|
|
|
|
|
|
|
|
num_glyphs = face->root.num_glyphs;
|
|
|
|
record_size -= num_glyphs + 2;
|
|
|
|
|
|
|
|
{
|
|
|
|
TT_HdmxRec* cur = hdmx->records;
|
|
|
|
TT_HdmxRec* limit = cur + hdmx->num_records;
|
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
for ( ; cur < limit; cur++ )
|
|
|
|
{
|
|
|
|
/* read record */
|
|
|
|
if ( READ_Byte( cur->ppem ) ||
|
|
|
|
READ_Byte( cur->max_width ) )
|
|
|
|
goto Exit;
|
2000-05-17 01:44:38 +02:00
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
if ( ALLOC( cur->widths, num_glyphs ) ||
|
1999-12-17 00:11:37 +01:00
|
|
|
FILE_Read( cur->widths, num_glyphs ) )
|
|
|
|
goto Exit;
|
2000-05-17 01:44:38 +02:00
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
/* skip padding bytes */
|
2000-06-05 07:26:15 +02:00
|
|
|
if ( record_size > 0 && FILE_Skip( record_size ) )
|
1999-12-17 00:11:37 +01:00
|
|
|
goto Exit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Exit:
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*************************************************************************/
|
|
|
|
/* */
|
|
|
|
/* <Function> */
|
|
|
|
/* TT_Free_Hdmx */
|
|
|
|
/* */
|
|
|
|
/* <Description> */
|
|
|
|
/* Frees the horizontal device metrics table. */
|
|
|
|
/* */
|
|
|
|
/* <Input> */
|
|
|
|
/* face :: A handle to the target face object. */
|
|
|
|
/* */
|
|
|
|
LOCAL_FUNC
|
|
|
|
void TT_Free_Hdmx( TT_Face face )
|
|
|
|
{
|
|
|
|
if ( face )
|
|
|
|
{
|
|
|
|
TT_Int n;
|
|
|
|
FT_Memory memory = face->root.driver->memory;
|
|
|
|
|
2000-06-05 07:26:15 +02:00
|
|
|
|
1999-12-17 00:11:37 +01:00
|
|
|
for ( n = 0; n < face->hdmx.num_records; n++ )
|
|
|
|
FREE( face->hdmx.records[n].widths );
|
|
|
|
|
|
|
|
FREE( face->hdmx.records );
|
|
|
|
face->hdmx.num_records = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* END */
|