blob: 4355bed8900cd932f5f50241dcaf814f309271ba [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 Lemberg4e6dd852000-06-05 05:26:15 +00008/* Copyright 1996-2000 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
19
David Turnerefce08d2000-05-11 18:23:52 +000020#include <freetype/internal/ftdebug.h>
21#include <freetype/internal/tterrors.h>
22#include <freetype/tttags.h>
David Turnerd2b1f351999-12-16 23:11:37 +000023
24#include <ttload.h>
David Turnerd2b1f351999-12-16 23:11:37 +000025#include <ttcmap.h>
David Turnerd2b1f351999-12-16 23:11:37 +000026
David Turnerd2b1f351999-12-16 23:11:37 +000027
Werner Lemberg4e6dd852000-06-05 05:26:15 +000028 /*************************************************************************/
29 /* */
30 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
31 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
32 /* messages during execution. */
33 /* */
34#undef FT_COMPONENT
35#define FT_COMPONENT trace_ttload
David Turnera56489e2000-02-13 13:41:56 +000036
David Turnerd2b1f351999-12-16 23:11:37 +000037
38 /*************************************************************************/
39 /* */
40 /* <Function> */
41 /* TT_LookUp_Table */
42 /* */
43 /* <Description> */
44 /* Looks for a TrueType table by name. */
45 /* */
46 /* <Input> */
47 /* face :: A face object handle. */
Werner Lemberg4e6dd852000-06-05 05:26:15 +000048 /* tag :: The searched tag. */
David Turnerd2b1f351999-12-16 23:11:37 +000049 /* */
50 /* <Return> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +000051 /* A pointer to the table directory entry. 0 if not found. */
David Turnerd2b1f351999-12-16 23:11:37 +000052 /* */
David Turnerbfe2f982000-05-12 12:17:15 +000053 LOCAL_FUNC
David Turnerd2b1f351999-12-16 23:11:37 +000054 TT_Table* TT_LookUp_Table( TT_Face face,
55 TT_ULong tag )
56 {
57 TT_Table* entry;
58 TT_Table* limit;
David Turnere49ab252000-05-16 23:44:38 +000059
Werner Lemberg4e6dd852000-06-05 05:26:15 +000060
61 FT_TRACE3(( "TT_LookUp_Table: %08p, `%c%c%c%c' )\n",
David Turner51179f02000-05-18 16:18:05 +000062 face,
Werner Lemberg4e6dd852000-06-05 05:26:15 +000063 (TT_Char)( tag >> 24 ),
64 (TT_Char)( tag >> 16 ),
65 (TT_Char)( tag >> 8 ),
66 (TT_Char)( tag ) ));
David Turnerd2b1f351999-12-16 23:11:37 +000067
68 entry = face->dir_tables;
69 limit = entry + face->num_tables;
Werner Lemberg4e6dd852000-06-05 05:26:15 +000070
David Turnerd2b1f351999-12-16 23:11:37 +000071 for ( ; entry < limit; entry++ )
72 {
73 if ( entry->Tag == tag )
74 return entry;
David Turnere49ab252000-05-16 23:44:38 +000075 }
Werner Lemberg4e6dd852000-06-05 05:26:15 +000076
77 FT_TRACE3(( " Could not find table!\n" ));
David Turnerd2b1f351999-12-16 23:11:37 +000078 return 0;
79 }
80
Werner Lemberg4e6dd852000-06-05 05:26:15 +000081
David Turnerd2b1f351999-12-16 23:11:37 +000082 /*************************************************************************/
83 /* */
84 /* <Function> */
85 /* TT_Goto_Table */
86 /* */
87 /* <Description> */
88 /* Looks for a TrueType table by name, then seek a stream to it. */
89 /* */
90 /* <Input> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +000091 /* face :: A face object handle. */
92 /* tag :: The searched tag. */
93 /* stream :: The stream to seek when the table is found. */
94 /* */
95 /* <Output> */
96 /* length :: The length of the table if found, undefined otherwise. */
David Turnerd2b1f351999-12-16 23:11:37 +000097 /* */
98 /* <Return> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +000099 /* TrueType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +0000100 /* */
David Turnerbfe2f982000-05-12 12:17:15 +0000101 LOCAL_FUNC
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000102 TT_Error TT_Goto_Table( TT_Face face,
103 TT_ULong tag,
104 FT_Stream stream,
105 TT_ULong* length )
David Turnerd2b1f351999-12-16 23:11:37 +0000106 {
107 TT_Table* table;
108 TT_Error error;
David Turnere49ab252000-05-16 23:44:38 +0000109
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000110
David Turnerd2b1f351999-12-16 23:11:37 +0000111 table = TT_LookUp_Table( face, tag );
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000112 if ( table )
David Turnerd2b1f351999-12-16 23:11:37 +0000113 {
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000114 if ( length )
David Turnerd2b1f351999-12-16 23:11:37 +0000115 *length = table->Length;
David Turnere49ab252000-05-16 23:44:38 +0000116
David Turnerd2b1f351999-12-16 23:11:37 +0000117 (void)FILE_Seek( table->Offset );
118 }
119 else
120 error = TT_Err_Table_Missing;
David Turnere49ab252000-05-16 23:44:38 +0000121
David Turnerd2b1f351999-12-16 23:11:37 +0000122 return error;
123 }
124
125
126 /*************************************************************************/
127 /* */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000128 /* <Function> */
David Turnerb1677a82000-05-29 20:37:41 +0000129 /* TT_Load_SFNT_Header */
David Turnerd2b1f351999-12-16 23:11:37 +0000130 /* */
131 /* <Description> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000132 /* Loads the header of a SFNT font file. Supports collections. */
David Turnerd2b1f351999-12-16 23:11:37 +0000133 /* */
134 /* <Input> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000135 /* face :: A handle to the target face object. */
136 /* stream :: The input stream. */
137 /* face_index :: If the font is a collection, the number of the font */
138 /* in the collection, ignored otherwise. */
David Turnerb1677a82000-05-29 20:37:41 +0000139 /* */
David Turnerd42c68e2000-01-27 13:56:02 +0000140 /* <Output> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000141 /* sfnt :: The SFNT header. */
David Turnerd2b1f351999-12-16 23:11:37 +0000142 /* */
143 /* <Return> */
144 /* TrueType error code. 0 means success. */
145 /* */
146 /* <Note> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000147 /* The stream cursor must be at the font file's origin. */
David Turnerd2b1f351999-12-16 23:11:37 +0000148 /* */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000149 /* This function recognizes fonts embedded in a `TrueType collection' */
150 /* */
151 /* The header will be checked whether it is valid by looking at the */
152 /* values of `search_range', `entry_selector', and `range_shift'. */
David Turnerb1677a82000-05-29 20:37:41 +0000153 /* */
David Turnerd2b1f351999-12-16 23:11:37 +0000154 LOCAL_FUNC
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000155 TT_Error TT_Load_SFNT_Header( TT_Face face,
156 FT_Stream stream,
157 TT_Long face_index,
158 SFNT_Header* sfnt )
David Turnerd2b1f351999-12-16 23:11:37 +0000159 {
David Turnerb1677a82000-05-29 20:37:41 +0000160 TT_Error error;
161 TT_ULong format_tag;
162 FT_Memory memory = stream->memory;
Werner Lemberg920d41e2000-06-05 14:32:32 +0000163
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000164 const FT_Frame_Field sfnt_header_fields[] =
165 {
166 FT_FRAME_START( 8 ),
167 FT_FRAME_USHORT( SFNT_Header, num_tables ),
168 FT_FRAME_USHORT( SFNT_Header, search_range ),
169 FT_FRAME_USHORT( SFNT_Header, entry_selector ),
170 FT_FRAME_USHORT( SFNT_Header, range_shift ),
171 FT_FRAME_END
172 };
Werner Lemberg920d41e2000-06-05 14:32:32 +0000173
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000174 const FT_Frame_Field ttc_header_fields[] =
175 {
176 FT_FRAME_START( 8 ),
177 FT_FRAME_LONG( TTC_Header, version ),
178 FT_FRAME_LONG( TTC_Header, DirCount ),
179 FT_FRAME_END };
David Turnerd2b1f351999-12-16 23:11:37 +0000180
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000181
182 FT_TRACE2(( "TT_Load_SFNT_Header: %08p, %ld\n",
David Turner3581d062000-06-01 03:26:58 +0000183 face, face_index ));
David Turnerd2b1f351999-12-16 23:11:37 +0000184
185 face->ttc_header.Tag = 0;
186 face->ttc_header.version = 0;
187 face->ttc_header.DirCount = 0;
188
189 face->num_tables = 0;
190
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000191 /* first of all, read the first 4 bytes. If it's `ttcf', then the */
David Turnerd42c68e2000-01-27 13:56:02 +0000192 /* file is a TrueType collection, otherwise it can be any other */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000193 /* kind of font. */
194 if ( READ_ULong( format_tag ) )
195 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +0000196
David Turnerb1677a82000-05-29 20:37:41 +0000197 if ( format_tag == TTAG_ttcf )
David Turnerd2b1f351999-12-16 23:11:37 +0000198 {
199 TT_Int n;
David Turnere49ab252000-05-16 23:44:38 +0000200
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000201
202 FT_TRACE3(( "TT_Load_SFNT_Header: file is a collection\n" ));
David Turnere49ab252000-05-16 23:44:38 +0000203
David Turnerd2b1f351999-12-16 23:11:37 +0000204 /* it's a TrueType collection, i.e. a file containing several */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000205 /* font files. Read the font directory now */
David Turnera56489e2000-02-13 13:41:56 +0000206 if ( READ_Fields( ttc_header_fields, &face->ttc_header ) )
207 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +0000208
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000209 /* now read the offsets of each font in the file */
David Turnerd2b1f351999-12-16 23:11:37 +0000210 if ( ALLOC_ARRAY( face->ttc_header.TableDirectory,
211 face->ttc_header.DirCount,
212 TT_ULong ) ||
213 ACCESS_Frame( face->ttc_header.DirCount * 4L ) )
214 goto Exit;
215
216 for ( n = 0; n < face->ttc_header.DirCount; n++ )
217 face->ttc_header.TableDirectory[n] = GET_ULong();
218
219 FORGET_Frame();
220
221 /* check face index */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000222 if ( face_index >= face->ttc_header.DirCount )
David Turnerd2b1f351999-12-16 23:11:37 +0000223 {
224 error = TT_Err_Bad_Argument;
225 goto Exit;
David Turnere49ab252000-05-16 23:44:38 +0000226 }
227
David Turnerd2b1f351999-12-16 23:11:37 +0000228 /* seek to the appropriate TrueType file, then read tag */
David Turnerb1677a82000-05-29 20:37:41 +0000229 if ( FILE_Seek( face->ttc_header.TableDirectory[face_index] ) ||
230 READ_Long( format_tag ) )
David Turnerd2b1f351999-12-16 23:11:37 +0000231 goto Exit;
232 }
David Turnerd2b1f351999-12-16 23:11:37 +0000233
David Turnerb1677a82000-05-29 20:37:41 +0000234 /* the format tag was read, now check the rest of the header */
235 sfnt->format_tag = format_tag;
236 if ( READ_Fields( sfnt_header_fields, sfnt ) )
237 goto Exit;
Werner Lemberg920d41e2000-06-05 14:32:32 +0000238
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000239 /* now, check the values of `num_tables', `seach_range', etc. */
David Turnerb1677a82000-05-29 20:37:41 +0000240 {
241 TT_UInt num_tables = sfnt->num_tables;
David Turnerb1677a82000-05-29 20:37:41 +0000242 TT_ULong entry_selector = 1L << sfnt->entry_selector;
David Turner3581d062000-06-01 03:26:58 +0000243
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000244
245 /* IMPORTANT: Many fonts have an incorrect `search_range' value, so */
246 /* we only check the `entry_selector' correctness here. */
247 /* */
248 if ( num_tables == 0 ||
249 entry_selector > num_tables ||
250 entry_selector * 2 <= num_tables )
David Turner3581d062000-06-01 03:26:58 +0000251 {
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000252 FT_TRACE2(( "TT_Load_SFNT_Header: file is not SFNT!\n" ));
David Turnerb1677a82000-05-29 20:37:41 +0000253 error = FT_Err_Unknown_File_Format;
254 }
255 }
256
David Turnerd42c68e2000-01-27 13:56:02 +0000257 Exit:
258 return error;
Werner Lemberg920d41e2000-06-05 14:32:32 +0000259 }
David Turnerb1677a82000-05-29 20:37:41 +0000260
David Turnerd2b1f351999-12-16 23:11:37 +0000261
David Turnerd42c68e2000-01-27 13:56:02 +0000262 /*************************************************************************/
263 /* */
264 /* <Function> */
265 /* TT_Load_Directory */
266 /* */
267 /* <Description> */
268 /* Loads the table directory into a face object. */
269 /* */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000270 /* <InOut> */
271 /* face :: A handle to the target face object. */
272 /* */
David Turnerd42c68e2000-01-27 13:56:02 +0000273 /* <Input> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000274 /* stream :: The input stream. */
275 /* sfnt :: The SFNT directory header. */
David Turnerd42c68e2000-01-27 13:56:02 +0000276 /* */
277 /* <Return> */
278 /* TrueType error code. 0 means success. */
279 /* */
280 /* <Note> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000281 /* The stream cursor must be at the font file's origin. */
David Turnerd42c68e2000-01-27 13:56:02 +0000282 /* */
283 LOCAL_FUNC
David Turnerb1677a82000-05-29 20:37:41 +0000284 TT_Error TT_Load_Directory( TT_Face face,
285 FT_Stream stream,
286 SFNT_Header* sfnt )
David Turnerd42c68e2000-01-27 13:56:02 +0000287 {
288 TT_Error error;
289 FT_Memory memory = stream->memory;
David Turnerd42c68e2000-01-27 13:56:02 +0000290
291 TT_Table *entry, *limit;
292
David Turnerd42c68e2000-01-27 13:56:02 +0000293
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000294 FT_TRACE2(( "TT_Load_Directory: %08p\n", face ));
295
296 FT_TRACE2(( "-- Tables count: %12u\n", sfnt->num_tables ));
297 FT_TRACE2(( "-- Format version: %08lx\n", sfnt->format_tag ));
David Turnerd42c68e2000-01-27 13:56:02 +0000298
David Turnerb1677a82000-05-29 20:37:41 +0000299 face->num_tables = sfnt->num_tables;
David Turnerd2b1f351999-12-16 23:11:37 +0000300
301 if ( ALLOC_ARRAY( face->dir_tables,
302 face->num_tables,
303 TT_Table ) )
304 goto Exit;
305
306 if ( ACCESS_Frame( face->num_tables * 16L ) )
307 goto Exit;
308
309 entry = face->dir_tables;
310 limit = entry + face->num_tables;
311
312 for ( ; entry < limit; entry++ )
David Turnerd42c68e2000-01-27 13:56:02 +0000313 { /* loop through the tables and get all entries */
David Turnerd2b1f351999-12-16 23:11:37 +0000314 entry->Tag = GET_Tag4();
315 entry->CheckSum = GET_ULong();
316 entry->Offset = GET_Long();
317 entry->Length = GET_Long();
318
319 FT_TRACE2(( " %c%c%c%c - %08lx - %08lx\n",
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000320 (TT_Char)( entry->Tag >> 24 ),
321 (TT_Char)( entry->Tag >> 16 ),
322 (TT_Char)( entry->Tag >> 8 ),
323 (TT_Char)( entry->Tag ),
324 entry->Offset,
325 entry->Length ));
David Turnerd2b1f351999-12-16 23:11:37 +0000326 }
327
328 FORGET_Frame();
329
330 FT_TRACE2(( "Directory loaded\n\n" ));
331
332 Exit:
333 return error;
334 }
335
336
337 /*************************************************************************/
338 /* */
339 /* <Function> */
340 /* TT_Load_Any */
341 /* */
342 /* <Description> */
343 /* Loads any font table into client memory. Used by the */
344 /* TT_Get_Font_Data() API function. */
345 /* */
346 /* <Input> */
347 /* face :: The face object to look for. */
348 /* */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000349 /* tag :: The tag of table to load. Use the value 0 if you want */
David Turnerd2b1f351999-12-16 23:11:37 +0000350 /* to access the whole font file, else set this parameter */
351 /* to a valid TrueType table tag that you can forge with */
352 /* the MAKE_TT_TAG macro. */
353 /* */
354 /* offset :: The starting offset in the table (or the file if */
355 /* tag == 0). */
356 /* */
357 /* length :: The address of the decision variable: */
358 /* */
359 /* If length == NULL: */
360 /* Loads the whole table. Returns an error if */
361 /* `offset' == 0! */
362 /* */
363 /* If *length == 0: */
364 /* Exits immediately; returning the length of the given */
365 /* table or of the font file, depending on the value of */
366 /* `tag'. */
367 /* */
368 /* If *length != 0: */
369 /* Loads the next `length' bytes of table or font, */
370 /* starting at offset `offset' (in table or font too). */
371 /* */
372 /* <Output> */
373 /* buffer :: The address of target buffer. */
374 /* */
375 /* <Return> */
376 /* TrueType error code. 0 means success. */
377 /* */
378 LOCAL_FUNC
379 TT_Error TT_Load_Any( TT_Face face,
380 TT_ULong tag,
381 TT_Long offset,
382 void* buffer,
383 TT_Long* length )
384 {
385 TT_Error error;
386 FT_Stream stream;
387 TT_Table* table;
388 TT_ULong size;
389
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000390
David Turnerd2b1f351999-12-16 23:11:37 +0000391 if ( tag != 0 )
392 {
393 /* look for tag in font directory */
394 table = TT_LookUp_Table( face, tag );
395 if ( !table )
396 {
397 error = TT_Err_Table_Missing;
398 goto Exit;
399 }
400
401 offset += table->Offset;
402 size = table->Length;
403 }
404 else
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000405 /* tag == 0 -- the user wants to access the font file directly */
David Turnerd2b1f351999-12-16 23:11:37 +0000406 size = face->root.stream->size;
David Turnerd2b1f351999-12-16 23:11:37 +0000407
408 if ( length && *length == 0 )
409 {
410 *length = size;
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000411
David Turnerd2b1f351999-12-16 23:11:37 +0000412 return TT_Err_Ok;
413 }
414
415 if ( length )
416 size = *length;
417
418 stream = face->root.stream;
419 (void)FILE_Read_At( offset, buffer, size );
420
421 Exit:
422 return error;
423 }
424
425
426 /*************************************************************************/
427 /* */
428 /* <Function> */
429 /* TT_Load_Header */
430 /* */
431 /* <Description> */
432 /* Loads the TrueType font header. */
433 /* */
434 /* <Input> */
435 /* face :: A handle to the target face object. */
436 /* stream :: The input stream. */
437 /* */
438 /* <Return> */
439 /* TrueType error code. 0 means success. */
440 /* */
441 LOCAL_FUNC
442 TT_Error TT_Load_Header( TT_Face face,
443 FT_Stream stream )
444 {
445 TT_Error error;
446 TT_Header* header;
David Turnerb1677a82000-05-29 20:37:41 +0000447
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000448 static const FT_Frame_Field header_fields[] =
449 {
450 FT_FRAME_START( 54 ),
451 FT_FRAME_ULONG( TT_Header, Table_Version ),
452 FT_FRAME_ULONG( TT_Header, Font_Revision ),
453 FT_FRAME_LONG( TT_Header, CheckSum_Adjust ),
454 FT_FRAME_LONG( TT_Header, Magic_Number ),
455 FT_FRAME_USHORT( TT_Header, Flags ),
456 FT_FRAME_USHORT( TT_Header, Units_Per_EM ),
457 FT_FRAME_LONG( TT_Header, Created[0] ),
458 FT_FRAME_LONG( TT_Header, Created[1] ),
459 FT_FRAME_LONG( TT_Header, Modified[0] ),
460 FT_FRAME_LONG( TT_Header, Modified[1] ),
461 FT_FRAME_SHORT( TT_Header, xMin ),
462 FT_FRAME_SHORT( TT_Header, yMin ),
463 FT_FRAME_SHORT( TT_Header, xMax ),
464 FT_FRAME_SHORT( TT_Header, yMax ),
465 FT_FRAME_USHORT( TT_Header, Mac_Style ),
466 FT_FRAME_USHORT( TT_Header, Lowest_Rec_PPEM ),
467 FT_FRAME_SHORT( TT_Header, Font_Direction ),
468 FT_FRAME_SHORT( TT_Header, Index_To_Loc_Format ),
469 FT_FRAME_SHORT( TT_Header, Glyph_Data_Format ),
470 FT_FRAME_END
471 };
David Turnerd2b1f351999-12-16 23:11:37 +0000472
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000473
474 FT_TRACE2(( "Load_TT_Header: %08p\n", face ));
David Turnerd2b1f351999-12-16 23:11:37 +0000475
476 error = face->goto_table( face, TTAG_head, stream, 0 );
477 if ( error )
478 {
479 FT_TRACE0(( "Font Header is missing!\n" ));
480 goto Exit;
481 }
482
David Turnera56489e2000-02-13 13:41:56 +0000483 header = &face->header;
484
David Turnerb1677a82000-05-29 20:37:41 +0000485 if ( READ_Fields( header_fields, header ) )
David Turnerd2b1f351999-12-16 23:11:37 +0000486 goto Exit;
487
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000488 FT_TRACE2(( " Units per EM: %8u\n", header->Units_Per_EM ));
489 FT_TRACE2(( " IndexToLoc: %8d\n", header->Index_To_Loc_Format ));
David Turnerd2b1f351999-12-16 23:11:37 +0000490 FT_TRACE2(( "Font Header Loaded.\n" ));
491
492 Exit:
493 return error;
494 }
495
496
497 /*************************************************************************/
498 /* */
499 /* <Function> */
500 /* TT_Load_MaxProfile */
501 /* */
502 /* <Description> */
503 /* Loads the maximum profile into a face object. */
504 /* */
505 /* <Input> */
506 /* face :: A handle to the target face object. */
507 /* stream :: The input stream. */
508 /* */
509 /* <Return> */
510 /* TrueType error code. 0 means success. */
511 /* */
512 LOCAL_FUNC
513 TT_Error TT_Load_MaxProfile( TT_Face face,
514 FT_Stream stream )
515 {
516 TT_Error error;
517 TT_MaxProfile* maxProfile = &face->max_profile;
David Turnerb1677a82000-05-29 20:37:41 +0000518
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000519 const FT_Frame_Field maxp_fields[] =
520 {
521 FT_FRAME_START( 32 ),
522 FT_FRAME_ULONG( TT_MaxProfile, version ),
523 FT_FRAME_USHORT( TT_MaxProfile, numGlyphs ),
524 FT_FRAME_USHORT( TT_MaxProfile, maxPoints ),
525 FT_FRAME_USHORT( TT_MaxProfile, maxContours ),
526 FT_FRAME_USHORT( TT_MaxProfile, maxCompositePoints ),
527 FT_FRAME_USHORT( TT_MaxProfile, maxCompositeContours ),
528 FT_FRAME_USHORT( TT_MaxProfile, maxZones ),
529 FT_FRAME_USHORT( TT_MaxProfile, maxTwilightPoints ),
530 FT_FRAME_USHORT( TT_MaxProfile, maxStorage ),
531 FT_FRAME_USHORT( TT_MaxProfile, maxFunctionDefs ),
532 FT_FRAME_USHORT( TT_MaxProfile, maxInstructionDefs ),
533 FT_FRAME_USHORT( TT_MaxProfile, maxStackElements ),
534 FT_FRAME_USHORT( TT_MaxProfile, maxSizeOfInstructions ),
535 FT_FRAME_USHORT( TT_MaxProfile, maxComponentElements ),
536 FT_FRAME_USHORT( TT_MaxProfile, maxComponentDepth ),
537 FT_FRAME_END };
David Turnerd2b1f351999-12-16 23:11:37 +0000538
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000539
540 FT_TRACE2(( "Load_TT_MaxProfile: %08p\n", face ));
David Turnerd2b1f351999-12-16 23:11:37 +0000541
542 error = face->goto_table( face, TTAG_maxp, stream, 0 );
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000543 if ( error )
544 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +0000545
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000546 if ( READ_Fields( maxp_fields, maxProfile ) )
547 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +0000548
549 /* XXX: an adjustment that is necessary to load certain */
550 /* broken fonts like `Keystrokes MT' :-( */
551 /* */
552 /* We allocate 64 function entries by default when */
553 /* the maxFunctionDefs field is null. */
554
555 if ( maxProfile->maxFunctionDefs == 0 )
556 maxProfile->maxFunctionDefs = 64;
557
558 face->root.num_glyphs = maxProfile->numGlyphs;
559
560 face->root.max_points = MAX( maxProfile->maxCompositePoints,
561 maxProfile->maxPoints );
562
563 face->root.max_contours = MAX( maxProfile->maxCompositeContours,
564 maxProfile->maxContours );
565
566 face->max_components = (TT_ULong)maxProfile->maxComponentElements +
567 maxProfile->maxComponentDepth;
568
569 /* XXX: some fonts have maxComponents set to 0; we will */
570 /* then use 16 of them by default. */
571 if ( face->max_components == 0 )
572 face->max_components = 16;
573
574 /* We also increase maxPoints and maxContours in order to support */
575 /* some broken fonts. */
576 face->root.max_points += 8;
577 face->root.max_contours += 4;
578
579 FT_TRACE2(( "MAXP loaded.\n" ));
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000580
David Turnerd2b1f351999-12-16 23:11:37 +0000581 Exit:
582 return error;
583 }
584
585
586 /*************************************************************************/
587 /* */
588 /* <Function> */
589 /* TT_Load_Metrics */
590 /* */
591 /* <Description> */
592 /* Loads the horizontal or vertical metrics table into a face object. */
593 /* */
594 /* <Input> */
595 /* face :: A handle to the target face object. */
596 /* stream :: The input stream. */
597 /* vertical :: A boolean flag. If set, load vertical metrics. */
598 /* */
599 /* <Return> */
600 /* TrueType error code. 0 means success. */
601 /* */
602 static
603 TT_Error TT_Load_Metrics( TT_Face face,
604 FT_Stream stream,
605 TT_Bool vertical )
606 {
607 TT_Error error;
608 FT_Memory memory = stream->memory;
609
610 TT_ULong table_len;
611 TT_Long num_shorts, num_longs, num_shorts_checked;
612
613 TT_LongMetrics** longs;
614 TT_ShortMetrics** shorts;
615
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000616 FT_TRACE2(( "TT_Load_%s_Metrics: %08p\n",
617 vertical ? "Vertical" : "Horizontal", face ));
David Turnerd2b1f351999-12-16 23:11:37 +0000618
619 if ( vertical )
620 {
621 /* The table is optional, quit silently if it wasn't found */
622 /* XXX: Some fonts have a valid vertical header with a non-null */
623 /* `number_of_VMetrics' fields, but no corresponding `vmtx' */
624 /* table to get the metrics from (e.g. mingliu). */
625 /* */
626 /* For safety, we set the field to 0! */
627 /* */
628 error = face->goto_table( face, TTAG_vmtx, stream, &table_len );
629 if ( error )
630 {
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000631 /* Set number_Of_VMetrics to 0! */
David Turnerd2b1f351999-12-16 23:11:37 +0000632 FT_TRACE2(( " no vertical header in file.\n" ));
633 face->vertical.number_Of_VMetrics = 0;
634 error = TT_Err_Ok;
635 goto Exit;
636 }
637
638 num_longs = face->vertical.number_Of_VMetrics;
639 longs = (TT_LongMetrics**)&face->vertical.long_metrics;
640 shorts = (TT_ShortMetrics**)&face->vertical.short_metrics;
641 }
642 else
643 {
644 error = face->goto_table( face, TTAG_hmtx, stream, &table_len );
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000645 if ( error )
David Turnerd2b1f351999-12-16 23:11:37 +0000646 {
647 FT_ERROR(( " no horizontal metrics in file!\n" ));
648 error = TT_Err_Hmtx_Table_Missing;
649 goto Exit;
650 }
651
652 num_longs = face->horizontal.number_Of_HMetrics;
653 longs = (TT_LongMetrics**)&face->horizontal.long_metrics;
654 shorts = (TT_ShortMetrics**)&face->horizontal.short_metrics;
655 }
656
657 /* never trust derived values */
658
659 num_shorts = face->max_profile.numGlyphs - num_longs;
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000660 num_shorts_checked = ( table_len - num_longs * 4L ) / 2;
David Turnerd2b1f351999-12-16 23:11:37 +0000661
662 if ( num_shorts < 0 )
663 {
664 FT_ERROR(( "!! more metrics than glyphs!\n" ));
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000665
666 error = vertical ? TT_Err_Invalid_Vert_Metrics
667 : TT_Err_Invalid_Horiz_Metrics;
David Turnerd2b1f351999-12-16 23:11:37 +0000668 goto Exit;
669 }
670
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000671 if ( ALLOC_ARRAY( *longs, num_longs, TT_LongMetrics ) ||
David Turnerd2b1f351999-12-16 23:11:37 +0000672 ALLOC_ARRAY( *shorts, num_shorts, TT_ShortMetrics ) )
673 goto Exit;
674
675 if ( ACCESS_Frame( table_len ) )
676 goto Exit;
677
678 {
679 TT_LongMetrics* cur = *longs;
680 TT_LongMetrics* limit = cur + num_longs;
681
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000682
David Turnerd2b1f351999-12-16 23:11:37 +0000683 for ( ; cur < limit; cur++ )
684 {
685 cur->advance = GET_UShort();
686 cur->bearing = GET_Short();
687 }
688 }
689
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000690 /* do we have an inconsistent number of metric values? */
David Turnerd2b1f351999-12-16 23:11:37 +0000691 {
692 TT_ShortMetrics* cur = *shorts;
693 TT_ShortMetrics* limit = cur + MIN( num_shorts, num_shorts_checked );
694
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000695
David Turnerd2b1f351999-12-16 23:11:37 +0000696 for ( ; cur < limit; cur++ )
697 *cur = GET_Short();
698
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000699 /* we fill up the missing left side bearings with the */
700 /* last valid value. Since this will occur for buggy CJK */
701 /* fonts usually only, nothing serious will happen */
David Turnerd2b1f351999-12-16 23:11:37 +0000702 if ( num_shorts > num_shorts_checked && num_shorts_checked > 0 )
703 {
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000704 TT_Short val = *(shorts)[num_shorts_checked - 1];
705
David Turnerd2b1f351999-12-16 23:11:37 +0000706
707 limit = *shorts + num_shorts;
708 for ( ; cur < limit; cur++ )
709 *cur = val;
710 }
711 }
712
713 FORGET_Frame();
714
715 FT_TRACE2(( "loaded\n" ));
716
717 Exit:
718 return error;
719 }
720
721
722 /*************************************************************************/
723 /* */
724 /* <Function> */
725 /* TT_Load_Metrics_Header */
726 /* */
727 /* <Description> */
728 /* Loads the horizontal or vertical header in a face object. */
729 /* */
730 /* <Input> */
731 /* face :: A handle to the target face object. */
732 /* stream :: The input stream. */
733 /* vertical :: A boolean flag. If set, load vertical metrics. */
734 /* */
735 /* <Return> */
736 /* TrueType error code. 0 means success. */
737 /* */
738 LOCAL_FUNC
739 TT_Error TT_Load_Metrics_Header( TT_Face face,
740 FT_Stream stream,
741 TT_Bool vertical )
742 {
743 TT_Error error;
744 TT_HoriHeader* header;
David Turnerb1677a82000-05-29 20:37:41 +0000745
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000746 const FT_Frame_Field metrics_header_fields[] =
747 {
748 FT_FRAME_START( 36 ),
749 FT_FRAME_ULONG( TT_HoriHeader, Version ),
750 FT_FRAME_SHORT( TT_HoriHeader, Ascender ),
751 FT_FRAME_SHORT( TT_HoriHeader, Descender ),
752 FT_FRAME_SHORT( TT_HoriHeader, Line_Gap ),
753 FT_FRAME_USHORT( TT_HoriHeader, advance_Width_Max ),
754 FT_FRAME_SHORT( TT_HoriHeader, min_Left_Side_Bearing ),
755 FT_FRAME_SHORT( TT_HoriHeader, min_Right_Side_Bearing ),
756 FT_FRAME_SHORT( TT_HoriHeader, xMax_Extent ),
757 FT_FRAME_SHORT( TT_HoriHeader, caret_Slope_Rise ),
758 FT_FRAME_SHORT( TT_HoriHeader, caret_Slope_Run ),
759 FT_FRAME_SHORT( TT_HoriHeader, Reserved[0] ),
760 FT_FRAME_SHORT( TT_HoriHeader, Reserved[1] ),
761 FT_FRAME_SHORT( TT_HoriHeader, Reserved[2] ),
762 FT_FRAME_SHORT( TT_HoriHeader, Reserved[3] ),
763 FT_FRAME_SHORT( TT_HoriHeader, Reserved[4] ),
764 FT_FRAME_SHORT( TT_HoriHeader, metric_Data_Format ),
765 FT_FRAME_USHORT( TT_HoriHeader, number_Of_HMetrics ),
766 FT_FRAME_END
767 };
768
David Turnerb1677a82000-05-29 20:37:41 +0000769
David Turnerd2b1f351999-12-16 23:11:37 +0000770 FT_TRACE2(( vertical ? "Vertical header " : "Horizontal header " ));
771
772 if ( vertical )
773 {
774 face->vertical_info = 0;
775
776 /* The vertical header table is optional, so return quietly if */
777 /* we don't find it. */
778 error = face->goto_table( face, TTAG_vhea, stream, 0 );
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000779 if ( error )
David Turnerd2b1f351999-12-16 23:11:37 +0000780 {
781 error = TT_Err_Ok;
782 goto Exit;
783 }
784
785 face->vertical_info = 1;
786 header = (TT_HoriHeader*)&face->vertical;
787 }
788 else
789 {
790 /* The horizontal header is mandatory, return an error if we */
791 /* don't find it. */
792 error = face->goto_table( face, TTAG_hhea, stream, 0 );
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000793 if ( error )
David Turnerd2b1f351999-12-16 23:11:37 +0000794 {
795 error = TT_Err_Horiz_Header_Missing;
796 goto Exit;
797 }
798
799 header = &face->horizontal;
800 }
801
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000802 if ( READ_Fields( metrics_header_fields, header ) )
803 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +0000804
805 header->long_metrics = NULL;
806 header->short_metrics = NULL;
807
808 FT_TRACE2(( "loaded\n" ));
809
810 /* Now try to load the corresponding metrics */
811
812 error = TT_Load_Metrics( face, stream, vertical );
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000813
David Turnerd2b1f351999-12-16 23:11:37 +0000814 Exit:
815 return error;
816 }
817
818
819 /*************************************************************************/
820 /* */
821 /* <Function> */
822 /* TT_Load_Names */
823 /* */
824 /* <Description> */
825 /* Loads the name records. */
826 /* */
827 /* <Input> */
828 /* face :: A handle to the target face object. */
829 /* stream :: The input stream. */
830 /* */
831 /* <Return> */
832 /* TrueType error code. 0 means success. */
833 /* */
834 LOCAL_FUNC
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000835 TT_Error TT_Load_Names( TT_Face face,
836 FT_Stream stream )
David Turnerd2b1f351999-12-16 23:11:37 +0000837 {
838 TT_Error error;
839 FT_Memory memory = stream->memory;
840
841 TT_ULong table_pos, table_len;
842 TT_ULong storageSize;
843
844 TT_NameTable* names;
David Turnerb1677a82000-05-29 20:37:41 +0000845
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000846 const FT_Frame_Field name_table_fields[] =
847 {
848 FT_FRAME_START( 6 ),
849 FT_FRAME_USHORT( TT_NameTable, format ),
850 FT_FRAME_USHORT( TT_NameTable, numNameRecords ),
851 FT_FRAME_USHORT( TT_NameTable, storageOffset ),
852 FT_FRAME_END
853 };
David Turnera56489e2000-02-13 13:41:56 +0000854
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000855 const FT_Frame_Field name_record_fields[] =
856 {
857 /* no FT_FRAME_START */
858 FT_FRAME_USHORT( TT_NameRec, platformID ),
859 FT_FRAME_USHORT( TT_NameRec, encodingID ),
860 FT_FRAME_USHORT( TT_NameRec, languageID ),
861 FT_FRAME_USHORT( TT_NameRec, nameID ),
862 FT_FRAME_USHORT( TT_NameRec, stringLength ),
863 FT_FRAME_USHORT( TT_NameRec, stringOffset ),
864 FT_FRAME_END
865 };
David Turnerd2b1f351999-12-16 23:11:37 +0000866
867
868 FT_TRACE2(( "Names " ));
869
870 error = face->goto_table( face, TTAG_name, stream, &table_len );
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000871 if ( error )
David Turnerd2b1f351999-12-16 23:11:37 +0000872 {
873 /* The name table is required so indicate failure. */
874 FT_TRACE2(( "is missing!\n" ));
875 error = TT_Err_Name_Table_Missing;
876 goto Exit;
877 }
878
879 table_pos = FILE_Pos();
880
David Turnera56489e2000-02-13 13:41:56 +0000881 names = &face->name_table;
882
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000883 if ( READ_Fields( name_table_fields, names ) )
884 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +0000885
886 /* Allocate the array of name records. */
887 if ( ALLOC_ARRAY( names->names,
888 names->numNameRecords,
889 TT_NameRec ) ||
890 ACCESS_Frame( names->numNameRecords * 12L ) )
891 goto Exit;
892
893 /* Load the name records and determine how much storage is needed */
894 /* to hold the strings themselves. */
895 {
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000896 TT_NameRec* cur = names->names;
897 TT_NameRec* limit = cur + names->numNameRecords;
898
David Turnerd2b1f351999-12-16 23:11:37 +0000899
900 storageSize = 0;
901
902 for ( ; cur < limit; cur ++ )
903 {
904 TT_ULong upper;
905
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000906
David Turnera56489e2000-02-13 13:41:56 +0000907 (void)READ_Fields( name_record_fields, cur );
David Turnerb1677a82000-05-29 20:37:41 +0000908
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000909 upper = (TT_ULong)( cur->stringOffset + cur->stringLength );
910 if ( upper > storageSize )
911 storageSize = upper;
David Turnerd2b1f351999-12-16 23:11:37 +0000912 }
913 }
914
915 FORGET_Frame();
916
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000917 if ( storageSize > 0 )
David Turnerd2b1f351999-12-16 23:11:37 +0000918 {
919 /* allocate the name storage area in memory, then read it */
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000920 if ( ALLOC( names->storage, storageSize ) ||
David Turnerd2b1f351999-12-16 23:11:37 +0000921 FILE_Read_At( table_pos + names->storageOffset,
922 (void*)names->storage, storageSize ) )
923 goto Exit;
David Turnere49ab252000-05-16 23:44:38 +0000924
David Turnerd2b1f351999-12-16 23:11:37 +0000925 /* Go through and assign the string pointers to the name records. */
926 {
927 TT_NameRec* cur = names->names;
928 TT_NameRec* limit = cur + names->numNameRecords;
David Turnere49ab252000-05-16 23:44:38 +0000929
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000930
David Turnerd2b1f351999-12-16 23:11:37 +0000931 for ( ; cur < limit; cur++ )
932 cur->string = names->storage + cur->stringOffset;
933 }
934
David Turnere49ab252000-05-16 23:44:38 +0000935#ifdef FT_DEBUG_LEVEL_TRACE
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000936
David Turnerd2b1f351999-12-16 23:11:37 +0000937 /* Print Name Record Table in case of debugging */
938 {
939 TT_NameRec* cur = names->names;
940 TT_NameRec* limit = cur + names->numNameRecords;
941
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000942
David Turnerd2b1f351999-12-16 23:11:37 +0000943 for ( ; cur < limit; cur++ )
944 {
945 TT_UInt j;
David Turnere49ab252000-05-16 23:44:38 +0000946
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000947
948 FT_TRACE3(( "%d %d %x %d\n ",
David Turnerd2b1f351999-12-16 23:11:37 +0000949 cur->platformID,
950 cur->encodingID,
951 cur->languageID,
952 cur->nameID ));
David Turnere49ab252000-05-16 23:44:38 +0000953
David Turnerd2b1f351999-12-16 23:11:37 +0000954 /* I know that M$ encoded strings are Unicode, */
955 /* but this works reasonable well for debugging purposes. */
956 if ( cur->string )
957 for ( j = 0; j < cur->stringLength; j++ )
958 {
959 TT_Char c = *(cur->string + j);
David Turnere49ab252000-05-16 23:44:38 +0000960
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000961
David Turnerd2b1f351999-12-16 23:11:37 +0000962 if ( (TT_Byte)c < 128 )
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000963 FT_TRACE3(( "%c", c ));
David Turnerd2b1f351999-12-16 23:11:37 +0000964 }
965 }
966 }
Werner Lemberg4e6dd852000-06-05 05:26:15 +0000967 FT_TRACE3(( "\n" ));
968
969#endif /* FT_DEBUG_LEVEL_TRACE */
970
David Turnerd2b1f351999-12-16 23:11:37 +0000971 }
972 FT_TRACE2(( "loaded\n" ));
973
974 Exit:
975 return error;
976 }
977
978
979 /*************************************************************************/
980 /* */
981 /* <Function> */
982 /* TT_Free_Names */
983 /* */
984 /* <Description> */
985 /* Frees the name records. */
986 /* */
987 /* <Input> */
988 /* face :: A handle to the target face object. */
989 /* */
990 LOCAL_FUNC
991 void TT_Free_Names( TT_Face face )
992 {
993 FT_Memory memory = face->root.driver->memory;
994 TT_NameTable* names = &face->name_table;
995
996
997 /* free strings table */
998 FREE( names->names );
999
1000 /* free strings storage */
1001 FREE( names->storage );
1002
1003 names->numNameRecords = 0;
1004 names->format = 0;
1005 names->storageOffset = 0;
1006 }
1007
1008
1009 /*************************************************************************/
1010 /* */
1011 /* <Function> */
1012 /* TT_Load_CMap */
1013 /* */
1014 /* <Description> */
1015 /* Loads the cmap directory in a face object. The cmaps itselves are */
1016 /* loaded on demand in the `ttcmap.c' module. */
1017 /* */
1018 /* <Input> */
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001019 /* face :: A handle to the target face object. */
1020 /* stream :: A handle to the input stream. */
David Turnerd2b1f351999-12-16 23:11:37 +00001021 /* */
1022 /* <Return> */
1023 /* TrueType error code. 0 means success. */
1024 /* */
1025 LOCAL_FUNC
1026 TT_Error TT_Load_CMap( TT_Face face,
1027 FT_Stream stream )
1028 {
1029 TT_Error error;
1030 FT_Memory memory = stream->memory;
David Turnera56489e2000-02-13 13:41:56 +00001031 TT_Long table_start;
David Turnerd2b1f351999-12-16 23:11:37 +00001032 TT_CMapDir cmap_dir;
1033
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001034 const FT_Frame_Field cmap_fields[] =
1035 {
1036 FT_FRAME_START( 4 ),
1037 FT_FRAME_USHORT( TT_CMapDir, tableVersionNumber ),
1038 FT_FRAME_USHORT( TT_CMapDir, numCMaps ),
1039 FT_FRAME_END
1040 };
David Turnera56489e2000-02-13 13:41:56 +00001041
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001042 const FT_Frame_Field cmap_rec_fields[] =
1043 {
1044 FT_FRAME_START( 6 ),
1045 FT_FRAME_USHORT( TT_CMapTable, format ),
1046 FT_FRAME_USHORT( TT_CMapTable, length ),
1047 FT_FRAME_USHORT( TT_CMapTable, version ),
1048 FT_FRAME_END
1049 };
1050
David Turnera56489e2000-02-13 13:41:56 +00001051
David Turnerd2b1f351999-12-16 23:11:37 +00001052 FT_TRACE2(( "CMaps " ));
1053
1054 error = face->goto_table( face, TTAG_cmap, stream, 0 );
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001055 if ( error )
David Turnerd2b1f351999-12-16 23:11:37 +00001056 {
1057 error = TT_Err_CMap_Table_Missing;
1058 goto Exit;
1059 }
1060
1061 table_start = FILE_Pos();
1062
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001063 if ( READ_Fields( cmap_fields, &cmap_dir ) )
1064 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +00001065
1066 /* save space in face table for cmap tables */
1067 if ( ALLOC_ARRAY( face->charmaps,
1068 cmap_dir.numCMaps,
1069 TT_CharMapRec ) )
1070 goto Exit;
1071
1072 face->num_charmaps = cmap_dir.numCMaps;
1073 {
1074 TT_CharMap charmap = face->charmaps;
1075 TT_CharMap limit = charmap + face->num_charmaps;
1076
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001077
David Turnera56489e2000-02-13 13:41:56 +00001078 /* read the header of each charmap first */
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001079 if ( ACCESS_Frame( face->num_charmaps * 8L ) )
1080 goto Exit;
1081
David Turnerd2b1f351999-12-16 23:11:37 +00001082 for ( ; charmap < limit; charmap++ )
1083 {
1084 TT_CMapTable* cmap;
1085
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001086
David Turnerd2b1f351999-12-16 23:11:37 +00001087 charmap->root.face = (FT_Face)face;
1088 cmap = &charmap->cmap;
1089
David Turnerd2b1f351999-12-16 23:11:37 +00001090 cmap->loaded = FALSE;
1091 cmap->platformID = GET_UShort();
1092 cmap->platformEncodingID = GET_UShort();
David Turnera56489e2000-02-13 13:41:56 +00001093 cmap->offset = (TT_ULong)GET_Long();
1094 }
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001095
David Turnera56489e2000-02-13 13:41:56 +00001096 FORGET_Frame();
David Turnere49ab252000-05-16 23:44:38 +00001097
David Turnera56489e2000-02-13 13:41:56 +00001098 /* now read the rest of each table */
1099 for ( charmap = face->charmaps; charmap < limit; charmap++ )
1100 {
1101 TT_CMapTable* cmap = &charmap->cmap;
David Turnere49ab252000-05-16 23:44:38 +00001102
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001103
David Turnera56489e2000-02-13 13:41:56 +00001104 if ( FILE_Seek( table_start + (TT_Long)cmap->offset ) ||
1105 READ_Fields( cmap_rec_fields, cmap ) )
David Turnerd2b1f351999-12-16 23:11:37 +00001106 goto Exit;
David Turnere49ab252000-05-16 23:44:38 +00001107
David Turnerd2b1f351999-12-16 23:11:37 +00001108 cmap->offset = FILE_Pos();
David Turnerd2b1f351999-12-16 23:11:37 +00001109 }
1110 }
1111
1112 FT_TRACE2(( "loaded\n" ));
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001113
David Turnerd2b1f351999-12-16 23:11:37 +00001114 Exit:
1115 return error;
1116 }
1117
1118
1119 /*************************************************************************/
1120 /* */
1121 /* <Function> */
1122 /* TT_Load_OS2 */
1123 /* */
1124 /* <Description> */
1125 /* Loads the OS2 table. */
1126 /* */
1127 /* <Input> */
1128 /* face :: A handle to the target face object. */
1129 /* stream :: A handle to the input stream. */
1130 /* */
1131 /* <Return> */
1132 /* TrueType error code. 0 means success. */
1133 /* */
1134 LOCAL_FUNC
1135 TT_Error TT_Load_OS2( TT_Face face,
1136 FT_Stream stream )
1137 {
1138 TT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +00001139 TT_OS2* os2;
David Turnerb1677a82000-05-29 20:37:41 +00001140
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001141 const FT_Frame_Field os2_fields[] =
1142 {
1143 FT_FRAME_START( 78 ),
1144 FT_FRAME_USHORT( TT_OS2, version ),
1145 FT_FRAME_SHORT( TT_OS2, xAvgCharWidth ),
1146 FT_FRAME_USHORT( TT_OS2, usWeightClass ),
1147 FT_FRAME_USHORT( TT_OS2, usWidthClass ),
1148 FT_FRAME_SHORT( TT_OS2, fsType ),
1149 FT_FRAME_SHORT( TT_OS2, ySubscriptXSize ),
1150 FT_FRAME_SHORT( TT_OS2, ySubscriptYSize ),
1151 FT_FRAME_SHORT( TT_OS2, ySubscriptXOffset ),
1152 FT_FRAME_SHORT( TT_OS2, ySubscriptYOffset ),
1153 FT_FRAME_SHORT( TT_OS2, ySuperscriptXSize ),
1154 FT_FRAME_SHORT( TT_OS2, ySuperscriptYSize ),
1155 FT_FRAME_SHORT( TT_OS2, ySuperscriptXOffset ),
1156 FT_FRAME_SHORT( TT_OS2, ySuperscriptYOffset ),
1157 FT_FRAME_SHORT( TT_OS2, yStrikeoutSize ),
1158 FT_FRAME_SHORT( TT_OS2, yStrikeoutPosition ),
1159 FT_FRAME_SHORT( TT_OS2, sFamilyClass ),
1160 FT_FRAME_BYTE( TT_OS2, panose[0] ),
1161 FT_FRAME_BYTE( TT_OS2, panose[1] ),
1162 FT_FRAME_BYTE( TT_OS2, panose[2] ),
1163 FT_FRAME_BYTE( TT_OS2, panose[3] ),
1164 FT_FRAME_BYTE( TT_OS2, panose[4] ),
1165 FT_FRAME_BYTE( TT_OS2, panose[5] ),
1166 FT_FRAME_BYTE( TT_OS2, panose[6] ),
1167 FT_FRAME_BYTE( TT_OS2, panose[7] ),
1168 FT_FRAME_BYTE( TT_OS2, panose[8] ),
1169 FT_FRAME_BYTE( TT_OS2, panose[9] ),
1170 FT_FRAME_ULONG( TT_OS2, ulUnicodeRange1 ),
1171 FT_FRAME_ULONG( TT_OS2, ulUnicodeRange2 ),
1172 FT_FRAME_ULONG( TT_OS2, ulUnicodeRange3 ),
1173 FT_FRAME_ULONG( TT_OS2, ulUnicodeRange4 ),
1174 FT_FRAME_BYTE( TT_OS2, achVendID[0] ),
1175 FT_FRAME_BYTE( TT_OS2, achVendID[1] ),
1176 FT_FRAME_BYTE( TT_OS2, achVendID[2] ),
1177 FT_FRAME_BYTE( TT_OS2, achVendID[3] ),
David Turnera56489e2000-02-13 13:41:56 +00001178
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001179 FT_FRAME_USHORT( TT_OS2, fsSelection ),
1180 FT_FRAME_USHORT( TT_OS2, usFirstCharIndex ),
1181 FT_FRAME_USHORT( TT_OS2, usLastCharIndex ),
1182 FT_FRAME_SHORT( TT_OS2, sTypoAscender ),
1183 FT_FRAME_SHORT( TT_OS2, sTypoDescender ),
1184 FT_FRAME_SHORT( TT_OS2, sTypoLineGap ),
1185 FT_FRAME_USHORT( TT_OS2, usWinAscent ),
1186 FT_FRAME_USHORT( TT_OS2, usWinDescent ),
1187 FT_FRAME_END
1188 };
David Turnere49ab252000-05-16 23:44:38 +00001189
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001190 const FT_Frame_Field os2_fields_extra[] =
1191 {
1192 FT_FRAME_START( 8 ),
1193 FT_FRAME_ULONG( TT_OS2, ulCodePageRange1 ),
1194 FT_FRAME_ULONG( TT_OS2, ulCodePageRange2 ),
1195 FT_FRAME_END
1196 };
David Turner1119bae2000-05-02 11:01:49 +00001197
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001198 const FT_Frame_Field os2_fields_extra2[] =
1199 {
1200 FT_FRAME_START( 10 ),
1201 FT_FRAME_SHORT( TT_OS2, sxHeight ),
1202 FT_FRAME_SHORT( TT_OS2, sCapHeight ),
1203 FT_FRAME_USHORT( TT_OS2, usDefaultChar ),
1204 FT_FRAME_USHORT( TT_OS2, usBreakChar ),
1205 FT_FRAME_USHORT( TT_OS2, usMaxContext ),
1206 FT_FRAME_END
1207 };
1208
David Turnerd2b1f351999-12-16 23:11:37 +00001209
1210 FT_TRACE2(( "OS/2 Table " ));
1211
1212 /* We now support old Mac fonts where the OS/2 table doesn't */
1213 /* exist. Simply put, we set the `version' field to 0xFFFF */
1214 /* and test this value each time we need to access the table. */
1215 error = face->goto_table( face, TTAG_OS2, stream, 0 );
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001216 if ( error )
David Turnerd2b1f351999-12-16 23:11:37 +00001217 {
1218 FT_TRACE2(( "is missing\n!" ));
1219 face->os2.version = 0xFFFF;
1220 error = TT_Err_Ok;
1221 goto Exit;
1222 }
1223
David Turnera56489e2000-02-13 13:41:56 +00001224 os2 = &face->os2;
1225
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001226 if ( READ_Fields( os2_fields, os2 ) )
1227 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +00001228
1229 os2->ulCodePageRange1 = 0;
1230 os2->ulCodePageRange2 = 0;
1231
1232 if ( os2->version >= 0x0001 )
1233 {
1234 /* only version 1 tables */
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001235 if ( READ_Fields( os2_fields_extra, os2 ) )
1236 goto Exit;
David Turner1119bae2000-05-02 11:01:49 +00001237
1238 if ( os2->version >= 0x0002 )
1239 {
1240 /* only version 2 tables */
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001241 if ( READ_Fields( os2_fields_extra2, os2 ) )
1242 goto Exit;
David Turner1119bae2000-05-02 11:01:49 +00001243 }
David Turnerd2b1f351999-12-16 23:11:37 +00001244 }
1245
1246 FT_TRACE2(( "loaded\n" ));
1247
1248 Exit:
1249 return error;
1250 }
1251
1252
1253 /*************************************************************************/
1254 /* */
1255 /* <Function> */
1256 /* TT_Load_Postscript */
1257 /* */
1258 /* <Description> */
1259 /* Loads the Postscript table. */
1260 /* */
1261 /* <Input> */
1262 /* face :: A handle to the target face object. */
1263 /* stream :: A handle to the input stream. */
1264 /* */
1265 /* <Return> */
1266 /* TrueType error code. 0 means success. */
1267 /* */
1268 LOCAL_FUNC
1269 TT_Error TT_Load_PostScript( TT_Face face,
1270 FT_Stream stream )
1271 {
1272 TT_Error error;
1273 TT_Postscript* post = &face->postscript;
David Turnerb1677a82000-05-29 20:37:41 +00001274
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001275 static const FT_Frame_Field post_fields[] =
1276 {
1277 FT_FRAME_START( 32 ),
1278 FT_FRAME_ULONG( TT_Postscript, FormatType ),
1279 FT_FRAME_ULONG( TT_Postscript, italicAngle ),
1280 FT_FRAME_SHORT( TT_Postscript, underlinePosition ),
1281 FT_FRAME_SHORT( TT_Postscript, underlineThickness ),
1282 FT_FRAME_ULONG( TT_Postscript, isFixedPitch ),
1283 FT_FRAME_ULONG( TT_Postscript, minMemType42 ),
1284 FT_FRAME_ULONG( TT_Postscript, maxMemType42 ),
1285 FT_FRAME_ULONG( TT_Postscript, minMemType1 ),
1286 FT_FRAME_ULONG( TT_Postscript, maxMemType1 ),
1287 FT_FRAME_END
1288 };
1289
David Turnerd2b1f351999-12-16 23:11:37 +00001290
1291 FT_TRACE2(( "PostScript " ));
1292
1293 error = face->goto_table( face, TTAG_post, stream, 0 );
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001294 if ( error )
David Turnerd2b1f351999-12-16 23:11:37 +00001295 return TT_Err_Post_Table_Missing;
1296
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001297 if ( READ_Fields( post_fields, post ) )
1298 return error;
David Turnerd2b1f351999-12-16 23:11:37 +00001299
David Turnerd2b1f351999-12-16 23:11:37 +00001300 /* we don't load the glyph names, we do that in another */
1301 /* module (ttpost). */
1302 FT_TRACE2(( "loaded\n" ));
1303
1304 return TT_Err_Ok;
1305 }
1306
1307
1308 /*************************************************************************/
1309 /* */
1310 /* <Function> */
David Turner51179f02000-05-18 16:18:05 +00001311 /* TT_Load_PCLT */
1312 /* */
1313 /* <Description> */
1314 /* Loads the PCL 5 Table. */
1315 /* */
1316 /* <Input> */
1317 /* face :: A handle to the target face object. */
1318 /* stream :: A handle to the input stream. */
1319 /* */
1320 /* <Return> */
1321 /* TrueType error code. 0 means success. */
1322 /* */
1323 LOCAL_FUNC
1324 TT_Error TT_Load_PCLT( TT_Face face,
1325 FT_Stream stream )
1326 {
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001327 static const FT_Frame_Field pclt_fields[] =
1328 {
1329 FT_FRAME_START( 20 ),
1330 FT_FRAME_ULONG ( TT_PCLT, Version ),
1331 FT_FRAME_ULONG ( TT_PCLT, FontNumber ),
1332 FT_FRAME_USHORT( TT_PCLT, Pitch ),
1333 FT_FRAME_USHORT( TT_PCLT, xHeight ),
1334 FT_FRAME_USHORT( TT_PCLT, Style ),
1335 FT_FRAME_USHORT( TT_PCLT, TypeFamily ),
1336 FT_FRAME_USHORT( TT_PCLT, CapHeight ),
1337 FT_FRAME_END
1338 };
Werner Lemberg920d41e2000-06-05 14:32:32 +00001339
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001340 static const FT_Frame_Field pclt_fields2[] =
1341 {
1342 FT_FRAME_START( 4 ),
1343 FT_FRAME_CHAR( TT_PCLT, StrokeWeight ),
1344 FT_FRAME_CHAR( TT_PCLT, WidthType ),
1345 FT_FRAME_BYTE( TT_PCLT, SerifStyle ),
1346 FT_FRAME_BYTE( TT_PCLT, Reserved ),
1347 FT_FRAME_END
1348 };
Werner Lemberg920d41e2000-06-05 14:32:32 +00001349
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001350 TT_Error error;
1351 TT_PCLT* pclt = &face->pclt;
1352
Werner Lemberg920d41e2000-06-05 14:32:32 +00001353
David Turner51179f02000-05-18 16:18:05 +00001354 FT_TRACE2(( "PCLT " ));
1355
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001356 /* optional table */
1357 error = face->goto_table( face, TTAG_PCLT, stream, 0 );
1358 if ( error )
1359 {
1360 FT_TRACE2(( "missing (optional)\n" ));
1361 pclt->Version = 0;
1362 return TT_Err_Ok;
1363 }
Werner Lemberg920d41e2000-06-05 14:32:32 +00001364
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001365 if ( READ_Fields( pclt_fields, pclt ) ||
1366 FILE_Read ( pclt->TypeFace, 16 ) ||
1367 FILE_Read ( pclt->CharacterComplement, 8 ) ||
1368 FILE_Read ( pclt->FileName, 6 ) ||
1369 READ_Fields( pclt_fields2, pclt ) )
David Turner51179f02000-05-18 16:18:05 +00001370 goto Exit;
Werner Lemberg920d41e2000-06-05 14:32:32 +00001371
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001372 FT_TRACE2(( "loaded\n" ));
1373
Werner Lemberg920d41e2000-06-05 14:32:32 +00001374 Exit:
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001375 return error;
1376 }
1377
David Turner51179f02000-05-18 16:18:05 +00001378
1379 /*************************************************************************/
1380 /* */
1381 /* <Function> */
David Turnerd2b1f351999-12-16 23:11:37 +00001382 /* TT_Load_Gasp */
1383 /* */
1384 /* <Description> */
1385 /* Loads the `GASP' table into a face object. */
1386 /* */
1387 /* <Input> */
1388 /* face :: A handle to the target face object. */
1389 /* stream :: The input stream. */
1390 /* */
1391 /* <Return> */
1392 /* TrueType error code. 0 means success. */
1393 /* */
1394 LOCAL_FUNC
1395 TT_Error TT_Load_Gasp( TT_Face face,
1396 FT_Stream stream )
1397 {
1398 TT_Error error;
1399 FT_Memory memory = stream->memory;
1400
1401 TT_UInt j,num_ranges;
1402 TT_GaspRange* gaspranges;
1403
1404
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001405 FT_TRACE2(( "TT_Load_Gasp: %08p\n", face ));
David Turnerd2b1f351999-12-16 23:11:37 +00001406
1407 /* the gasp table is optional */
1408 error = face->goto_table( face, TTAG_gasp, stream, 0 );
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001409 if ( error )
1410 return TT_Err_Ok;
David Turnerd2b1f351999-12-16 23:11:37 +00001411
1412 if ( ACCESS_Frame( 4L ) )
1413 goto Exit;
1414
1415 face->gasp.version = GET_UShort();
1416 face->gasp.numRanges = GET_UShort();
1417
1418 FORGET_Frame();
1419
1420 num_ranges = face->gasp.numRanges;
1421 FT_TRACE3(( "number of ranges = %d\n", num_ranges ));
1422
1423 if ( ALLOC_ARRAY( gaspranges, num_ranges, TT_GaspRange ) ||
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001424 ACCESS_Frame( num_ranges * 4L ) )
David Turnerd2b1f351999-12-16 23:11:37 +00001425 goto Exit;
1426
1427 face->gasp.gaspRanges = gaspranges;
1428
1429 for ( j = 0; j < num_ranges; j++ )
1430 {
1431 gaspranges[j].maxPPEM = GET_UShort();
1432 gaspranges[j].gaspFlag = GET_UShort();
1433
1434 FT_TRACE3(( " [max:%d flag:%d]",
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001435 gaspranges[j].maxPPEM,
1436 gaspranges[j].gaspFlag ));
David Turnerd2b1f351999-12-16 23:11:37 +00001437 }
1438 FT_TRACE3(( "\n" ));
1439
1440 FORGET_Frame();
1441 FT_TRACE2(( "GASP loaded\n" ));
1442
1443 Exit:
1444 return error;
1445 }
1446
1447
1448 /*************************************************************************/
1449 /* */
1450 /* <Function> */
1451 /* TT_Load_Kern */
1452 /* */
1453 /* <Description> */
1454 /* Loads the first kerning table with format 0 in the font. Only */
1455 /* accepts the first horizontal kerning table. Developers should use */
1456 /* the `ftxkern' extension to access other kerning tables in the font */
1457 /* file, if they really want to. */
1458 /* */
1459 /* <Input> */
1460 /* face :: A handle to the target face object. */
1461 /* stream :: The input stream. */
1462 /* */
1463 /* <Return> */
1464 /* TrueType error code. 0 means success. */
1465 /* */
1466 LOCAL_FUNC
1467 TT_Error TT_Load_Kern( TT_Face face,
1468 FT_Stream stream )
1469 {
1470 TT_Error error;
1471 FT_Memory memory = stream->memory;
1472
1473 TT_UInt n, num_tables, version;
1474
David Turnerd2b1f351999-12-16 23:11:37 +00001475
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001476 /* the kern table is optional. exit silently if it is missing */
1477 error = face->goto_table( face, TTAG_kern, stream, 0 );
1478 if ( error )
1479 return TT_Err_Ok;
1480
1481 if ( ACCESS_Frame( 4L ) )
1482 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +00001483
1484 version = GET_UShort();
1485 num_tables = GET_UShort();
1486
1487 FORGET_Frame();
1488
1489 for ( n = 0; n < num_tables; n++ )
1490 {
1491 TT_UInt coverage;
1492 TT_UInt length;
1493
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001494
1495 if ( ACCESS_Frame( 6L ) )
1496 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +00001497
1498 version = GET_UShort(); /* version */
1499 length = GET_UShort() - 6; /* substract header length */
1500 coverage = GET_UShort();
1501
1502 FORGET_Frame();
David Turnere49ab252000-05-16 23:44:38 +00001503
David Turnerd2b1f351999-12-16 23:11:37 +00001504 if ( coverage == 0x0001 )
1505 {
1506 TT_UInt num_pairs;
1507 TT_Kern_0_Pair* pair;
1508 TT_Kern_0_Pair* limit;
1509
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001510
1511 /* found a horizontal format 0 kerning table! */
1512 if ( ACCESS_Frame( 8L ) )
David Turnerd2b1f351999-12-16 23:11:37 +00001513 goto Exit;
1514
1515 num_pairs = GET_UShort();
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001516
David Turnerd2b1f351999-12-16 23:11:37 +00001517 /* skip the rest */
1518
1519 FORGET_Frame();
1520
1521 /* allocate array of kerning pairs */
1522 if ( ALLOC_ARRAY( face->kern_pairs, num_pairs, TT_Kern_0_Pair ) ||
1523 ACCESS_Frame( 6L * num_pairs ) )
1524 goto Exit;
1525
1526 pair = face->kern_pairs;
1527 limit = pair + num_pairs;
1528 for ( ; pair < limit; pair++ )
1529 {
1530 pair->left = GET_UShort();
1531 pair->right = GET_UShort();
1532 pair->value = GET_UShort();
1533 }
1534
1535 FORGET_Frame();
1536
1537 face->num_kern_pairs = num_pairs;
1538 face->kern_table_index = n;
1539 goto Exit;
1540 }
David Turnere49ab252000-05-16 23:44:38 +00001541
David Turnerd2b1f351999-12-16 23:11:37 +00001542 if ( FILE_Skip( length ) )
1543 goto Exit;
1544 }
1545
1546 /* no kern table found -- doesn't matter */
1547 face->kern_table_index = -1;
1548 face->num_kern_pairs = 0;
1549 face->kern_pairs = NULL;
1550
1551 Exit:
1552 return error;
1553 }
1554
1555
1556 /*************************************************************************/
1557 /* */
1558 /* <Function> */
1559 /* TT_Load_Hdmx */
1560 /* */
1561 /* <Description> */
1562 /* Loads the horizontal device metrics table. */
1563 /* */
1564 /* <Input> */
1565 /* face :: A handle to the target face object. */
1566 /* stream :: A handle to the input stream. */
1567 /* */
1568 /* <Return> */
1569 /* TrueType error code. 0 means success. */
1570 /* */
1571 LOCAL_FUNC
David Turnere49ab252000-05-16 23:44:38 +00001572 TT_Error TT_Load_Hdmx( TT_Face face,
David Turnerd2b1f351999-12-16 23:11:37 +00001573 FT_Stream stream )
1574 {
1575 TT_Error error;
1576 FT_Memory memory = stream->memory;
1577
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001578 TT_Hdmx* hdmx = &face->hdmx;
1579 TT_Long num_glyphs;
1580 TT_Long record_size;
1581
David Turnerd2b1f351999-12-16 23:11:37 +00001582
1583 hdmx->version = 0;
1584 hdmx->num_records = 0;
1585 hdmx->records = 0;
1586
1587 /* this table is optional */
1588 error = face->goto_table( face, TTAG_hdmx, stream, 0 );
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001589 if ( error )
1590 return TT_Err_Ok;
David Turnerd2b1f351999-12-16 23:11:37 +00001591
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001592 if ( ACCESS_Frame( 8L ) )
1593 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +00001594
1595 hdmx->version = GET_UShort();
1596 hdmx->num_records = GET_Short();
1597 record_size = GET_Long();
1598
1599 FORGET_Frame();
1600
1601 /* Only recognize format 0 */
1602 if ( hdmx->version != 0 )
1603 goto Exit;
1604
1605 if ( ALLOC_ARRAY( hdmx->records, hdmx->num_records, TT_HdmxRec ) )
1606 goto Exit;
1607
1608 num_glyphs = face->root.num_glyphs;
1609 record_size -= num_glyphs + 2;
1610
1611 {
1612 TT_HdmxRec* cur = hdmx->records;
1613 TT_HdmxRec* limit = cur + hdmx->num_records;
1614
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001615
David Turnerd2b1f351999-12-16 23:11:37 +00001616 for ( ; cur < limit; cur++ )
1617 {
1618 /* read record */
1619 if ( READ_Byte( cur->ppem ) ||
1620 READ_Byte( cur->max_width ) )
1621 goto Exit;
David Turnere49ab252000-05-16 23:44:38 +00001622
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001623 if ( ALLOC( cur->widths, num_glyphs ) ||
David Turnerd2b1f351999-12-16 23:11:37 +00001624 FILE_Read( cur->widths, num_glyphs ) )
1625 goto Exit;
David Turnere49ab252000-05-16 23:44:38 +00001626
David Turnerd2b1f351999-12-16 23:11:37 +00001627 /* skip padding bytes */
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001628 if ( record_size > 0 && FILE_Skip( record_size ) )
David Turnerd2b1f351999-12-16 23:11:37 +00001629 goto Exit;
1630 }
1631 }
1632
1633 Exit:
1634 return error;
1635 }
1636
1637
1638 /*************************************************************************/
1639 /* */
1640 /* <Function> */
1641 /* TT_Free_Hdmx */
1642 /* */
1643 /* <Description> */
1644 /* Frees the horizontal device metrics table. */
1645 /* */
1646 /* <Input> */
1647 /* face :: A handle to the target face object. */
1648 /* */
1649 LOCAL_FUNC
1650 void TT_Free_Hdmx( TT_Face face )
1651 {
1652 if ( face )
1653 {
1654 TT_Int n;
1655 FT_Memory memory = face->root.driver->memory;
1656
Werner Lemberg4e6dd852000-06-05 05:26:15 +00001657
David Turnerd2b1f351999-12-16 23:11:37 +00001658 for ( n = 0; n < face->hdmx.num_records; n++ )
1659 FREE( face->hdmx.records[n].widths );
1660
1661 FREE( face->hdmx.records );
1662 face->hdmx.num_records = 0;
1663 }
1664 }
1665
1666
1667/* END */