blob: 8e6995c4b0d8f68f1ccb7c6d182d68b01d00ac96 [file] [log] [blame]
David Turnerd2b1f351999-12-16 23:11:37 +00001/***************************************************************************/
2/* */
3/* ttload.c */
4/* */
Werner Lemberg4e6dd852000-06-05 05:26:15 +00005/* Load the basic TrueType tables, i.e., tables that can be either in */
6/* TTF or OTF fonts (body). */
David Turnerd2b1f351999-12-16 23:11:37 +00007/* */
Werner Lemberg415235d2001-06-28 17:49:10 +00008/* Copyright 1996-2001 by */
David Turnerd2b1f351999-12-16 23:11:37 +00009/* David Turner, Robert Wilhelm, and Werner Lemberg. */
10/* */
Werner Lemberg4e6dd852000-06-05 05:26:15 +000011/* This file is part of the FreeType project, and may only be used, */
12/* modified, and distributed under the terms of the FreeType project */
David Turnerd2b1f351999-12-16 23:11:37 +000013/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
14/* this file you indicate that you have read the license and */
15/* understand and accept it fully. */
16/* */
David Turnerd2b1f351999-12-16 23:11:37 +000017/***************************************************************************/
18
Werner Lembergcc069be2000-12-08 16:17:16 +000019
David Turner19ed8af2000-12-08 02:42:29 +000020#include <ft2build.h>
21#include FT_INTERNAL_DEBUG_H
David Turner19ed8af2000-12-08 02:42:29 +000022#include FT_INTERNAL_STREAM_H
23#include FT_TRUETYPE_TAGS_H
David Turner8d3a4012001-03-20 11:14:24 +000024#include "ttload.h"
25#include "ttcmap.h"
David Turnera90663f2000-07-08 00:41:13 +000026
Werner Lemberg1f7f0e82001-06-06 17:30:41 +000027#include "sferrors.h"
28
David Turner9a554eb2001-06-27 12:40:46 +000029#include <stdlib.h> /* for qsort */
Werner Lembergcc069be2000-12-08 16:17:16 +000030
Werner Lemberg4e6dd852000-06-05 05:26:15 +000031 /*************************************************************************/
32 /* */
33 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
34 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
35 /* messages during execution. */
36 /* */
37#undef FT_COMPONENT
38#define FT_COMPONENT trace_ttload
David Turnera56489e2000-02-13 13:41:56 +000039
David Turnerd2b1f351999-12-16 23:11:37 +000040
41 /*************************************************************************/
42 /* */
43 /* <Function> */
44 /* TT_LookUp_Table */
45 /* */
46 /* <Description> */
47 /* Looks for a TrueType table by name. */
48 /* */
49 /* <Input> */
50 /* face :: A face object handle. */
Werner Lemberg4e6dd852000-06-05 05:26:15 +000051 /* tag :: The searched tag. */
David Turnerd2b1f351999-12-16 23:11:37 +000052 /* */
53 /* <Return> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +000054 /* A pointer to the table directory entry. 0 if not found. */
David Turnerd2b1f351999-12-16 23:11:37 +000055 /* */
David Turnerb5713c52002-03-14 11:26:29 +000056 FT_LOCAL_DEF( TT_Table )
Werner Lemberg52005c32001-06-27 23:25:46 +000057 TT_LookUp_Table( TT_Face face,
58 FT_ULong tag )
David Turnerd2b1f351999-12-16 23:11:37 +000059 {
David Turnerb5713c52002-03-14 11:26:29 +000060 TT_Table entry;
61 TT_Table limit;
David Turnere49ab252000-05-16 23:44:38 +000062
Werner Lemberg4e6dd852000-06-05 05:26:15 +000063
Tom Kacvinsky200a1a42000-11-13 07:31:21 +000064 FT_TRACE3(( "TT_LookUp_Table: %08p, `%c%c%c%c' -- ",
Werner Lemberg34e52702000-11-13 16:58:01 +000065 face,
66 (FT_Char)( tag >> 24 ),
67 (FT_Char)( tag >> 16 ),
68 (FT_Char)( tag >> 8 ),
69 (FT_Char)( tag ) ));
David Turnerd2b1f351999-12-16 23:11:37 +000070
71 entry = face->dir_tables;
72 limit = entry + face->num_tables;
Werner Lemberg4e6dd852000-06-05 05:26:15 +000073
David Turnerd2b1f351999-12-16 23:11:37 +000074 for ( ; entry < limit; entry++ )
75 {
76 if ( entry->Tag == tag )
Tom Kacvinsky200a1a42000-11-13 07:31:21 +000077 {
Werner Lemberg34e52702000-11-13 16:58:01 +000078 FT_TRACE3(( "found table.\n" ));
David Turnerd2b1f351999-12-16 23:11:37 +000079 return entry;
Tom Kacvinsky200a1a42000-11-13 07:31:21 +000080 }
David Turnere49ab252000-05-16 23:44:38 +000081 }
Werner Lemberg4e6dd852000-06-05 05:26:15 +000082
Tom Kacvinsky200a1a42000-11-13 07:31:21 +000083 FT_TRACE3(( "could not find table!\n" ));
David Turnerd2b1f351999-12-16 23:11:37 +000084 return 0;
85 }
86
Werner Lemberg4e6dd852000-06-05 05:26:15 +000087
David Turnerd2b1f351999-12-16 23:11:37 +000088 /*************************************************************************/
89 /* */
90 /* <Function> */
91 /* TT_Goto_Table */
92 /* */
93 /* <Description> */
94 /* Looks for a TrueType table by name, then seek a stream to it. */
95 /* */
96 /* <Input> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +000097 /* face :: A face object handle. */
98 /* tag :: The searched tag. */
99 /* stream :: The stream to seek when the table is found. */
100 /* */
101 /* <Output> */
102 /* length :: The length of the table if found, undefined otherwise. */
David Turnerd2b1f351999-12-16 23:11:37 +0000103 /* */
104 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +0000105 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +0000106 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +0000107 FT_LOCAL_DEF( FT_Error )
Werner Lemberg52005c32001-06-27 23:25:46 +0000108 TT_Goto_Table( TT_Face face,
109 FT_ULong tag,
110 FT_Stream stream,
111 FT_ULong* length )
David Turnerd2b1f351999-12-16 23:11:37 +0000112 {
David Turnerb5713c52002-03-14 11:26:29 +0000113 TT_Table table;
David Turnerf9b8dec2000-06-16 19:34:52 +0000114 FT_Error error;
David Turnere49ab252000-05-16 23:44:38 +0000115
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000116
David Turnerd2b1f351999-12-16 23:11:37 +0000117 table = TT_LookUp_Table( face, tag );
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000118 if ( table )
David Turnerd2b1f351999-12-16 23:11:37 +0000119 {
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000120 if ( length )
David Turnerd2b1f351999-12-16 23:11:37 +0000121 *length = table->Length;
David Turnere49ab252000-05-16 23:44:38 +0000122
David Turner7d3a2642002-03-20 10:49:31 +0000123 if ( FT_STREAM_SEEK( table->Offset ) )
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000124 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +0000125 }
126 else
Werner Lemberg1f7f0e82001-06-06 17:30:41 +0000127 error = SFNT_Err_Table_Missing;
David Turnere49ab252000-05-16 23:44:38 +0000128
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000129 Exit:
David Turnerd2b1f351999-12-16 23:11:37 +0000130 return error;
131 }
132
133
134 /*************************************************************************/
135 /* */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000136 /* <Function> */
David Turnerb5713c52002-03-14 11:26:29 +0000137 /* TT_Load_SFNT_HeaderRec */
David Turnerd2b1f351999-12-16 23:11:37 +0000138 /* */
139 /* <Description> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000140 /* Loads the header of a SFNT font file. Supports collections. */
David Turnerd2b1f351999-12-16 23:11:37 +0000141 /* */
142 /* <Input> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000143 /* face :: A handle to the target face object. */
144 /* stream :: The input stream. */
145 /* face_index :: If the font is a collection, the number of the font */
146 /* in the collection, ignored otherwise. */
David Turnerb1677a82000-05-29 20:37:41 +0000147 /* */
David Turnerd42c68e2000-01-27 13:56:02 +0000148 /* <Output> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000149 /* sfnt :: The SFNT header. */
David Turnerd2b1f351999-12-16 23:11:37 +0000150 /* */
151 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +0000152 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +0000153 /* */
154 /* <Note> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000155 /* The stream cursor must be at the font file's origin. */
David Turnerd2b1f351999-12-16 23:11:37 +0000156 /* */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000157 /* This function recognizes fonts embedded in a `TrueType collection' */
158 /* */
159 /* The header will be checked whether it is valid by looking at the */
160 /* values of `search_range', `entry_selector', and `range_shift'. */
David Turnerb1677a82000-05-29 20:37:41 +0000161 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +0000162 FT_LOCAL_DEF( FT_Error )
David Turnerb5713c52002-03-14 11:26:29 +0000163 TT_Load_SFNT_HeaderRec( TT_Face face,
Werner Lemberg52005c32001-06-27 23:25:46 +0000164 FT_Stream stream,
165 FT_Long face_index,
David Turnerb5713c52002-03-14 11:26:29 +0000166 SFNT_Header sfnt )
David Turnerd2b1f351999-12-16 23:11:37 +0000167 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000168 FT_Error error;
169 FT_ULong format_tag;
Werner Lemberg7a4fda82000-06-13 23:21:00 +0000170 FT_Memory memory = stream->memory;
Werner Lemberg920d41e2000-06-05 14:32:32 +0000171
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000172 const FT_Frame_Field sfnt_header_fields[] =
173 {
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000174#undef FT_STRUCTURE
David Turnerb5713c52002-03-14 11:26:29 +0000175#define FT_STRUCTURE SFNT_HeaderRec
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000176
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000177 FT_FRAME_START( 8 ),
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000178 FT_FRAME_USHORT( num_tables ),
179 FT_FRAME_USHORT( search_range ),
180 FT_FRAME_USHORT( entry_selector ),
181 FT_FRAME_USHORT( range_shift ),
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000182 FT_FRAME_END
183 };
Werner Lemberg920d41e2000-06-05 14:32:32 +0000184
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000185 const FT_Frame_Field ttc_header_fields[] =
186 {
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000187#undef FT_STRUCTURE
David Turnerb5713c52002-03-14 11:26:29 +0000188#define FT_STRUCTURE TTC_HeaderRec
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000189
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000190 FT_FRAME_START( 8 ),
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000191 FT_FRAME_LONG( version ),
192 FT_FRAME_LONG( count ),
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000193 FT_FRAME_END };
David Turnerd2b1f351999-12-16 23:11:37 +0000194
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000195
David Turnerb5713c52002-03-14 11:26:29 +0000196 FT_TRACE2(( "TT_Load_SFNT_HeaderRec: %08p, %ld\n",
David Turner3581d062000-06-01 03:26:58 +0000197 face, face_index ));
David Turnerd2b1f351999-12-16 23:11:37 +0000198
Werner Lemberge1bbc012000-07-19 06:25:56 +0000199 face->ttc_header.tag = 0;
David Turnerd2b1f351999-12-16 23:11:37 +0000200 face->ttc_header.version = 0;
Werner Lemberge1bbc012000-07-19 06:25:56 +0000201 face->ttc_header.count = 0;
David Turnerd2b1f351999-12-16 23:11:37 +0000202
203 face->num_tables = 0;
204
Werner Lembergfbeb41d2000-07-02 00:27:53 +0000205 /* first of all, read the first 4 bytes. If it is `ttcf', then the */
206 /* file is a TrueType collection, otherwise it can be any other */
207 /* kind of font. */
David Turnera890c292002-03-22 12:55:23 +0000208 if ( FT_READ_ULONG( format_tag ) )
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000209 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +0000210
David Turnerb1677a82000-05-29 20:37:41 +0000211 if ( format_tag == TTAG_ttcf )
David Turnerd2b1f351999-12-16 23:11:37 +0000212 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000213 FT_Int n;
David Turnere49ab252000-05-16 23:44:38 +0000214
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000215
David Turnerb5713c52002-03-14 11:26:29 +0000216 FT_TRACE3(( "TT_Load_SFNT_HeaderRec: file is a collection\n" ));
David Turnere49ab252000-05-16 23:44:38 +0000217
David Turnerd2b1f351999-12-16 23:11:37 +0000218 /* it's a TrueType collection, i.e. a file containing several */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000219 /* font files. Read the font directory now */
David Turner7d3a2642002-03-20 10:49:31 +0000220 if ( FT_STREAM_READ_FIELDS( ttc_header_fields, &face->ttc_header ) )
David Turnera56489e2000-02-13 13:41:56 +0000221 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +0000222
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000223 /* now read the offsets of each font in the file */
David Turnere459d742002-03-22 13:52:37 +0000224 if ( FT_NEW_ARRAY( face->ttc_header.offsets, face->ttc_header.count ) ||
225 FT_FRAME_ENTER( face->ttc_header.count * 4L ) )
David Turnerd2b1f351999-12-16 23:11:37 +0000226 goto Exit;
227
Werner Lemberge1bbc012000-07-19 06:25:56 +0000228 for ( n = 0; n < face->ttc_header.count; n++ )
David Turnera890c292002-03-22 12:55:23 +0000229 face->ttc_header.offsets[n] = FT_GET_ULONG();
David Turnerd2b1f351999-12-16 23:11:37 +0000230
David Turner7d3a2642002-03-20 10:49:31 +0000231 FT_FRAME_EXIT();
David Turnerd2b1f351999-12-16 23:11:37 +0000232
233 /* check face index */
Werner Lemberge1bbc012000-07-19 06:25:56 +0000234 if ( face_index >= face->ttc_header.count )
David Turnerd2b1f351999-12-16 23:11:37 +0000235 {
Werner Lemberg1f7f0e82001-06-06 17:30:41 +0000236 error = SFNT_Err_Bad_Argument;
David Turnerd2b1f351999-12-16 23:11:37 +0000237 goto Exit;
David Turnere49ab252000-05-16 23:44:38 +0000238 }
239
David Turnerd2b1f351999-12-16 23:11:37 +0000240 /* seek to the appropriate TrueType file, then read tag */
David Turner7d3a2642002-03-20 10:49:31 +0000241 if ( FT_STREAM_SEEK( face->ttc_header.offsets[face_index] ) ||
David Turnera890c292002-03-22 12:55:23 +0000242 FT_READ_LONG( format_tag ) )
David Turnerd2b1f351999-12-16 23:11:37 +0000243 goto Exit;
244 }
David Turnerd2b1f351999-12-16 23:11:37 +0000245
David Turnerb1677a82000-05-29 20:37:41 +0000246 /* the format tag was read, now check the rest of the header */
247 sfnt->format_tag = format_tag;
David Turner7d3a2642002-03-20 10:49:31 +0000248 if ( FT_STREAM_READ_FIELDS( sfnt_header_fields, sfnt ) )
David Turnerb1677a82000-05-29 20:37:41 +0000249 goto Exit;
Werner Lemberg920d41e2000-06-05 14:32:32 +0000250
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000251 /* now, check the values of `num_tables', `seach_range', etc. */
David Turnerb1677a82000-05-29 20:37:41 +0000252 {
Werner Lembergfbeb41d2000-07-02 00:27:53 +0000253 FT_UInt num_tables = sfnt->num_tables;
254 FT_ULong entry_selector = 1L << sfnt->entry_selector;
David Turner3581d062000-06-01 03:26:58 +0000255
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000256
257 /* IMPORTANT: Many fonts have an incorrect `search_range' value, so */
258 /* we only check the `entry_selector' correctness here. */
259 /* */
260 if ( num_tables == 0 ||
261 entry_selector > num_tables ||
262 entry_selector * 2 <= num_tables )
David Turner3581d062000-06-01 03:26:58 +0000263 {
David Turnerb5713c52002-03-14 11:26:29 +0000264 FT_TRACE2(( "TT_Load_SFNT_HeaderRec: file is not SFNT!\n" ));
Werner Lemberg1f7f0e82001-06-06 17:30:41 +0000265 error = SFNT_Err_Unknown_File_Format;
David Turnerb1677a82000-05-29 20:37:41 +0000266 }
267 }
268
David Turnerd42c68e2000-01-27 13:56:02 +0000269 Exit:
270 return error;
Werner Lemberg920d41e2000-06-05 14:32:32 +0000271 }
David Turnerb1677a82000-05-29 20:37:41 +0000272
David Turnerd2b1f351999-12-16 23:11:37 +0000273
David Turnerd42c68e2000-01-27 13:56:02 +0000274 /*************************************************************************/
275 /* */
276 /* <Function> */
277 /* TT_Load_Directory */
278 /* */
279 /* <Description> */
280 /* Loads the table directory into a face object. */
281 /* */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000282 /* <InOut> */
283 /* face :: A handle to the target face object. */
284 /* */
David Turnerd42c68e2000-01-27 13:56:02 +0000285 /* <Input> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000286 /* stream :: The input stream. */
287 /* sfnt :: The SFNT directory header. */
David Turnerd42c68e2000-01-27 13:56:02 +0000288 /* */
289 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +0000290 /* FreeType error code. 0 means success. */
David Turnerd42c68e2000-01-27 13:56:02 +0000291 /* */
292 /* <Note> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000293 /* The stream cursor must be at the font file's origin. */
David Turnerd42c68e2000-01-27 13:56:02 +0000294 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +0000295 FT_LOCAL_DEF( FT_Error )
Werner Lemberg52005c32001-06-27 23:25:46 +0000296 TT_Load_Directory( TT_Face face,
297 FT_Stream stream,
David Turnerb5713c52002-03-14 11:26:29 +0000298 SFNT_Header sfnt )
David Turnerd42c68e2000-01-27 13:56:02 +0000299 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000300 FT_Error error;
David Turnerd42c68e2000-01-27 13:56:02 +0000301 FT_Memory memory = stream->memory;
David Turnerd42c68e2000-01-27 13:56:02 +0000302
David Turnerb5713c52002-03-14 11:26:29 +0000303 TT_TableRec *entry, *limit;
David Turnerd42c68e2000-01-27 13:56:02 +0000304
David Turnerd42c68e2000-01-27 13:56:02 +0000305
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000306 FT_TRACE2(( "TT_Load_Directory: %08p\n", face ));
307
308 FT_TRACE2(( "-- Tables count: %12u\n", sfnt->num_tables ));
309 FT_TRACE2(( "-- Format version: %08lx\n", sfnt->format_tag ));
David Turnerd42c68e2000-01-27 13:56:02 +0000310
David Turnerb1677a82000-05-29 20:37:41 +0000311 face->num_tables = sfnt->num_tables;
David Turnerd2b1f351999-12-16 23:11:37 +0000312
David Turnere459d742002-03-22 13:52:37 +0000313 if ( FT_NEW_ARRAY( face->dir_tables, face->num_tables ) )
David Turnerd2b1f351999-12-16 23:11:37 +0000314 goto Exit;
315
David Turner7d3a2642002-03-20 10:49:31 +0000316 if ( FT_FRAME_ENTER( face->num_tables * 16L ) )
David Turnerd2b1f351999-12-16 23:11:37 +0000317 goto Exit;
318
319 entry = face->dir_tables;
320 limit = entry + face->num_tables;
321
322 for ( ; entry < limit; entry++ )
David Turnerd42c68e2000-01-27 13:56:02 +0000323 { /* loop through the tables and get all entries */
David Turnera890c292002-03-22 12:55:23 +0000324 entry->Tag = FT_GET_TAG4();
325 entry->CheckSum = FT_GET_ULONG();
326 entry->Offset = FT_GET_LONG();
327 entry->Length = FT_GET_LONG();
David Turnerd2b1f351999-12-16 23:11:37 +0000328
329 FT_TRACE2(( " %c%c%c%c - %08lx - %08lx\n",
David Turnerf9b8dec2000-06-16 19:34:52 +0000330 (FT_Char)( entry->Tag >> 24 ),
331 (FT_Char)( entry->Tag >> 16 ),
332 (FT_Char)( entry->Tag >> 8 ),
333 (FT_Char)( entry->Tag ),
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000334 entry->Offset,
335 entry->Length ));
David Turnerd2b1f351999-12-16 23:11:37 +0000336 }
337
David Turner7d3a2642002-03-20 10:49:31 +0000338 FT_FRAME_EXIT();
David Turnerd2b1f351999-12-16 23:11:37 +0000339
340 FT_TRACE2(( "Directory loaded\n\n" ));
341
342 Exit:
343 return error;
344 }
345
346
347 /*************************************************************************/
348 /* */
349 /* <Function> */
350 /* TT_Load_Any */
351 /* */
352 /* <Description> */
Werner Lembergc8f9cf32000-07-19 02:59:31 +0000353 /* Loads any font table into client memory. */
David Turnerd2b1f351999-12-16 23:11:37 +0000354 /* */
355 /* <Input> */
356 /* face :: The face object to look for. */
357 /* */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000358 /* tag :: The tag of table to load. Use the value 0 if you want */
David Turnerd2b1f351999-12-16 23:11:37 +0000359 /* to access the whole font file, else set this parameter */
360 /* to a valid TrueType table tag that you can forge with */
361 /* the MAKE_TT_TAG macro. */
362 /* */
363 /* offset :: The starting offset in the table (or the file if */
364 /* tag == 0). */
365 /* */
366 /* length :: The address of the decision variable: */
367 /* */
368 /* If length == NULL: */
369 /* Loads the whole table. Returns an error if */
370 /* `offset' == 0! */
371 /* */
372 /* If *length == 0: */
373 /* Exits immediately; returning the length of the given */
374 /* table or of the font file, depending on the value of */
375 /* `tag'. */
376 /* */
377 /* If *length != 0: */
378 /* Loads the next `length' bytes of table or font, */
379 /* starting at offset `offset' (in table or font too). */
380 /* */
381 /* <Output> */
382 /* buffer :: The address of target buffer. */
383 /* */
384 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +0000385 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +0000386 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +0000387 FT_LOCAL_DEF( FT_Error )
Werner Lemberg52005c32001-06-27 23:25:46 +0000388 TT_Load_Any( TT_Face face,
389 FT_ULong tag,
390 FT_Long offset,
391 FT_Byte* buffer,
392 FT_ULong* length )
David Turnerd2b1f351999-12-16 23:11:37 +0000393 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000394 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +0000395 FT_Stream stream;
David Turnerb5713c52002-03-14 11:26:29 +0000396 TT_Table table;
David Turnerf9b8dec2000-06-16 19:34:52 +0000397 FT_ULong size;
David Turnerd2b1f351999-12-16 23:11:37 +0000398
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000399
David Turnerd2b1f351999-12-16 23:11:37 +0000400 if ( tag != 0 )
401 {
402 /* look for tag in font directory */
403 table = TT_LookUp_Table( face, tag );
404 if ( !table )
405 {
Werner Lemberg1f7f0e82001-06-06 17:30:41 +0000406 error = SFNT_Err_Table_Missing;
David Turnerd2b1f351999-12-16 23:11:37 +0000407 goto Exit;
408 }
409
410 offset += table->Offset;
411 size = table->Length;
412 }
413 else
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000414 /* tag == 0 -- the user wants to access the font file directly */
David Turnerd2b1f351999-12-16 23:11:37 +0000415 size = face->root.stream->size;
David Turnerd2b1f351999-12-16 23:11:37 +0000416
417 if ( length && *length == 0 )
418 {
419 *length = size;
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000420
Werner Lemberg1f7f0e82001-06-06 17:30:41 +0000421 return SFNT_Err_Ok;
David Turnerd2b1f351999-12-16 23:11:37 +0000422 }
423
424 if ( length )
425 size = *length;
426
427 stream = face->root.stream;
Werner Lembergb1dd3532000-07-31 22:51:00 +0000428 /* the `if' is syntactic sugar for picky compilers */
David Turner7d3a2642002-03-20 10:49:31 +0000429 if ( FT_STREAM_READ_AT( offset, buffer, size ) )
David Turner24d70242000-08-17 01:09:06 +0000430 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +0000431
432 Exit:
433 return error;
434 }
435
436
437 /*************************************************************************/
438 /* */
439 /* <Function> */
Tom Kacvinsky200a1a42000-11-13 07:31:21 +0000440 /* TT_Load_Generic_Header */
David Turnerd2b1f351999-12-16 23:11:37 +0000441 /* */
442 /* <Description> */
Tom Kacvinsky200a1a42000-11-13 07:31:21 +0000443 /* Loads the TrueType table `head' or `bhed'. */
David Turnerd2b1f351999-12-16 23:11:37 +0000444 /* */
445 /* <Input> */
446 /* face :: A handle to the target face object. */
447 /* stream :: The input stream. */
448 /* */
449 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +0000450 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +0000451 /* */
Werner Lemberg52005c32001-06-27 23:25:46 +0000452 static FT_Error
453 TT_Load_Generic_Header( TT_Face face,
454 FT_Stream stream,
455 FT_ULong tag )
David Turnerd2b1f351999-12-16 23:11:37 +0000456 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000457 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +0000458 TT_Header* header;
David Turnerb1677a82000-05-29 20:37:41 +0000459
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000460 static const FT_Frame_Field header_fields[] =
461 {
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000462#undef FT_STRUCTURE
463#define FT_STRUCTURE TT_Header
464
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000465 FT_FRAME_START( 54 ),
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000466 FT_FRAME_ULONG ( Table_Version ),
467 FT_FRAME_ULONG ( Font_Revision ),
468 FT_FRAME_LONG ( CheckSum_Adjust ),
469 FT_FRAME_LONG ( Magic_Number ),
470 FT_FRAME_USHORT( Flags ),
471 FT_FRAME_USHORT( Units_Per_EM ),
472 FT_FRAME_LONG ( Created[0] ),
473 FT_FRAME_LONG ( Created[1] ),
474 FT_FRAME_LONG ( Modified[0] ),
475 FT_FRAME_LONG ( Modified[1] ),
476 FT_FRAME_SHORT ( xMin ),
477 FT_FRAME_SHORT ( yMin ),
478 FT_FRAME_SHORT ( xMax ),
479 FT_FRAME_SHORT ( yMax ),
480 FT_FRAME_USHORT( Mac_Style ),
481 FT_FRAME_USHORT( Lowest_Rec_PPEM ),
482 FT_FRAME_SHORT ( Font_Direction ),
483 FT_FRAME_SHORT ( Index_To_Loc_Format ),
484 FT_FRAME_SHORT ( Glyph_Data_Format ),
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000485 FT_FRAME_END
486 };
David Turnerd2b1f351999-12-16 23:11:37 +0000487
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000488
Werner Lemberg34e52702000-11-13 16:58:01 +0000489 FT_TRACE2(( "TT_Load_Generic_Header: "
490 "%08p, looking up font table `%c%c%c%c'.\n",
491 face,
492 (FT_Char)( tag >> 24 ),
493 (FT_Char)( tag >> 16 ),
494 (FT_Char)( tag >> 8 ),
495 (FT_Char)( tag ) ));
David Turnerd2b1f351999-12-16 23:11:37 +0000496
David Turnerf96594f2000-11-06 23:07:51 +0000497 error = face->goto_table( face, tag, stream, 0 );
David Turnerd2b1f351999-12-16 23:11:37 +0000498 if ( error )
499 {
Werner Lemberg04bfe312001-12-11 14:09:06 +0000500 FT_TRACE2(( "TT_Load_Generic_Header: Font table is missing!\n" ));
David Turnerd2b1f351999-12-16 23:11:37 +0000501 goto Exit;
502 }
503
David Turnera56489e2000-02-13 13:41:56 +0000504 header = &face->header;
505
David Turner7d3a2642002-03-20 10:49:31 +0000506 if ( FT_STREAM_READ_FIELDS( header_fields, header ) )
David Turnerd2b1f351999-12-16 23:11:37 +0000507 goto Exit;
508
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000509 FT_TRACE2(( " Units per EM: %8u\n", header->Units_Per_EM ));
510 FT_TRACE2(( " IndexToLoc: %8d\n", header->Index_To_Loc_Format ));
Werner Lemberg04bfe312001-12-11 14:09:06 +0000511 FT_TRACE2(( "TT_Load_Generic_Header: Font table loaded.\n" ));
David Turnerd2b1f351999-12-16 23:11:37 +0000512
513 Exit:
514 return error;
515 }
516
Werner Lemberg4b680072000-11-07 06:30:29 +0000517
David Turnerbc82f1b2002-03-01 02:26:22 +0000518 FT_LOCAL_DEF( FT_Error )
Werner Lemberg52005c32001-06-27 23:25:46 +0000519 TT_Load_Header( TT_Face face,
520 FT_Stream stream )
David Turnerf96594f2000-11-06 23:07:51 +0000521 {
522 return TT_Load_Generic_Header( face, stream, TTAG_head );
523 }
524
Werner Lemberg4b680072000-11-07 06:30:29 +0000525
David Turnerf96594f2000-11-06 23:07:51 +0000526#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
Werner Lemberg4b680072000-11-07 06:30:29 +0000527
David Turnerbc82f1b2002-03-01 02:26:22 +0000528 FT_LOCAL_DEF( FT_Error )
Werner Lemberg52005c32001-06-27 23:25:46 +0000529 TT_Load_Bitmap_Header( TT_Face face,
530 FT_Stream stream )
David Turnerf96594f2000-11-06 23:07:51 +0000531 {
532 return TT_Load_Generic_Header( face, stream, TTAG_bhed );
533 }
Werner Lemberg4b680072000-11-07 06:30:29 +0000534
535#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
536
David Turnerd2b1f351999-12-16 23:11:37 +0000537
538 /*************************************************************************/
539 /* */
540 /* <Function> */
541 /* TT_Load_MaxProfile */
542 /* */
543 /* <Description> */
544 /* Loads the maximum profile into a face object. */
545 /* */
546 /* <Input> */
547 /* face :: A handle to the target face object. */
548 /* stream :: The input stream. */
549 /* */
550 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +0000551 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +0000552 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +0000553 FT_LOCAL_DEF( FT_Error )
Werner Lemberg52005c32001-06-27 23:25:46 +0000554 TT_Load_MaxProfile( TT_Face face,
555 FT_Stream stream )
David Turnerd2b1f351999-12-16 23:11:37 +0000556 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000557 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +0000558 TT_MaxProfile* maxProfile = &face->max_profile;
David Turnerb1677a82000-05-29 20:37:41 +0000559
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000560 const FT_Frame_Field maxp_fields[] =
561 {
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000562#undef FT_STRUCTURE
563#define FT_STRUCTURE TT_MaxProfile
564
Werner Lemberg36af3ea2001-07-17 12:37:54 +0000565 FT_FRAME_START( 6 ),
566 FT_FRAME_LONG ( version ),
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000567 FT_FRAME_USHORT( numGlyphs ),
Werner Lemberg36af3ea2001-07-17 12:37:54 +0000568 FT_FRAME_END
569 };
570
571 const FT_Frame_Field maxp_fields_extra[] =
572 {
573 FT_FRAME_START( 26 ),
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000574 FT_FRAME_USHORT( maxPoints ),
575 FT_FRAME_USHORT( maxContours ),
576 FT_FRAME_USHORT( maxCompositePoints ),
577 FT_FRAME_USHORT( maxCompositeContours ),
578 FT_FRAME_USHORT( maxZones ),
579 FT_FRAME_USHORT( maxTwilightPoints ),
580 FT_FRAME_USHORT( maxStorage ),
581 FT_FRAME_USHORT( maxFunctionDefs ),
582 FT_FRAME_USHORT( maxInstructionDefs ),
583 FT_FRAME_USHORT( maxStackElements ),
584 FT_FRAME_USHORT( maxSizeOfInstructions ),
585 FT_FRAME_USHORT( maxComponentElements ),
586 FT_FRAME_USHORT( maxComponentDepth ),
Werner Lemberg36af3ea2001-07-17 12:37:54 +0000587 FT_FRAME_END
588 };
David Turnerd2b1f351999-12-16 23:11:37 +0000589
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000590
591 FT_TRACE2(( "Load_TT_MaxProfile: %08p\n", face ));
David Turnerd2b1f351999-12-16 23:11:37 +0000592
593 error = face->goto_table( face, TTAG_maxp, stream, 0 );
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000594 if ( error )
595 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +0000596
David Turner7d3a2642002-03-20 10:49:31 +0000597 if ( FT_STREAM_READ_FIELDS( maxp_fields, maxProfile ) )
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000598 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +0000599
Werner Lemberg36af3ea2001-07-17 12:37:54 +0000600 maxProfile->maxPoints = 0;
601 maxProfile->maxContours = 0;
602 maxProfile->maxCompositePoints = 0;
603 maxProfile->maxCompositeContours = 0;
604 maxProfile->maxZones = 0;
605 maxProfile->maxTwilightPoints = 0;
606 maxProfile->maxStorage = 0;
607 maxProfile->maxFunctionDefs = 0;
608 maxProfile->maxInstructionDefs = 0;
609 maxProfile->maxStackElements = 0;
610 maxProfile->maxSizeOfInstructions = 0;
611 maxProfile->maxComponentElements = 0;
612 maxProfile->maxComponentDepth = 0;
David Turnerd2b1f351999-12-16 23:11:37 +0000613
Werner Lemberg36af3ea2001-07-17 12:37:54 +0000614 if ( maxProfile->version >= 0x10000L )
615 {
David Turner7d3a2642002-03-20 10:49:31 +0000616 if ( FT_STREAM_READ_FIELDS( maxp_fields_extra, maxProfile ) )
Werner Lemberg36af3ea2001-07-17 12:37:54 +0000617 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +0000618
Werner Lemberg36af3ea2001-07-17 12:37:54 +0000619 /* XXX: an adjustment that is necessary to load certain */
620 /* broken fonts like `Keystrokes MT' :-( */
621 /* */
622 /* We allocate 64 function entries by default when */
623 /* the maxFunctionDefs field is null. */
David Turnerd2b1f351999-12-16 23:11:37 +0000624
Werner Lemberg36af3ea2001-07-17 12:37:54 +0000625 if ( maxProfile->maxFunctionDefs == 0 )
626 maxProfile->maxFunctionDefs = 64;
David Turnerd2b1f351999-12-16 23:11:37 +0000627
Werner Lemberg36af3ea2001-07-17 12:37:54 +0000628 face->root.num_glyphs = maxProfile->numGlyphs;
David Turnerd2b1f351999-12-16 23:11:37 +0000629
Werner Lemberg36af3ea2001-07-17 12:37:54 +0000630 face->root.internal->max_points =
631 (FT_UShort)MAX( maxProfile->maxCompositePoints,
632 maxProfile->maxPoints );
David Turnerd2b1f351999-12-16 23:11:37 +0000633
Werner Lemberg36af3ea2001-07-17 12:37:54 +0000634 face->root.internal->max_contours =
635 (FT_Short)MAX( maxProfile->maxCompositeContours,
636 maxProfile->maxContours );
David Turnerd2b1f351999-12-16 23:11:37 +0000637
Werner Lemberg36af3ea2001-07-17 12:37:54 +0000638 face->max_components = (FT_ULong)maxProfile->maxComponentElements +
639 maxProfile->maxComponentDepth;
640
641 /* XXX: some fonts have maxComponents set to 0; we will */
642 /* then use 16 of them by default. */
643 if ( face->max_components == 0 )
644 face->max_components = 16;
645
646 /* We also increase maxPoints and maxContours in order to support */
647 /* some broken fonts. */
Werner Lemberg3975e2e2002-01-09 21:01:18 +0000648 face->root.internal->max_points += (FT_UShort)8;
649 face->root.internal->max_contours += (FT_Short) 4;
Werner Lemberg36af3ea2001-07-17 12:37:54 +0000650 }
David Turnerd2b1f351999-12-16 23:11:37 +0000651
652 FT_TRACE2(( "MAXP loaded.\n" ));
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000653
David Turnerd2b1f351999-12-16 23:11:37 +0000654 Exit:
655 return error;
656 }
657
658
659 /*************************************************************************/
660 /* */
661 /* <Function> */
662 /* TT_Load_Metrics */
663 /* */
664 /* <Description> */
665 /* Loads the horizontal or vertical metrics table into a face object. */
666 /* */
667 /* <Input> */
668 /* face :: A handle to the target face object. */
669 /* stream :: The input stream. */
670 /* vertical :: A boolean flag. If set, load vertical metrics. */
671 /* */
672 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +0000673 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +0000674 /* */
Werner Lemberg52005c32001-06-27 23:25:46 +0000675 static FT_Error
676 TT_Load_Metrics( TT_Face face,
677 FT_Stream stream,
678 FT_Bool vertical )
David Turnerd2b1f351999-12-16 23:11:37 +0000679 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000680 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +0000681 FT_Memory memory = stream->memory;
682
David Turnerf9b8dec2000-06-16 19:34:52 +0000683 FT_ULong table_len;
684 FT_Long num_shorts, num_longs, num_shorts_checked;
David Turnerd2b1f351999-12-16 23:11:37 +0000685
David Turnerb5713c52002-03-14 11:26:29 +0000686 TT_LongMetrics * longs;
David Turnerd2b1f351999-12-16 23:11:37 +0000687 TT_ShortMetrics** shorts;
688
Werner Lembergfbeb41d2000-07-02 00:27:53 +0000689
690 FT_TRACE2(( "TT_Load_%s_Metrics: %08p\n", vertical ? "Vertical"
691 : "Horizontal",
692 face ));
David Turnerd2b1f351999-12-16 23:11:37 +0000693
694 if ( vertical )
695 {
696 /* The table is optional, quit silently if it wasn't found */
697 /* XXX: Some fonts have a valid vertical header with a non-null */
698 /* `number_of_VMetrics' fields, but no corresponding `vmtx' */
699 /* table to get the metrics from (e.g. mingliu). */
700 /* */
701 /* For safety, we set the field to 0! */
702 /* */
703 error = face->goto_table( face, TTAG_vmtx, stream, &table_len );
704 if ( error )
705 {
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000706 /* Set number_Of_VMetrics to 0! */
David Turnerd2b1f351999-12-16 23:11:37 +0000707 FT_TRACE2(( " no vertical header in file.\n" ));
708 face->vertical.number_Of_VMetrics = 0;
Werner Lemberg1f7f0e82001-06-06 17:30:41 +0000709 error = SFNT_Err_Ok;
David Turnerd2b1f351999-12-16 23:11:37 +0000710 goto Exit;
711 }
712
713 num_longs = face->vertical.number_Of_VMetrics;
David Turnerb5713c52002-03-14 11:26:29 +0000714 longs = (TT_LongMetrics *)&face->vertical.long_metrics;
David Turnerd2b1f351999-12-16 23:11:37 +0000715 shorts = (TT_ShortMetrics**)&face->vertical.short_metrics;
716 }
717 else
718 {
719 error = face->goto_table( face, TTAG_hmtx, stream, &table_len );
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000720 if ( error )
David Turnerd2b1f351999-12-16 23:11:37 +0000721 {
722 FT_ERROR(( " no horizontal metrics in file!\n" ));
Werner Lemberg1f7f0e82001-06-06 17:30:41 +0000723 error = SFNT_Err_Hmtx_Table_Missing;
David Turnerd2b1f351999-12-16 23:11:37 +0000724 goto Exit;
725 }
726
727 num_longs = face->horizontal.number_Of_HMetrics;
David Turnerb5713c52002-03-14 11:26:29 +0000728 longs = (TT_LongMetrics *)&face->horizontal.long_metrics;
David Turnerd2b1f351999-12-16 23:11:37 +0000729 shorts = (TT_ShortMetrics**)&face->horizontal.short_metrics;
730 }
731
732 /* never trust derived values */
733
734 num_shorts = face->max_profile.numGlyphs - num_longs;
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000735 num_shorts_checked = ( table_len - num_longs * 4L ) / 2;
David Turnerd2b1f351999-12-16 23:11:37 +0000736
737 if ( num_shorts < 0 )
738 {
Werner Lembergfbeb41d2000-07-02 00:27:53 +0000739 FT_ERROR(( "TT_Load_%s_Metrics: more metrics than glyphs!\n",
740 vertical ? "Vertical"
741 : "Horizontal" ));
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000742
Werner Lemberg1f7f0e82001-06-06 17:30:41 +0000743 error = vertical ? SFNT_Err_Invalid_Vert_Metrics
744 : SFNT_Err_Invalid_Horiz_Metrics;
David Turnerd2b1f351999-12-16 23:11:37 +0000745 goto Exit;
746 }
747
David Turnere459d742002-03-22 13:52:37 +0000748 if ( FT_NEW_ARRAY( *longs, num_longs ) ||
749 FT_NEW_ARRAY( *shorts, num_shorts ) )
David Turnerd2b1f351999-12-16 23:11:37 +0000750 goto Exit;
751
David Turner7d3a2642002-03-20 10:49:31 +0000752 if ( FT_FRAME_ENTER( table_len ) )
David Turnerd2b1f351999-12-16 23:11:37 +0000753 goto Exit;
754
755 {
David Turnerb5713c52002-03-14 11:26:29 +0000756 TT_LongMetrics cur = *longs;
757 TT_LongMetrics limit = cur + num_longs;
David Turnerd2b1f351999-12-16 23:11:37 +0000758
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000759
David Turnerd2b1f351999-12-16 23:11:37 +0000760 for ( ; cur < limit; cur++ )
761 {
David Turnera890c292002-03-22 12:55:23 +0000762 cur->advance = FT_GET_USHORT();
763 cur->bearing = FT_GET_SHORT();
David Turnerd2b1f351999-12-16 23:11:37 +0000764 }
765 }
766
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000767 /* do we have an inconsistent number of metric values? */
David Turnerd2b1f351999-12-16 23:11:37 +0000768 {
769 TT_ShortMetrics* cur = *shorts;
770 TT_ShortMetrics* limit = cur + MIN( num_shorts, num_shorts_checked );
771
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000772
David Turnerd2b1f351999-12-16 23:11:37 +0000773 for ( ; cur < limit; cur++ )
David Turnera890c292002-03-22 12:55:23 +0000774 *cur = FT_GET_SHORT();
David Turnerd2b1f351999-12-16 23:11:37 +0000775
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000776 /* we fill up the missing left side bearings with the */
777 /* last valid value. Since this will occur for buggy CJK */
778 /* fonts usually only, nothing serious will happen */
David Turnerd2b1f351999-12-16 23:11:37 +0000779 if ( num_shorts > num_shorts_checked && num_shorts_checked > 0 )
780 {
Tom Kacvinsky4a1bc8f2001-04-02 17:47:16 +0000781 FT_Short val = (*shorts)[num_shorts_checked - 1];
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000782
David Turnerd2b1f351999-12-16 23:11:37 +0000783
784 limit = *shorts + num_shorts;
785 for ( ; cur < limit; cur++ )
786 *cur = val;
787 }
788 }
789
David Turner7d3a2642002-03-20 10:49:31 +0000790 FT_FRAME_EXIT();
David Turnerd2b1f351999-12-16 23:11:37 +0000791
792 FT_TRACE2(( "loaded\n" ));
793
794 Exit:
795 return error;
796 }
797
798
799 /*************************************************************************/
800 /* */
801 /* <Function> */
802 /* TT_Load_Metrics_Header */
803 /* */
804 /* <Description> */
805 /* Loads the horizontal or vertical header in a face object. */
806 /* */
807 /* <Input> */
808 /* face :: A handle to the target face object. */
809 /* stream :: The input stream. */
810 /* vertical :: A boolean flag. If set, load vertical metrics. */
811 /* */
812 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +0000813 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +0000814 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +0000815 FT_LOCAL_DEF( FT_Error )
Werner Lemberg52005c32001-06-27 23:25:46 +0000816 TT_Load_Metrics_Header( TT_Face face,
817 FT_Stream stream,
818 FT_Bool vertical )
David Turnerd2b1f351999-12-16 23:11:37 +0000819 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000820 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +0000821 TT_HoriHeader* header;
David Turnerb1677a82000-05-29 20:37:41 +0000822
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000823 const FT_Frame_Field metrics_header_fields[] =
824 {
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000825#undef FT_STRUCTURE
826#define FT_STRUCTURE TT_HoriHeader
827
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000828 FT_FRAME_START( 36 ),
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000829 FT_FRAME_ULONG ( Version ),
830 FT_FRAME_SHORT ( Ascender ),
831 FT_FRAME_SHORT ( Descender ),
832 FT_FRAME_SHORT ( Line_Gap ),
833 FT_FRAME_USHORT( advance_Width_Max ),
834 FT_FRAME_SHORT ( min_Left_Side_Bearing ),
835 FT_FRAME_SHORT ( min_Right_Side_Bearing ),
836 FT_FRAME_SHORT ( xMax_Extent ),
837 FT_FRAME_SHORT ( caret_Slope_Rise ),
838 FT_FRAME_SHORT ( caret_Slope_Run ),
Werner Lemberg5dea4442001-08-13 11:44:29 +0000839 FT_FRAME_SHORT ( caret_Offset ),
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000840 FT_FRAME_SHORT ( Reserved[0] ),
841 FT_FRAME_SHORT ( Reserved[1] ),
842 FT_FRAME_SHORT ( Reserved[2] ),
843 FT_FRAME_SHORT ( Reserved[3] ),
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000844 FT_FRAME_SHORT ( metric_Data_Format ),
845 FT_FRAME_USHORT( number_Of_HMetrics ),
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000846 FT_FRAME_END
847 };
848
David Turnerb1677a82000-05-29 20:37:41 +0000849
David Turnerd2b1f351999-12-16 23:11:37 +0000850 FT_TRACE2(( vertical ? "Vertical header " : "Horizontal header " ));
851
852 if ( vertical )
853 {
854 face->vertical_info = 0;
855
856 /* The vertical header table is optional, so return quietly if */
857 /* we don't find it. */
858 error = face->goto_table( face, TTAG_vhea, stream, 0 );
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000859 if ( error )
David Turnerd2b1f351999-12-16 23:11:37 +0000860 {
Werner Lemberg1f7f0e82001-06-06 17:30:41 +0000861 error = SFNT_Err_Ok;
David Turnerd2b1f351999-12-16 23:11:37 +0000862 goto Exit;
863 }
864
865 face->vertical_info = 1;
866 header = (TT_HoriHeader*)&face->vertical;
867 }
868 else
869 {
Werner Lembergfbeb41d2000-07-02 00:27:53 +0000870 /* The horizontal header is mandatory; return an error if we */
David Turnerd2b1f351999-12-16 23:11:37 +0000871 /* don't find it. */
872 error = face->goto_table( face, TTAG_hhea, stream, 0 );
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000873 if ( error )
David Turnerd2b1f351999-12-16 23:11:37 +0000874 {
Werner Lemberg1f7f0e82001-06-06 17:30:41 +0000875 error = SFNT_Err_Horiz_Header_Missing;
David Turnerd2b1f351999-12-16 23:11:37 +0000876 goto Exit;
877 }
878
879 header = &face->horizontal;
880 }
881
David Turner7d3a2642002-03-20 10:49:31 +0000882 if ( FT_STREAM_READ_FIELDS( metrics_header_fields, header ) )
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000883 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +0000884
885 header->long_metrics = NULL;
886 header->short_metrics = NULL;
887
888 FT_TRACE2(( "loaded\n" ));
889
890 /* Now try to load the corresponding metrics */
891
892 error = TT_Load_Metrics( face, stream, vertical );
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000893
David Turnerd2b1f351999-12-16 23:11:37 +0000894 Exit:
895 return error;
896 }
897
898
899 /*************************************************************************/
900 /* */
901 /* <Function> */
902 /* TT_Load_Names */
903 /* */
904 /* <Description> */
905 /* Loads the name records. */
906 /* */
907 /* <Input> */
908 /* face :: A handle to the target face object. */
909 /* stream :: The input stream. */
910 /* */
911 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +0000912 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +0000913 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +0000914 FT_LOCAL_DEF( FT_Error )
Werner Lemberg52005c32001-06-27 23:25:46 +0000915 TT_Load_Names( TT_Face face,
916 FT_Stream stream )
David Turnerd2b1f351999-12-16 23:11:37 +0000917 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000918 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +0000919 FT_Memory memory = stream->memory;
920
David Turnerf9b8dec2000-06-16 19:34:52 +0000921 FT_ULong table_pos, table_len;
David Turnerc03d9cf2002-02-27 23:10:19 +0000922 FT_ULong storageOffset, storageSize;
923 FT_Byte* storage;
David Turnerd2b1f351999-12-16 23:11:37 +0000924
David Turnerb5713c52002-03-14 11:26:29 +0000925 TT_NameTable names;
David Turnerb1677a82000-05-29 20:37:41 +0000926
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000927 const FT_Frame_Field name_table_fields[] =
928 {
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000929#undef FT_STRUCTURE
David Turnerb5713c52002-03-14 11:26:29 +0000930#define FT_STRUCTURE TT_NameTableRec
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000931
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000932 FT_FRAME_START( 6 ),
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000933 FT_FRAME_USHORT( format ),
934 FT_FRAME_USHORT( numNameRecords ),
935 FT_FRAME_USHORT( storageOffset ),
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000936 FT_FRAME_END
937 };
David Turnera56489e2000-02-13 13:41:56 +0000938
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000939 const FT_Frame_Field name_record_fields[] =
940 {
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000941#undef FT_STRUCTURE
David Turnerb5713c52002-03-14 11:26:29 +0000942#define FT_STRUCTURE TT_NameEntryRec
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000943
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000944 /* no FT_FRAME_START */
Werner Lemberge72c9fe2000-07-31 18:59:02 +0000945 FT_FRAME_USHORT( platformID ),
946 FT_FRAME_USHORT( encodingID ),
947 FT_FRAME_USHORT( languageID ),
948 FT_FRAME_USHORT( nameID ),
949 FT_FRAME_USHORT( stringLength ),
950 FT_FRAME_USHORT( stringOffset ),
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000951 FT_FRAME_END
952 };
David Turnerd2b1f351999-12-16 23:11:37 +0000953
954
955 FT_TRACE2(( "Names " ));
956
957 error = face->goto_table( face, TTAG_name, stream, &table_len );
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000958 if ( error )
David Turnerd2b1f351999-12-16 23:11:37 +0000959 {
960 /* The name table is required so indicate failure. */
961 FT_TRACE2(( "is missing!\n" ));
Werner Lemberg1f7f0e82001-06-06 17:30:41 +0000962 error = SFNT_Err_Name_Table_Missing;
David Turnerd2b1f351999-12-16 23:11:37 +0000963 goto Exit;
964 }
965
David Turner7d3a2642002-03-20 10:49:31 +0000966 table_pos = FT_STREAM_POS();
David Turnerd2b1f351999-12-16 23:11:37 +0000967
David Turnera56489e2000-02-13 13:41:56 +0000968 names = &face->name_table;
969
David Turner7d3a2642002-03-20 10:49:31 +0000970 if ( FT_STREAM_READ_FIELDS( name_table_fields, names ) )
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000971 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +0000972
David Turnerc03d9cf2002-02-27 23:10:19 +0000973 /* check the 'storageOffset' field */
974 storageOffset = names->storageOffset;
975 if ( storageOffset < (FT_ULong)(6 + 12*names->numNameRecords) ||
976 table_len <= storageOffset )
977 {
978 FT_ERROR(( "TT.load_names: invalid 'name' table\n" ));
979 error = SFNT_Err_Name_Table_Missing;
980 goto Exit;
981 }
982
983 storageSize = (FT_ULong)(table_len - storageOffset);
984
David Turnerd2b1f351999-12-16 23:11:37 +0000985 /* Allocate the array of name records. */
David Turnere459d742002-03-22 13:52:37 +0000986 if ( FT_ALLOC( names->names,
David Turnerb5713c52002-03-14 11:26:29 +0000987 names->numNameRecords*sizeof(TT_NameEntryRec) + storageSize ) ||
David Turner7d3a2642002-03-20 10:49:31 +0000988 FT_FRAME_ENTER( names->numNameRecords * 12L ) )
David Turnerd2b1f351999-12-16 23:11:37 +0000989 goto Exit;
990
David Turnerc03d9cf2002-02-27 23:10:19 +0000991 storage = (FT_Byte*)(names->names + names->numNameRecords);
992
David Turnerd2b1f351999-12-16 23:11:37 +0000993 /* Load the name records and determine how much storage is needed */
994 /* to hold the strings themselves. */
995 {
David Turnerb5713c52002-03-14 11:26:29 +0000996 TT_NameEntryRec* cur = names->names;
997 TT_NameEntryRec* limit = cur + names->numNameRecords;
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000998
David Turnerd2b1f351999-12-16 23:11:37 +0000999
David Turnerd2b1f351999-12-16 23:11:37 +00001000 for ( ; cur < limit; cur ++ )
1001 {
David Turner7d3a2642002-03-20 10:49:31 +00001002 if ( FT_STREAM_READ_FIELDS( name_record_fields, cur ) )
Werner Lembergb1dd3532000-07-31 22:51:00 +00001003 break;
David Turnerb1677a82000-05-29 20:37:41 +00001004
David Turnerc03d9cf2002-02-27 23:10:19 +00001005 /* invalid name entries will have "cur->string" set to NULL !! */
1006 if ( (FT_ULong)(cur->stringOffset + cur->stringLength) < storageSize )
1007 cur->string = storage + cur->stringOffset;
David Turner28ea6f62002-03-05 16:12:57 +00001008 else
1009 {
1010 /* that's an invalid entry */
1011 cur->stringOffset = 0;
1012 cur->string = NULL;
1013 }
David Turnerd2b1f351999-12-16 23:11:37 +00001014 }
1015 }
1016
David Turner7d3a2642002-03-20 10:49:31 +00001017 FT_FRAME_EXIT();
David Turnerd2b1f351999-12-16 23:11:37 +00001018
David Turnerc03d9cf2002-02-27 23:10:19 +00001019 if (error)
1020 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +00001021
David Turner28ea6f62002-03-05 16:12:57 +00001022 storageOffset -= 6 + 12*names->numNameRecords;
David Turner7d3a2642002-03-20 10:49:31 +00001023 if ( FT_STREAM_SKIP( storageOffset ) ||
1024 FT_STREAM_READ( storage, storageSize ) )
David Turner28ea6f62002-03-05 16:12:57 +00001025 goto Exit;
1026
1027
David Turnere49ab252000-05-16 23:44:38 +00001028#ifdef FT_DEBUG_LEVEL_TRACE
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001029
David Turnerd2b1f351999-12-16 23:11:37 +00001030 /* Print Name Record Table in case of debugging */
1031 {
David Turnerb5713c52002-03-14 11:26:29 +00001032 TT_NameEntryRec* cur = names->names;
1033 TT_NameEntryRec* limit = cur + names->numNameRecords;
David Turnerd2b1f351999-12-16 23:11:37 +00001034
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001035
David Turnerd2b1f351999-12-16 23:11:37 +00001036 for ( ; cur < limit; cur++ )
1037 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001038 FT_UInt j;
David Turnere49ab252000-05-16 23:44:38 +00001039
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001040
David Turnerc03d9cf2002-02-27 23:10:19 +00001041 FT_TRACE3(( "(%2d %2d %4x %2d) ",
David Turnerd2b1f351999-12-16 23:11:37 +00001042 cur->platformID,
1043 cur->encodingID,
1044 cur->languageID,
1045 cur->nameID ));
David Turnere49ab252000-05-16 23:44:38 +00001046
David Turnerd2b1f351999-12-16 23:11:37 +00001047 /* I know that M$ encoded strings are Unicode, */
1048 /* but this works reasonable well for debugging purposes. */
1049 if ( cur->string )
David Turnerd3c8e062000-12-04 22:53:55 +00001050 for ( j = 0; j < (FT_UInt)cur->stringLength; j++ )
David Turnerd2b1f351999-12-16 23:11:37 +00001051 {
David Turnerc03d9cf2002-02-27 23:10:19 +00001052 FT_Byte c = *(FT_Byte*)(cur->string + j);
David Turnere49ab252000-05-16 23:44:38 +00001053
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001054
David Turnerc03d9cf2002-02-27 23:10:19 +00001055 if ( c >= 32 && c < 128 )
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001056 FT_TRACE3(( "%c", c ));
David Turnerd2b1f351999-12-16 23:11:37 +00001057 }
David Turnerc03d9cf2002-02-27 23:10:19 +00001058 else
1059 FT_TRACE3(( "INVALID ENTRY !!\n" ));
1060
1061 FT_TRACE3(( "\n" ));
David Turnerd2b1f351999-12-16 23:11:37 +00001062 }
1063 }
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001064
1065#endif /* FT_DEBUG_LEVEL_TRACE */
1066
David Turnerd2b1f351999-12-16 23:11:37 +00001067 FT_TRACE2(( "loaded\n" ));
1068
David Turner49bd4f02000-07-12 16:57:37 +00001069 /* everything went well, update face->num_names */
1070 face->num_names = names->numNameRecords;
1071
David Turnerd2b1f351999-12-16 23:11:37 +00001072 Exit:
1073 return error;
1074 }
1075
1076
1077 /*************************************************************************/
1078 /* */
1079 /* <Function> */
1080 /* TT_Free_Names */
1081 /* */
1082 /* <Description> */
1083 /* Frees the name records. */
1084 /* */
1085 /* <Input> */
1086 /* face :: A handle to the target face object. */
1087 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +00001088 FT_LOCAL_DEF( void )
Werner Lemberg52005c32001-06-27 23:25:46 +00001089 TT_Free_Names( TT_Face face )
David Turnerd2b1f351999-12-16 23:11:37 +00001090 {
David Turnerf0df85b2000-06-22 00:17:42 +00001091 FT_Memory memory = face->root.driver->root.memory;
David Turnerb5713c52002-03-14 11:26:29 +00001092 TT_NameTable names = &face->name_table;
David Turnerd2b1f351999-12-16 23:11:37 +00001093
1094
1095 /* free strings table */
David Turnere459d742002-03-22 13:52:37 +00001096 FT_FREE( names->names );
David Turnerd2b1f351999-12-16 23:11:37 +00001097
1098 /* free strings storage */
David Turnere459d742002-03-22 13:52:37 +00001099 FT_FREE( names->storage );
David Turnerd2b1f351999-12-16 23:11:37 +00001100
1101 names->numNameRecords = 0;
1102 names->format = 0;
1103 names->storageOffset = 0;
1104 }
1105
1106
1107 /*************************************************************************/
1108 /* */
1109 /* <Function> */
1110 /* TT_Load_CMap */
1111 /* */
1112 /* <Description> */
1113 /* Loads the cmap directory in a face object. The cmaps itselves are */
1114 /* loaded on demand in the `ttcmap.c' module. */
1115 /* */
1116 /* <Input> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001117 /* face :: A handle to the target face object. */
1118 /* stream :: A handle to the input stream. */
David Turnerd2b1f351999-12-16 23:11:37 +00001119 /* */
1120 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +00001121 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +00001122 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +00001123 FT_LOCAL_DEF( FT_Error )
Werner Lemberg52005c32001-06-27 23:25:46 +00001124 TT_Load_CMap( TT_Face face,
1125 FT_Stream stream )
David Turnerd2b1f351999-12-16 23:11:37 +00001126 {
David Turnerb5713c52002-03-14 11:26:29 +00001127 FT_Error error;
1128 FT_Memory memory = stream->memory;
1129 FT_Long table_start;
1130 TT_CMapDirRec cmap_dir;
David Turnerd2b1f351999-12-16 23:11:37 +00001131
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001132 const FT_Frame_Field cmap_fields[] =
1133 {
Werner Lemberge72c9fe2000-07-31 18:59:02 +00001134#undef FT_STRUCTURE
David Turnerb5713c52002-03-14 11:26:29 +00001135#define FT_STRUCTURE TT_CMapDirRec
Werner Lemberge72c9fe2000-07-31 18:59:02 +00001136
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001137 FT_FRAME_START( 4 ),
Werner Lemberge72c9fe2000-07-31 18:59:02 +00001138 FT_FRAME_USHORT( tableVersionNumber ),
1139 FT_FRAME_USHORT( numCMaps ),
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001140 FT_FRAME_END
1141 };
David Turnera56489e2000-02-13 13:41:56 +00001142
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001143 const FT_Frame_Field cmap_rec_fields[] =
1144 {
Werner Lemberge72c9fe2000-07-31 18:59:02 +00001145#undef FT_STRUCTURE
David Turnerb5713c52002-03-14 11:26:29 +00001146#define FT_STRUCTURE TT_CMapTableRec
Werner Lemberge72c9fe2000-07-31 18:59:02 +00001147
Werner Lembergbcf8d4b2001-08-24 23:11:34 +00001148 FT_FRAME_START( 4 ),
Werner Lemberge72c9fe2000-07-31 18:59:02 +00001149 FT_FRAME_USHORT( format ),
1150 FT_FRAME_USHORT( length ),
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001151 FT_FRAME_END
1152 };
1153
David Turnera56489e2000-02-13 13:41:56 +00001154
David Turnerd2b1f351999-12-16 23:11:37 +00001155 FT_TRACE2(( "CMaps " ));
1156
1157 error = face->goto_table( face, TTAG_cmap, stream, 0 );
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001158 if ( error )
David Turnerd2b1f351999-12-16 23:11:37 +00001159 {
Werner Lemberg1f7f0e82001-06-06 17:30:41 +00001160 error = SFNT_Err_CMap_Table_Missing;
David Turnerd2b1f351999-12-16 23:11:37 +00001161 goto Exit;
1162 }
1163
David Turner7d3a2642002-03-20 10:49:31 +00001164 table_start = FT_STREAM_POS();
David Turnerd2b1f351999-12-16 23:11:37 +00001165
David Turner7d3a2642002-03-20 10:49:31 +00001166 if ( FT_STREAM_READ_FIELDS( cmap_fields, &cmap_dir ) )
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001167 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +00001168
Werner Lembergfbeb41d2000-07-02 00:27:53 +00001169 /* reserve space in face table for cmap tables */
David Turnere459d742002-03-22 13:52:37 +00001170 if ( FT_NEW_ARRAY( face->charmaps, cmap_dir.numCMaps ) )
David Turnerd2b1f351999-12-16 23:11:37 +00001171 goto Exit;
1172
1173 face->num_charmaps = cmap_dir.numCMaps;
1174 {
1175 TT_CharMap charmap = face->charmaps;
1176 TT_CharMap limit = charmap + face->num_charmaps;
1177
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001178
David Turnera56489e2000-02-13 13:41:56 +00001179 /* read the header of each charmap first */
David Turner7d3a2642002-03-20 10:49:31 +00001180 if ( FT_FRAME_ENTER( face->num_charmaps * 8L ) )
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001181 goto Exit;
1182
David Turnerd2b1f351999-12-16 23:11:37 +00001183 for ( ; charmap < limit; charmap++ )
1184 {
David Turnerb5713c52002-03-14 11:26:29 +00001185 TT_CMapTable cmap;
David Turnerd2b1f351999-12-16 23:11:37 +00001186
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001187
David Turnerd2b1f351999-12-16 23:11:37 +00001188 charmap->root.face = (FT_Face)face;
1189 cmap = &charmap->cmap;
1190
David Turnerd2b1f351999-12-16 23:11:37 +00001191 cmap->loaded = FALSE;
David Turnera890c292002-03-22 12:55:23 +00001192 cmap->platformID = FT_GET_USHORT();
1193 cmap->platformEncodingID = FT_GET_USHORT();
1194 cmap->offset = (FT_ULong)FT_GET_LONG();
David Turnera56489e2000-02-13 13:41:56 +00001195 }
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001196
David Turner7d3a2642002-03-20 10:49:31 +00001197 FT_FRAME_EXIT();
David Turnere49ab252000-05-16 23:44:38 +00001198
David Turnera56489e2000-02-13 13:41:56 +00001199 /* now read the rest of each table */
1200 for ( charmap = face->charmaps; charmap < limit; charmap++ )
1201 {
David Turnerb5713c52002-03-14 11:26:29 +00001202 TT_CMapTable cmap = &charmap->cmap;
David Turnere49ab252000-05-16 23:44:38 +00001203
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001204
David Turner7d3a2642002-03-20 10:49:31 +00001205 if ( FT_STREAM_SEEK( table_start + (FT_Long)cmap->offset ) ||
1206 FT_STREAM_READ_FIELDS( cmap_rec_fields, cmap ) )
David Turnerd2b1f351999-12-16 23:11:37 +00001207 goto Exit;
David Turnere49ab252000-05-16 23:44:38 +00001208
David Turner7d3a2642002-03-20 10:49:31 +00001209 cmap->offset = FT_STREAM_POS();
David Turnerd2b1f351999-12-16 23:11:37 +00001210 }
1211 }
1212
1213 FT_TRACE2(( "loaded\n" ));
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001214
David Turnerd2b1f351999-12-16 23:11:37 +00001215 Exit:
1216 return error;
1217 }
1218
1219
1220 /*************************************************************************/
1221 /* */
1222 /* <Function> */
1223 /* TT_Load_OS2 */
1224 /* */
1225 /* <Description> */
1226 /* Loads the OS2 table. */
1227 /* */
1228 /* <Input> */
1229 /* face :: A handle to the target face object. */
1230 /* stream :: A handle to the input stream. */
1231 /* */
1232 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +00001233 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +00001234 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +00001235 FT_LOCAL_DEF( FT_Error )
Werner Lemberg52005c32001-06-27 23:25:46 +00001236 TT_Load_OS2( TT_Face face,
1237 FT_Stream stream )
David Turnerd2b1f351999-12-16 23:11:37 +00001238 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001239 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +00001240 TT_OS2* os2;
David Turnerb1677a82000-05-29 20:37:41 +00001241
Werner Lemberg36af3ea2001-07-17 12:37:54 +00001242 const FT_Frame_Field os2_fields[] =
1243 {
Werner Lemberge72c9fe2000-07-31 18:59:02 +00001244#undef FT_STRUCTURE
1245#define FT_STRUCTURE TT_OS2
1246
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001247 FT_FRAME_START( 78 ),
Werner Lemberge72c9fe2000-07-31 18:59:02 +00001248 FT_FRAME_USHORT( version ),
1249 FT_FRAME_SHORT ( xAvgCharWidth ),
1250 FT_FRAME_USHORT( usWeightClass ),
1251 FT_FRAME_USHORT( usWidthClass ),
1252 FT_FRAME_SHORT ( fsType ),
1253 FT_FRAME_SHORT ( ySubscriptXSize ),
1254 FT_FRAME_SHORT ( ySubscriptYSize ),
1255 FT_FRAME_SHORT ( ySubscriptXOffset ),
1256 FT_FRAME_SHORT ( ySubscriptYOffset ),
1257 FT_FRAME_SHORT ( ySuperscriptXSize ),
1258 FT_FRAME_SHORT ( ySuperscriptYSize ),
1259 FT_FRAME_SHORT ( ySuperscriptXOffset ),
1260 FT_FRAME_SHORT ( ySuperscriptYOffset ),
1261 FT_FRAME_SHORT ( yStrikeoutSize ),
1262 FT_FRAME_SHORT ( yStrikeoutPosition ),
1263 FT_FRAME_SHORT ( sFamilyClass ),
1264 FT_FRAME_BYTE ( panose[0] ),
1265 FT_FRAME_BYTE ( panose[1] ),
1266 FT_FRAME_BYTE ( panose[2] ),
1267 FT_FRAME_BYTE ( panose[3] ),
1268 FT_FRAME_BYTE ( panose[4] ),
1269 FT_FRAME_BYTE ( panose[5] ),
1270 FT_FRAME_BYTE ( panose[6] ),
1271 FT_FRAME_BYTE ( panose[7] ),
1272 FT_FRAME_BYTE ( panose[8] ),
1273 FT_FRAME_BYTE ( panose[9] ),
1274 FT_FRAME_ULONG ( ulUnicodeRange1 ),
1275 FT_FRAME_ULONG ( ulUnicodeRange2 ),
1276 FT_FRAME_ULONG ( ulUnicodeRange3 ),
1277 FT_FRAME_ULONG ( ulUnicodeRange4 ),
1278 FT_FRAME_BYTE ( achVendID[0] ),
1279 FT_FRAME_BYTE ( achVendID[1] ),
1280 FT_FRAME_BYTE ( achVendID[2] ),
1281 FT_FRAME_BYTE ( achVendID[3] ),
David Turnera56489e2000-02-13 13:41:56 +00001282
Werner Lemberge72c9fe2000-07-31 18:59:02 +00001283 FT_FRAME_USHORT( fsSelection ),
1284 FT_FRAME_USHORT( usFirstCharIndex ),
1285 FT_FRAME_USHORT( usLastCharIndex ),
1286 FT_FRAME_SHORT ( sTypoAscender ),
1287 FT_FRAME_SHORT ( sTypoDescender ),
1288 FT_FRAME_SHORT ( sTypoLineGap ),
1289 FT_FRAME_USHORT( usWinAscent ),
1290 FT_FRAME_USHORT( usWinDescent ),
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001291 FT_FRAME_END
1292 };
David Turnere49ab252000-05-16 23:44:38 +00001293
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001294 const FT_Frame_Field os2_fields_extra[] =
1295 {
1296 FT_FRAME_START( 8 ),
Werner Lemberge72c9fe2000-07-31 18:59:02 +00001297 FT_FRAME_ULONG( ulCodePageRange1 ),
1298 FT_FRAME_ULONG( ulCodePageRange2 ),
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001299 FT_FRAME_END
1300 };
David Turner1119bae2000-05-02 11:01:49 +00001301
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001302 const FT_Frame_Field os2_fields_extra2[] =
1303 {
1304 FT_FRAME_START( 10 ),
Werner Lemberge72c9fe2000-07-31 18:59:02 +00001305 FT_FRAME_SHORT ( sxHeight ),
1306 FT_FRAME_SHORT ( sCapHeight ),
1307 FT_FRAME_USHORT( usDefaultChar ),
1308 FT_FRAME_USHORT( usBreakChar ),
1309 FT_FRAME_USHORT( usMaxContext ),
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001310 FT_FRAME_END
1311 };
1312
David Turnerd2b1f351999-12-16 23:11:37 +00001313
1314 FT_TRACE2(( "OS/2 Table " ));
1315
1316 /* We now support old Mac fonts where the OS/2 table doesn't */
1317 /* exist. Simply put, we set the `version' field to 0xFFFF */
1318 /* and test this value each time we need to access the table. */
1319 error = face->goto_table( face, TTAG_OS2, stream, 0 );
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001320 if ( error )
David Turnerd2b1f351999-12-16 23:11:37 +00001321 {
Werner Lembergfbeb41d2000-07-02 00:27:53 +00001322 FT_TRACE2(( "is missing!\n" ));
David Turnerd2b1f351999-12-16 23:11:37 +00001323 face->os2.version = 0xFFFF;
Werner Lemberg1f7f0e82001-06-06 17:30:41 +00001324 error = SFNT_Err_Ok;
David Turnerd2b1f351999-12-16 23:11:37 +00001325 goto Exit;
1326 }
1327
David Turnera56489e2000-02-13 13:41:56 +00001328 os2 = &face->os2;
1329
David Turner7d3a2642002-03-20 10:49:31 +00001330 if ( FT_STREAM_READ_FIELDS( os2_fields, os2 ) )
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001331 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +00001332
1333 os2->ulCodePageRange1 = 0;
1334 os2->ulCodePageRange2 = 0;
Werner Lemberg36af3ea2001-07-17 12:37:54 +00001335 os2->sxHeight = 0;
1336 os2->sCapHeight = 0;
1337 os2->usDefaultChar = 0;
1338 os2->usBreakChar = 0;
1339 os2->usMaxContext = 0;
David Turnerd2b1f351999-12-16 23:11:37 +00001340
1341 if ( os2->version >= 0x0001 )
1342 {
1343 /* only version 1 tables */
David Turner7d3a2642002-03-20 10:49:31 +00001344 if ( FT_STREAM_READ_FIELDS( os2_fields_extra, os2 ) )
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001345 goto Exit;
David Turner1119bae2000-05-02 11:01:49 +00001346
1347 if ( os2->version >= 0x0002 )
1348 {
1349 /* only version 2 tables */
David Turner7d3a2642002-03-20 10:49:31 +00001350 if ( FT_STREAM_READ_FIELDS( os2_fields_extra2, os2 ) )
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001351 goto Exit;
David Turner1119bae2000-05-02 11:01:49 +00001352 }
David Turnerd2b1f351999-12-16 23:11:37 +00001353 }
1354
1355 FT_TRACE2(( "loaded\n" ));
1356
1357 Exit:
1358 return error;
1359 }
1360
1361
1362 /*************************************************************************/
1363 /* */
1364 /* <Function> */
1365 /* TT_Load_Postscript */
1366 /* */
1367 /* <Description> */
1368 /* Loads the Postscript table. */
1369 /* */
1370 /* <Input> */
1371 /* face :: A handle to the target face object. */
1372 /* stream :: A handle to the input stream. */
1373 /* */
1374 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +00001375 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +00001376 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +00001377 FT_LOCAL_DEF( FT_Error )
Werner Lemberg52005c32001-06-27 23:25:46 +00001378 TT_Load_PostScript( TT_Face face,
1379 FT_Stream stream )
David Turnerd2b1f351999-12-16 23:11:37 +00001380 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001381 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +00001382 TT_Postscript* post = &face->postscript;
David Turnerb1677a82000-05-29 20:37:41 +00001383
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001384 static const FT_Frame_Field post_fields[] =
1385 {
Werner Lemberge72c9fe2000-07-31 18:59:02 +00001386#undef FT_STRUCTURE
1387#define FT_STRUCTURE TT_Postscript
1388
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001389 FT_FRAME_START( 32 ),
Werner Lemberge72c9fe2000-07-31 18:59:02 +00001390 FT_FRAME_ULONG( FormatType ),
1391 FT_FRAME_ULONG( italicAngle ),
1392 FT_FRAME_SHORT( underlinePosition ),
1393 FT_FRAME_SHORT( underlineThickness ),
1394 FT_FRAME_ULONG( isFixedPitch ),
1395 FT_FRAME_ULONG( minMemType42 ),
1396 FT_FRAME_ULONG( maxMemType42 ),
1397 FT_FRAME_ULONG( minMemType1 ),
1398 FT_FRAME_ULONG( maxMemType1 ),
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001399 FT_FRAME_END
1400 };
1401
David Turnerd2b1f351999-12-16 23:11:37 +00001402
1403 FT_TRACE2(( "PostScript " ));
1404
1405 error = face->goto_table( face, TTAG_post, stream, 0 );
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001406 if ( error )
Werner Lemberg1f7f0e82001-06-06 17:30:41 +00001407 return SFNT_Err_Post_Table_Missing;
David Turnerd2b1f351999-12-16 23:11:37 +00001408
David Turner7d3a2642002-03-20 10:49:31 +00001409 if ( FT_STREAM_READ_FIELDS( post_fields, post ) )
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001410 return error;
David Turnerd2b1f351999-12-16 23:11:37 +00001411
David Turnerd2b1f351999-12-16 23:11:37 +00001412 /* we don't load the glyph names, we do that in another */
1413 /* module (ttpost). */
1414 FT_TRACE2(( "loaded\n" ));
1415
Werner Lemberg1f7f0e82001-06-06 17:30:41 +00001416 return SFNT_Err_Ok;
David Turnerd2b1f351999-12-16 23:11:37 +00001417 }
1418
1419
1420 /*************************************************************************/
1421 /* */
1422 /* <Function> */
David Turner51179f02000-05-18 16:18:05 +00001423 /* TT_Load_PCLT */
1424 /* */
1425 /* <Description> */
1426 /* Loads the PCL 5 Table. */
1427 /* */
1428 /* <Input> */
1429 /* face :: A handle to the target face object. */
1430 /* stream :: A handle to the input stream. */
1431 /* */
1432 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +00001433 /* FreeType error code. 0 means success. */
David Turner51179f02000-05-18 16:18:05 +00001434 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +00001435 FT_LOCAL_DEF( FT_Error )
Werner Lemberg52005c32001-06-27 23:25:46 +00001436 TT_Load_PCLT( TT_Face face,
1437 FT_Stream stream )
David Turner51179f02000-05-18 16:18:05 +00001438 {
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001439 static const FT_Frame_Field pclt_fields[] =
1440 {
Werner Lemberge72c9fe2000-07-31 18:59:02 +00001441#undef FT_STRUCTURE
1442#define FT_STRUCTURE TT_PCLT
1443
David Turnerd18388e2000-07-03 15:00:49 +00001444 FT_FRAME_START( 54 ),
Werner Lemberge72c9fe2000-07-31 18:59:02 +00001445 FT_FRAME_ULONG ( Version ),
1446 FT_FRAME_ULONG ( FontNumber ),
1447 FT_FRAME_USHORT( Pitch ),
1448 FT_FRAME_USHORT( xHeight ),
1449 FT_FRAME_USHORT( Style ),
1450 FT_FRAME_USHORT( TypeFamily ),
1451 FT_FRAME_USHORT( CapHeight ),
1452 FT_FRAME_BYTES ( TypeFace, 16 ),
1453 FT_FRAME_BYTES ( CharacterComplement, 8 ),
1454 FT_FRAME_BYTES ( FileName, 6 ),
1455 FT_FRAME_CHAR ( StrokeWeight ),
1456 FT_FRAME_CHAR ( WidthType ),
1457 FT_FRAME_BYTE ( SerifStyle ),
1458 FT_FRAME_BYTE ( Reserved ),
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001459 FT_FRAME_END
1460 };
Werner Lemberg920d41e2000-06-05 14:32:32 +00001461
David Turnerf9b8dec2000-06-16 19:34:52 +00001462 FT_Error error;
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001463 TT_PCLT* pclt = &face->pclt;
1464
Werner Lemberg920d41e2000-06-05 14:32:32 +00001465
David Turner51179f02000-05-18 16:18:05 +00001466 FT_TRACE2(( "PCLT " ));
1467
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001468 /* optional table */
1469 error = face->goto_table( face, TTAG_PCLT, stream, 0 );
1470 if ( error )
1471 {
1472 FT_TRACE2(( "missing (optional)\n" ));
1473 pclt->Version = 0;
Werner Lemberg1f7f0e82001-06-06 17:30:41 +00001474 return SFNT_Err_Ok;
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001475 }
Werner Lemberg920d41e2000-06-05 14:32:32 +00001476
David Turner7d3a2642002-03-20 10:49:31 +00001477 if ( FT_STREAM_READ_FIELDS( pclt_fields, pclt ) )
David Turner51179f02000-05-18 16:18:05 +00001478 goto Exit;
Werner Lemberg920d41e2000-06-05 14:32:32 +00001479
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001480 FT_TRACE2(( "loaded\n" ));
1481
Werner Lemberg920d41e2000-06-05 14:32:32 +00001482 Exit:
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001483 return error;
1484 }
1485
David Turner51179f02000-05-18 16:18:05 +00001486
1487 /*************************************************************************/
1488 /* */
1489 /* <Function> */
David Turnerd2b1f351999-12-16 23:11:37 +00001490 /* TT_Load_Gasp */
1491 /* */
1492 /* <Description> */
Werner Lembergfbeb41d2000-07-02 00:27:53 +00001493 /* Loads the `gasp' table into a face object. */
David Turnerd2b1f351999-12-16 23:11:37 +00001494 /* */
1495 /* <Input> */
1496 /* face :: A handle to the target face object. */
1497 /* stream :: The input stream. */
1498 /* */
1499 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +00001500 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +00001501 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +00001502 FT_LOCAL_DEF( FT_Error )
Werner Lemberg52005c32001-06-27 23:25:46 +00001503 TT_Load_Gasp( TT_Face face,
1504 FT_Stream stream )
David Turnerd2b1f351999-12-16 23:11:37 +00001505 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001506 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +00001507 FT_Memory memory = stream->memory;
1508
David Turnerf9b8dec2000-06-16 19:34:52 +00001509 FT_UInt j,num_ranges;
David Turnerb5713c52002-03-14 11:26:29 +00001510 TT_GaspRange gaspranges;
David Turnerd2b1f351999-12-16 23:11:37 +00001511
1512
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001513 FT_TRACE2(( "TT_Load_Gasp: %08p\n", face ));
David Turnerd2b1f351999-12-16 23:11:37 +00001514
1515 /* the gasp table is optional */
1516 error = face->goto_table( face, TTAG_gasp, stream, 0 );
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001517 if ( error )
Werner Lemberg1f7f0e82001-06-06 17:30:41 +00001518 return SFNT_Err_Ok;
David Turnerd2b1f351999-12-16 23:11:37 +00001519
David Turner7d3a2642002-03-20 10:49:31 +00001520 if ( FT_FRAME_ENTER( 4L ) )
David Turnerd2b1f351999-12-16 23:11:37 +00001521 goto Exit;
1522
David Turnera890c292002-03-22 12:55:23 +00001523 face->gasp.version = FT_GET_USHORT();
1524 face->gasp.numRanges = FT_GET_USHORT();
David Turnerd2b1f351999-12-16 23:11:37 +00001525
David Turner7d3a2642002-03-20 10:49:31 +00001526 FT_FRAME_EXIT();
David Turnerd2b1f351999-12-16 23:11:37 +00001527
1528 num_ranges = face->gasp.numRanges;
1529 FT_TRACE3(( "number of ranges = %d\n", num_ranges ));
1530
David Turnere459d742002-03-22 13:52:37 +00001531 if ( FT_NEW_ARRAY( gaspranges, num_ranges ) ||
1532 FT_FRAME_ENTER( num_ranges * 4L ) )
David Turnerd2b1f351999-12-16 23:11:37 +00001533 goto Exit;
1534
1535 face->gasp.gaspRanges = gaspranges;
1536
1537 for ( j = 0; j < num_ranges; j++ )
1538 {
David Turnera890c292002-03-22 12:55:23 +00001539 gaspranges[j].maxPPEM = FT_GET_USHORT();
1540 gaspranges[j].gaspFlag = FT_GET_USHORT();
David Turnerd2b1f351999-12-16 23:11:37 +00001541
1542 FT_TRACE3(( " [max:%d flag:%d]",
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001543 gaspranges[j].maxPPEM,
1544 gaspranges[j].gaspFlag ));
David Turnerd2b1f351999-12-16 23:11:37 +00001545 }
1546 FT_TRACE3(( "\n" ));
1547
David Turner7d3a2642002-03-20 10:49:31 +00001548 FT_FRAME_EXIT();
David Turnerd2b1f351999-12-16 23:11:37 +00001549 FT_TRACE2(( "GASP loaded\n" ));
1550
1551 Exit:
1552 return error;
1553 }
1554
1555
Werner Lemberg52005c32001-06-27 23:25:46 +00001556 FT_CALLBACK_DEF( int )
1557 tt_kern_pair_compare( const void* a,
1558 const void* b );
1559
1560
David Turnerd2b1f351999-12-16 23:11:37 +00001561 /*************************************************************************/
1562 /* */
1563 /* <Function> */
1564 /* TT_Load_Kern */
1565 /* */
1566 /* <Description> */
1567 /* Loads the first kerning table with format 0 in the font. Only */
1568 /* accepts the first horizontal kerning table. Developers should use */
1569 /* the `ftxkern' extension to access other kerning tables in the font */
1570 /* file, if they really want to. */
1571 /* */
1572 /* <Input> */
1573 /* face :: A handle to the target face object. */
1574 /* stream :: The input stream. */
1575 /* */
1576 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +00001577 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +00001578 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +00001579 FT_LOCAL_DEF( FT_Error )
Werner Lemberg52005c32001-06-27 23:25:46 +00001580 TT_Load_Kern( TT_Face face,
1581 FT_Stream stream )
David Turnerd2b1f351999-12-16 23:11:37 +00001582 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001583 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +00001584 FT_Memory memory = stream->memory;
1585
Werner Lembergcf24d512001-06-18 14:23:45 +00001586 FT_UInt n, num_tables;
David Turnerd2b1f351999-12-16 23:11:37 +00001587
David Turnerd2b1f351999-12-16 23:11:37 +00001588
Werner Lembergfbeb41d2000-07-02 00:27:53 +00001589 /* the kern table is optional; exit silently if it is missing */
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001590 error = face->goto_table( face, TTAG_kern, stream, 0 );
1591 if ( error )
Werner Lemberg1f7f0e82001-06-06 17:30:41 +00001592 return SFNT_Err_Ok;
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001593
David Turner7d3a2642002-03-20 10:49:31 +00001594 if ( FT_FRAME_ENTER( 4L ) )
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001595 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +00001596
David Turnera890c292002-03-22 12:55:23 +00001597 (void)FT_GET_USHORT(); /* version */
1598 num_tables = FT_GET_USHORT();
David Turnerd2b1f351999-12-16 23:11:37 +00001599
David Turner7d3a2642002-03-20 10:49:31 +00001600 FT_FRAME_EXIT();
David Turnerd2b1f351999-12-16 23:11:37 +00001601
1602 for ( n = 0; n < num_tables; n++ )
1603 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001604 FT_UInt coverage;
1605 FT_UInt length;
David Turnerd2b1f351999-12-16 23:11:37 +00001606
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001607
David Turner7d3a2642002-03-20 10:49:31 +00001608 if ( FT_FRAME_ENTER( 6L ) )
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001609 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +00001610
David Turnera890c292002-03-22 12:55:23 +00001611 (void)FT_GET_USHORT(); /* version */
1612 length = FT_GET_USHORT() - 6; /* substract header length */
1613 coverage = FT_GET_USHORT();
David Turnerd2b1f351999-12-16 23:11:37 +00001614
David Turner7d3a2642002-03-20 10:49:31 +00001615 FT_FRAME_EXIT();
David Turnere49ab252000-05-16 23:44:38 +00001616
David Turnerd2b1f351999-12-16 23:11:37 +00001617 if ( coverage == 0x0001 )
1618 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001619 FT_UInt num_pairs;
David Turnerb5713c52002-03-14 11:26:29 +00001620 TT_Kern0_Pair pair;
1621 TT_Kern0_Pair limit;
David Turnerd2b1f351999-12-16 23:11:37 +00001622
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001623
1624 /* found a horizontal format 0 kerning table! */
David Turner7d3a2642002-03-20 10:49:31 +00001625 if ( FT_FRAME_ENTER( 8L ) )
David Turnerd2b1f351999-12-16 23:11:37 +00001626 goto Exit;
1627
David Turnera890c292002-03-22 12:55:23 +00001628 num_pairs = FT_GET_USHORT();
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001629
David Turnerd2b1f351999-12-16 23:11:37 +00001630 /* skip the rest */
1631
David Turner7d3a2642002-03-20 10:49:31 +00001632 FT_FRAME_EXIT();
David Turnerd2b1f351999-12-16 23:11:37 +00001633
1634 /* allocate array of kerning pairs */
David Turnere459d742002-03-22 13:52:37 +00001635 if ( FT_NEW_ARRAY( face->kern_pairs, num_pairs ) ||
1636 FT_FRAME_ENTER( 6L * num_pairs ) )
David Turnerd2b1f351999-12-16 23:11:37 +00001637 goto Exit;
1638
1639 pair = face->kern_pairs;
1640 limit = pair + num_pairs;
1641 for ( ; pair < limit; pair++ )
1642 {
David Turnera890c292002-03-22 12:55:23 +00001643 pair->left = FT_GET_USHORT();
1644 pair->right = FT_GET_USHORT();
1645 pair->value = FT_GET_USHORT();
David Turnerd2b1f351999-12-16 23:11:37 +00001646 }
1647
David Turner7d3a2642002-03-20 10:49:31 +00001648 FT_FRAME_EXIT();
David Turnerd2b1f351999-12-16 23:11:37 +00001649
1650 face->num_kern_pairs = num_pairs;
1651 face->kern_table_index = n;
Werner Lemberg415235d2001-06-28 17:49:10 +00001652
David Turner9a554eb2001-06-27 12:40:46 +00001653 /* ensure that the kerning pair table is sorted (yes, some */
Werner Lembergf814d0f2001-06-27 16:18:10 +00001654 /* fonts have unsorted tables!) */
David Turner9a554eb2001-06-27 12:40:46 +00001655 {
1656 FT_UInt i;
David Turnerb5713c52002-03-14 11:26:29 +00001657 TT_Kern0_Pair pair0;
Werner Lemberg415235d2001-06-28 17:49:10 +00001658
David Turner9a554eb2001-06-27 12:40:46 +00001659
Werner Lembergf814d0f2001-06-27 16:18:10 +00001660 pair0 = face->kern_pairs;
1661
1662 for ( i = 1; i < num_pairs; i++, pair0++ )
David Turner9a554eb2001-06-27 12:40:46 +00001663 {
Werner Lembergf814d0f2001-06-27 16:18:10 +00001664 if ( tt_kern_pair_compare( pair0, pair0 + 1 ) != -1 )
David Turner9a554eb2001-06-27 12:40:46 +00001665 {
1666 qsort( (void*)face->kern_pairs, (int)num_pairs,
David Turnerb5713c52002-03-14 11:26:29 +00001667 sizeof ( TT_Kern0_PairRec ), tt_kern_pair_compare );
David Turner9a554eb2001-06-27 12:40:46 +00001668 break;
1669 }
1670 }
1671 }
Werner Lemberg415235d2001-06-28 17:49:10 +00001672
David Turnerd2b1f351999-12-16 23:11:37 +00001673 goto Exit;
1674 }
David Turnere49ab252000-05-16 23:44:38 +00001675
David Turner7d3a2642002-03-20 10:49:31 +00001676 if ( FT_STREAM_SKIP( length ) )
David Turnerd2b1f351999-12-16 23:11:37 +00001677 goto Exit;
1678 }
1679
1680 /* no kern table found -- doesn't matter */
1681 face->kern_table_index = -1;
1682 face->num_kern_pairs = 0;
1683 face->kern_pairs = NULL;
1684
1685 Exit:
1686 return error;
1687 }
1688
Werner Lembergf814d0f2001-06-27 16:18:10 +00001689
David Turner9a554eb2001-06-27 12:40:46 +00001690#undef TT_KERN_INDEX
Werner Lembergf814d0f2001-06-27 16:18:10 +00001691#define TT_KERN_INDEX( g1, g2 ) ( ( (FT_ULong)g1 << 16 ) | g2 )
David Turner9a554eb2001-06-27 12:40:46 +00001692
Werner Lemberg52005c32001-06-27 23:25:46 +00001693 FT_CALLBACK_DEF( int )
Werner Lembergf814d0f2001-06-27 16:18:10 +00001694 tt_kern_pair_compare( const void* a,
1695 const void* b )
David Turner9a554eb2001-06-27 12:40:46 +00001696 {
David Turnerb5713c52002-03-14 11:26:29 +00001697 TT_Kern0_Pair pair1 = (TT_Kern0_Pair)a;
1698 TT_Kern0_Pair pair2 = (TT_Kern0_Pair)b;
David Turner9a554eb2001-06-27 12:40:46 +00001699
1700 FT_ULong index1 = TT_KERN_INDEX( pair1->left, pair1->right );
1701 FT_ULong index2 = TT_KERN_INDEX( pair2->left, pair2->right );
1702
Werner Lembergf814d0f2001-06-27 16:18:10 +00001703
David Turner9a554eb2001-06-27 12:40:46 +00001704 return ( index1 < index2 ? -1 :
1705 ( index1 > index2 ? 1 : 0 ));
1706 }
1707
1708#undef TT_KERN_INDEX
David Turnerd2b1f351999-12-16 23:11:37 +00001709
Werner Lembergf814d0f2001-06-27 16:18:10 +00001710
David Turnerd2b1f351999-12-16 23:11:37 +00001711 /*************************************************************************/
1712 /* */
1713 /* <Function> */
1714 /* TT_Load_Hdmx */
1715 /* */
1716 /* <Description> */
1717 /* Loads the horizontal device metrics table. */
1718 /* */
1719 /* <Input> */
1720 /* face :: A handle to the target face object. */
1721 /* stream :: A handle to the input stream. */
1722 /* */
1723 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +00001724 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +00001725 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +00001726 FT_LOCAL_DEF( FT_Error )
Werner Lemberg52005c32001-06-27 23:25:46 +00001727 TT_Load_Hdmx( TT_Face face,
1728 FT_Stream stream )
David Turnerd2b1f351999-12-16 23:11:37 +00001729 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001730 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +00001731 FT_Memory memory = stream->memory;
1732
David Turnerb5713c52002-03-14 11:26:29 +00001733 TT_Hdmx hdmx = &face->hdmx;
David Turnerf9b8dec2000-06-16 19:34:52 +00001734 FT_Long num_glyphs;
1735 FT_Long record_size;
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001736
David Turnerd2b1f351999-12-16 23:11:37 +00001737
1738 hdmx->version = 0;
1739 hdmx->num_records = 0;
1740 hdmx->records = 0;
1741
1742 /* this table is optional */
1743 error = face->goto_table( face, TTAG_hdmx, stream, 0 );
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001744 if ( error )
Werner Lemberg1f7f0e82001-06-06 17:30:41 +00001745 return SFNT_Err_Ok;
David Turnerd2b1f351999-12-16 23:11:37 +00001746
David Turner7d3a2642002-03-20 10:49:31 +00001747 if ( FT_FRAME_ENTER( 8L ) )
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001748 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +00001749
David Turnera890c292002-03-22 12:55:23 +00001750 hdmx->version = FT_GET_USHORT();
1751 hdmx->num_records = FT_GET_SHORT();
1752 record_size = FT_GET_LONG();
David Turnerd2b1f351999-12-16 23:11:37 +00001753
David Turner7d3a2642002-03-20 10:49:31 +00001754 FT_FRAME_EXIT();
David Turnerd2b1f351999-12-16 23:11:37 +00001755
1756 /* Only recognize format 0 */
1757 if ( hdmx->version != 0 )
1758 goto Exit;
1759
David Turnere459d742002-03-22 13:52:37 +00001760 if ( FT_NEW_ARRAY( hdmx->records, hdmx->num_records ) )
David Turnerd2b1f351999-12-16 23:11:37 +00001761 goto Exit;
1762
1763 num_glyphs = face->root.num_glyphs;
1764 record_size -= num_glyphs + 2;
1765
1766 {
David Turnerb5713c52002-03-14 11:26:29 +00001767 TT_HdmxEntry cur = hdmx->records;
1768 TT_HdmxEntry limit = cur + hdmx->num_records;
David Turnerd2b1f351999-12-16 23:11:37 +00001769
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001770
David Turnerd2b1f351999-12-16 23:11:37 +00001771 for ( ; cur < limit; cur++ )
1772 {
1773 /* read record */
David Turnera890c292002-03-22 12:55:23 +00001774 if ( FT_READ_BYTE( cur->ppem ) ||
1775 FT_READ_BYTE( cur->max_width ) )
David Turnerd2b1f351999-12-16 23:11:37 +00001776 goto Exit;
David Turnere49ab252000-05-16 23:44:38 +00001777
David Turnere459d742002-03-22 13:52:37 +00001778 if ( FT_ALLOC( cur->widths, num_glyphs ) ||
David Turner7d3a2642002-03-20 10:49:31 +00001779 FT_STREAM_READ( cur->widths, num_glyphs ) )
David Turnerd2b1f351999-12-16 23:11:37 +00001780 goto Exit;
David Turnere49ab252000-05-16 23:44:38 +00001781
David Turnerd2b1f351999-12-16 23:11:37 +00001782 /* skip padding bytes */
David Turner7d3a2642002-03-20 10:49:31 +00001783 if ( record_size > 0 && FT_STREAM_SKIP( record_size ) )
David Turnerd2b1f351999-12-16 23:11:37 +00001784 goto Exit;
1785 }
1786 }
1787
1788 Exit:
1789 return error;
1790 }
1791
1792
1793 /*************************************************************************/
1794 /* */
1795 /* <Function> */
1796 /* TT_Free_Hdmx */
1797 /* */
1798 /* <Description> */
1799 /* Frees the horizontal device metrics table. */
1800 /* */
1801 /* <Input> */
1802 /* face :: A handle to the target face object. */
1803 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +00001804 FT_LOCAL_DEF( void )
Werner Lemberg52005c32001-06-27 23:25:46 +00001805 TT_Free_Hdmx( TT_Face face )
David Turnerd2b1f351999-12-16 23:11:37 +00001806 {
1807 if ( face )
1808 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001809 FT_Int n;
David Turnerf0df85b2000-06-22 00:17:42 +00001810 FT_Memory memory = face->root.driver->root.memory;
David Turnerd2b1f351999-12-16 23:11:37 +00001811
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001812
David Turnerd2b1f351999-12-16 23:11:37 +00001813 for ( n = 0; n < face->hdmx.num_records; n++ )
David Turnere459d742002-03-22 13:52:37 +00001814 FT_FREE( face->hdmx.records[n].widths );
David Turnerd2b1f351999-12-16 23:11:37 +00001815
David Turnere459d742002-03-22 13:52:37 +00001816 FT_FREE( face->hdmx.records );
David Turnerd2b1f351999-12-16 23:11:37 +00001817 face->hdmx.num_records = 0;
1818 }
1819 }
1820
1821
1822/* END */