1 /***************************************************************************/ |
|
2 /* */ |
|
3 /* ttload.c */ |
|
4 /* */ |
|
5 /* Load the basic TrueType tables, i.e., tables that can be either in */ |
|
6 /* TTF or OTF fonts (body). */ |
|
7 /* */ |
|
8 /* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, */ |
|
9 /* 2010 by */ |
|
10 /* David Turner, Robert Wilhelm, and Werner Lemberg. */ |
|
11 /* */ |
|
12 /* This file is part of the FreeType project, and may only be used, */ |
|
13 /* modified, and distributed under the terms of the FreeType project */ |
|
14 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ |
|
15 /* this file you indicate that you have read the license and */ |
|
16 /* understand and accept it fully. */ |
|
17 /* */ |
|
18 /***************************************************************************/ |
|
19 |
|
20 |
|
21 #include <ft2build.h> |
|
22 #include FT_INTERNAL_DEBUG_H |
|
23 #include FT_INTERNAL_STREAM_H |
|
24 #include FT_TRUETYPE_TAGS_H |
|
25 #include "ttload.h" |
|
26 |
|
27 #include "sferrors.h" |
|
28 |
|
29 |
|
30 /*************************************************************************/ |
|
31 /* */ |
|
32 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ |
|
33 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ |
|
34 /* messages during execution. */ |
|
35 /* */ |
|
36 #undef FT_COMPONENT |
|
37 #define FT_COMPONENT trace_ttload |
|
38 |
|
39 |
|
40 /*************************************************************************/ |
|
41 /* */ |
|
42 /* <Function> */ |
|
43 /* tt_face_lookup_table */ |
|
44 /* */ |
|
45 /* <Description> */ |
|
46 /* Looks for a TrueType table by name. */ |
|
47 /* */ |
|
48 /* <Input> */ |
|
49 /* face :: A face object handle. */ |
|
50 /* */ |
|
51 /* tag :: The searched tag. */ |
|
52 /* */ |
|
53 /* <Return> */ |
|
54 /* A pointer to the table directory entry. 0 if not found. */ |
|
55 /* */ |
|
56 FT_LOCAL_DEF( TT_Table ) |
|
57 tt_face_lookup_table( TT_Face face, |
|
58 FT_ULong tag ) |
|
59 { |
|
60 TT_Table entry; |
|
61 TT_Table limit; |
|
62 #ifdef FT_DEBUG_LEVEL_TRACE |
|
63 FT_Bool zero_length = FALSE; |
|
64 #endif |
|
65 |
|
66 |
|
67 FT_TRACE4(( "tt_face_lookup_table: %08p, `%c%c%c%c' -- ", |
|
68 face, |
|
69 (FT_Char)( tag >> 24 ), |
|
70 (FT_Char)( tag >> 16 ), |
|
71 (FT_Char)( tag >> 8 ), |
|
72 (FT_Char)( tag ) )); |
|
73 |
|
74 entry = face->dir_tables; |
|
75 limit = entry + face->num_tables; |
|
76 |
|
77 for ( ; entry < limit; entry++ ) |
|
78 { |
|
79 /* For compatibility with Windows, we consider */ |
|
80 /* zero-length tables the same as missing tables. */ |
|
81 if ( entry->Tag == tag ) |
|
82 { |
|
83 if ( entry->Length != 0 ) |
|
84 { |
|
85 FT_TRACE4(( "found table.\n" )); |
|
86 return entry; |
|
87 } |
|
88 #ifdef FT_DEBUG_LEVEL_TRACE |
|
89 zero_length = TRUE; |
|
90 #endif |
|
91 } |
|
92 } |
|
93 |
|
94 #ifdef FT_DEBUG_LEVEL_TRACE |
|
95 if ( zero_length ) |
|
96 FT_TRACE4(( "ignoring empty table\n" )); |
|
97 else |
|
98 FT_TRACE4(( "could not find table\n" )); |
|
99 #endif |
|
100 |
|
101 return NULL; |
|
102 } |
|
103 |
|
104 |
|
105 /*************************************************************************/ |
|
106 /* */ |
|
107 /* <Function> */ |
|
108 /* tt_face_goto_table */ |
|
109 /* */ |
|
110 /* <Description> */ |
|
111 /* Looks for a TrueType table by name, then seek a stream to it. */ |
|
112 /* */ |
|
113 /* <Input> */ |
|
114 /* face :: A face object handle. */ |
|
115 /* */ |
|
116 /* tag :: The searched tag. */ |
|
117 /* */ |
|
118 /* stream :: The stream to seek when the table is found. */ |
|
119 /* */ |
|
120 /* <Output> */ |
|
121 /* length :: The length of the table if found, undefined otherwise. */ |
|
122 /* */ |
|
123 /* <Return> */ |
|
124 /* FreeType error code. 0 means success. */ |
|
125 /* */ |
|
126 FT_LOCAL_DEF( FT_Error ) |
|
127 tt_face_goto_table( TT_Face face, |
|
128 FT_ULong tag, |
|
129 FT_Stream stream, |
|
130 FT_ULong* length ) |
|
131 { |
|
132 TT_Table table; |
|
133 FT_Error error; |
|
134 |
|
135 |
|
136 table = tt_face_lookup_table( face, tag ); |
|
137 if ( table ) |
|
138 { |
|
139 if ( length ) |
|
140 *length = table->Length; |
|
141 |
|
142 if ( FT_STREAM_SEEK( table->Offset ) ) |
|
143 goto Exit; |
|
144 } |
|
145 else |
|
146 error = SFNT_Err_Table_Missing; |
|
147 |
|
148 Exit: |
|
149 return error; |
|
150 } |
|
151 |
|
152 |
|
153 /* Here, we */ |
|
154 /* */ |
|
155 /* - check that `num_tables' is valid (and adjust it if necessary) */ |
|
156 /* */ |
|
157 /* - look for a `head' table, check its size, and parse it to check */ |
|
158 /* whether its `magic' field is correctly set */ |
|
159 /* */ |
|
160 /* - errors (except errors returned by stream handling) */ |
|
161 /* */ |
|
162 /* SFNT_Err_Unknown_File_Format: */ |
|
163 /* no table is defined in directory, it is not sfnt-wrapped */ |
|
164 /* data */ |
|
165 /* SFNT_Err_Table_Missing: */ |
|
166 /* table directory is valid, but essential tables */ |
|
167 /* (head/bhed/SING) are missing */ |
|
168 /* */ |
|
169 static FT_Error |
|
170 check_table_dir( SFNT_Header sfnt, |
|
171 FT_Stream stream ) |
|
172 { |
|
173 FT_Error error; |
|
174 FT_UShort nn, valid_entries = 0; |
|
175 FT_UInt has_head = 0, has_sing = 0, has_meta = 0; |
|
176 FT_ULong offset = sfnt->offset + 12; |
|
177 |
|
178 static const FT_Frame_Field table_dir_entry_fields[] = |
|
179 { |
|
180 #undef FT_STRUCTURE |
|
181 #define FT_STRUCTURE TT_TableRec |
|
182 |
|
183 FT_FRAME_START( 16 ), |
|
184 FT_FRAME_ULONG( Tag ), |
|
185 FT_FRAME_ULONG( CheckSum ), |
|
186 FT_FRAME_ULONG( Offset ), |
|
187 FT_FRAME_ULONG( Length ), |
|
188 FT_FRAME_END |
|
189 }; |
|
190 |
|
191 |
|
192 if ( FT_STREAM_SEEK( offset ) ) |
|
193 goto Exit; |
|
194 |
|
195 for ( nn = 0; nn < sfnt->num_tables; nn++ ) |
|
196 { |
|
197 TT_TableRec table; |
|
198 |
|
199 |
|
200 if ( FT_STREAM_READ_FIELDS( table_dir_entry_fields, &table ) ) |
|
201 { |
|
202 nn--; |
|
203 FT_TRACE2(( "check_table_dir:" |
|
204 " can read only %d table%s in font (instead of %d)\n", |
|
205 nn, nn == 1 ? "" : "s", sfnt->num_tables )); |
|
206 sfnt->num_tables = nn; |
|
207 break; |
|
208 } |
|
209 |
|
210 /* we ignore invalid tables */ |
|
211 if ( table.Offset + table.Length > stream->size ) |
|
212 { |
|
213 FT_TRACE2(( "check_table_dir: table entry %d invalid\n", nn )); |
|
214 continue; |
|
215 } |
|
216 else |
|
217 valid_entries++; |
|
218 |
|
219 if ( table.Tag == TTAG_head || table.Tag == TTAG_bhed ) |
|
220 { |
|
221 FT_UInt32 magic; |
|
222 |
|
223 |
|
224 #ifndef TT_CONFIG_OPTION_EMBEDDED_BITMAPS |
|
225 if ( table.Tag == TTAG_head ) |
|
226 #endif |
|
227 has_head = 1; |
|
228 |
|
229 /* |
|
230 * The table length should be 0x36, but certain font tools make it |
|
231 * 0x38, so we will just check that it is greater. |
|
232 * |
|
233 * Note that according to the specification, the table must be |
|
234 * padded to 32-bit lengths, but this doesn't apply to the value of |
|
235 * its `Length' field! |
|
236 * |
|
237 */ |
|
238 if ( table.Length < 0x36 ) |
|
239 { |
|
240 FT_TRACE2(( "check_table_dir: `head' table too small\n" )); |
|
241 error = SFNT_Err_Table_Missing; |
|
242 goto Exit; |
|
243 } |
|
244 |
|
245 if ( FT_STREAM_SEEK( table.Offset + 12 ) || |
|
246 FT_READ_ULONG( magic ) ) |
|
247 goto Exit; |
|
248 |
|
249 if ( magic != 0x5F0F3CF5UL ) |
|
250 { |
|
251 FT_TRACE2(( "check_table_dir:" |
|
252 " no magic number found in `head' table\n")); |
|
253 error = SFNT_Err_Table_Missing; |
|
254 goto Exit; |
|
255 } |
|
256 |
|
257 if ( FT_STREAM_SEEK( offset + ( nn + 1 ) * 16 ) ) |
|
258 goto Exit; |
|
259 } |
|
260 else if ( table.Tag == TTAG_SING ) |
|
261 has_sing = 1; |
|
262 else if ( table.Tag == TTAG_META ) |
|
263 has_meta = 1; |
|
264 } |
|
265 |
|
266 sfnt->num_tables = valid_entries; |
|
267 |
|
268 if ( sfnt->num_tables == 0 ) |
|
269 { |
|
270 FT_TRACE2(( "check_table_dir: no tables found\n" )); |
|
271 error = SFNT_Err_Unknown_File_Format; |
|
272 goto Exit; |
|
273 } |
|
274 |
|
275 /* if `sing' and `meta' tables are present, there is no `head' table */ |
|
276 if ( has_head || ( has_sing && has_meta ) ) |
|
277 { |
|
278 error = SFNT_Err_Ok; |
|
279 goto Exit; |
|
280 } |
|
281 else |
|
282 { |
|
283 FT_TRACE2(( "check_table_dir:" )); |
|
284 #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS |
|
285 FT_TRACE2(( " neither `head', `bhed', nor `sing' table found\n" )); |
|
286 #else |
|
287 FT_TRACE2(( " neither `head' nor `sing' table found\n" )); |
|
288 #endif |
|
289 error = SFNT_Err_Table_Missing; |
|
290 } |
|
291 |
|
292 Exit: |
|
293 return error; |
|
294 } |
|
295 |
|
296 |
|
297 /*************************************************************************/ |
|
298 /* */ |
|
299 /* <Function> */ |
|
300 /* tt_face_load_font_dir */ |
|
301 /* */ |
|
302 /* <Description> */ |
|
303 /* Loads the header of a SFNT font file. */ |
|
304 /* */ |
|
305 /* <Input> */ |
|
306 /* face :: A handle to the target face object. */ |
|
307 /* */ |
|
308 /* stream :: The input stream. */ |
|
309 /* */ |
|
310 /* <Output> */ |
|
311 /* sfnt :: The SFNT header. */ |
|
312 /* */ |
|
313 /* <Return> */ |
|
314 /* FreeType error code. 0 means success. */ |
|
315 /* */ |
|
316 /* <Note> */ |
|
317 /* The stream cursor must be at the beginning of the font directory. */ |
|
318 /* */ |
|
319 FT_LOCAL_DEF( FT_Error ) |
|
320 tt_face_load_font_dir( TT_Face face, |
|
321 FT_Stream stream ) |
|
322 { |
|
323 SFNT_HeaderRec sfnt; |
|
324 FT_Error error; |
|
325 FT_Memory memory = stream->memory; |
|
326 TT_TableRec* entry; |
|
327 FT_Int nn; |
|
328 |
|
329 static const FT_Frame_Field offset_table_fields[] = |
|
330 { |
|
331 #undef FT_STRUCTURE |
|
332 #define FT_STRUCTURE SFNT_HeaderRec |
|
333 |
|
334 FT_FRAME_START( 8 ), |
|
335 FT_FRAME_USHORT( num_tables ), |
|
336 FT_FRAME_USHORT( search_range ), |
|
337 FT_FRAME_USHORT( entry_selector ), |
|
338 FT_FRAME_USHORT( range_shift ), |
|
339 FT_FRAME_END |
|
340 }; |
|
341 |
|
342 |
|
343 FT_TRACE2(( "tt_face_load_font_dir: %08p\n", face )); |
|
344 |
|
345 /* read the offset table */ |
|
346 |
|
347 sfnt.offset = FT_STREAM_POS(); |
|
348 |
|
349 if ( FT_READ_ULONG( sfnt.format_tag ) || |
|
350 FT_STREAM_READ_FIELDS( offset_table_fields, &sfnt ) ) |
|
351 goto Exit; |
|
352 |
|
353 /* many fonts don't have these fields set correctly */ |
|
354 #if 0 |
|
355 if ( sfnt.search_range != 1 << ( sfnt.entry_selector + 4 ) || |
|
356 sfnt.search_range + sfnt.range_shift != sfnt.num_tables << 4 ) |
|
357 return SFNT_Err_Unknown_File_Format; |
|
358 #endif |
|
359 |
|
360 /* load the table directory */ |
|
361 |
|
362 FT_TRACE2(( "-- Number of tables: %10u\n", sfnt.num_tables )); |
|
363 FT_TRACE2(( "-- Format version: 0x%08lx\n", sfnt.format_tag )); |
|
364 |
|
365 /* check first */ |
|
366 error = check_table_dir( &sfnt, stream ); |
|
367 if ( error ) |
|
368 { |
|
369 FT_TRACE2(( "tt_face_load_font_dir:" |
|
370 " invalid table directory for TrueType\n" )); |
|
371 |
|
372 goto Exit; |
|
373 } |
|
374 |
|
375 face->num_tables = sfnt.num_tables; |
|
376 face->format_tag = sfnt.format_tag; |
|
377 |
|
378 if ( FT_QNEW_ARRAY( face->dir_tables, face->num_tables ) ) |
|
379 goto Exit; |
|
380 |
|
381 if ( FT_STREAM_SEEK( sfnt.offset + 12 ) || |
|
382 FT_FRAME_ENTER( face->num_tables * 16L ) ) |
|
383 goto Exit; |
|
384 |
|
385 entry = face->dir_tables; |
|
386 |
|
387 FT_TRACE2(( "\n" |
|
388 " tag offset length checksum\n" |
|
389 " ----------------------------------\n" )); |
|
390 |
|
391 for ( nn = 0; nn < sfnt.num_tables; nn++ ) |
|
392 { |
|
393 entry->Tag = FT_GET_TAG4(); |
|
394 entry->CheckSum = FT_GET_ULONG(); |
|
395 entry->Offset = FT_GET_LONG(); |
|
396 entry->Length = FT_GET_LONG(); |
|
397 |
|
398 /* ignore invalid tables */ |
|
399 if ( entry->Offset + entry->Length > stream->size ) |
|
400 continue; |
|
401 else |
|
402 { |
|
403 FT_TRACE2(( " %c%c%c%c %08lx %08lx %08lx\n", |
|
404 (FT_Char)( entry->Tag >> 24 ), |
|
405 (FT_Char)( entry->Tag >> 16 ), |
|
406 (FT_Char)( entry->Tag >> 8 ), |
|
407 (FT_Char)( entry->Tag ), |
|
408 entry->Offset, |
|
409 entry->Length, |
|
410 entry->CheckSum )); |
|
411 entry++; |
|
412 } |
|
413 } |
|
414 |
|
415 FT_FRAME_EXIT(); |
|
416 |
|
417 FT_TRACE2(( "table directory loaded\n\n" )); |
|
418 |
|
419 Exit: |
|
420 return error; |
|
421 } |
|
422 |
|
423 |
|
424 /*************************************************************************/ |
|
425 /* */ |
|
426 /* <Function> */ |
|
427 /* tt_face_load_any */ |
|
428 /* */ |
|
429 /* <Description> */ |
|
430 /* Loads any font table into client memory. */ |
|
431 /* */ |
|
432 /* <Input> */ |
|
433 /* face :: The face object to look for. */ |
|
434 /* */ |
|
435 /* tag :: The tag of table to load. Use the value 0 if you want */ |
|
436 /* to access the whole font file, else set this parameter */ |
|
437 /* to a valid TrueType table tag that you can forge with */ |
|
438 /* the MAKE_TT_TAG macro. */ |
|
439 /* */ |
|
440 /* offset :: The starting offset in the table (or the file if */ |
|
441 /* tag == 0). */ |
|
442 /* */ |
|
443 /* length :: The address of the decision variable: */ |
|
444 /* */ |
|
445 /* If length == NULL: */ |
|
446 /* Loads the whole table. Returns an error if */ |
|
447 /* `offset' == 0! */ |
|
448 /* */ |
|
449 /* If *length == 0: */ |
|
450 /* Exits immediately; returning the length of the given */ |
|
451 /* table or of the font file, depending on the value of */ |
|
452 /* `tag'. */ |
|
453 /* */ |
|
454 /* If *length != 0: */ |
|
455 /* Loads the next `length' bytes of table or font, */ |
|
456 /* starting at offset `offset' (in table or font too). */ |
|
457 /* */ |
|
458 /* <Output> */ |
|
459 /* buffer :: The address of target buffer. */ |
|
460 /* */ |
|
461 /* <Return> */ |
|
462 /* FreeType error code. 0 means success. */ |
|
463 /* */ |
|
464 FT_LOCAL_DEF( FT_Error ) |
|
465 tt_face_load_any( TT_Face face, |
|
466 FT_ULong tag, |
|
467 FT_Long offset, |
|
468 FT_Byte* buffer, |
|
469 FT_ULong* length ) |
|
470 { |
|
471 FT_Error error; |
|
472 FT_Stream stream; |
|
473 TT_Table table; |
|
474 FT_ULong size; |
|
475 |
|
476 |
|
477 if ( tag != 0 ) |
|
478 { |
|
479 /* look for tag in font directory */ |
|
480 table = tt_face_lookup_table( face, tag ); |
|
481 if ( !table ) |
|
482 { |
|
483 error = SFNT_Err_Table_Missing; |
|
484 goto Exit; |
|
485 } |
|
486 |
|
487 offset += table->Offset; |
|
488 size = table->Length; |
|
489 } |
|
490 else |
|
491 /* tag == 0 -- the user wants to access the font file directly */ |
|
492 size = face->root.stream->size; |
|
493 |
|
494 if ( length && *length == 0 ) |
|
495 { |
|
496 *length = size; |
|
497 |
|
498 return SFNT_Err_Ok; |
|
499 } |
|
500 |
|
501 if ( length ) |
|
502 size = *length; |
|
503 |
|
504 stream = face->root.stream; |
|
505 /* the `if' is syntactic sugar for picky compilers */ |
|
506 if ( FT_STREAM_READ_AT( offset, buffer, size ) ) |
|
507 goto Exit; |
|
508 |
|
509 Exit: |
|
510 return error; |
|
511 } |
|
512 |
|
513 |
|
514 /*************************************************************************/ |
|
515 /* */ |
|
516 /* <Function> */ |
|
517 /* tt_face_load_generic_header */ |
|
518 /* */ |
|
519 /* <Description> */ |
|
520 /* Loads the TrueType table `head' or `bhed'. */ |
|
521 /* */ |
|
522 /* <Input> */ |
|
523 /* face :: A handle to the target face object. */ |
|
524 /* */ |
|
525 /* stream :: The input stream. */ |
|
526 /* */ |
|
527 /* <Return> */ |
|
528 /* FreeType error code. 0 means success. */ |
|
529 /* */ |
|
530 static FT_Error |
|
531 tt_face_load_generic_header( TT_Face face, |
|
532 FT_Stream stream, |
|
533 FT_ULong tag ) |
|
534 { |
|
535 FT_Error error; |
|
536 TT_Header* header; |
|
537 |
|
538 static const FT_Frame_Field header_fields[] = |
|
539 { |
|
540 #undef FT_STRUCTURE |
|
541 #define FT_STRUCTURE TT_Header |
|
542 |
|
543 FT_FRAME_START( 54 ), |
|
544 FT_FRAME_ULONG ( Table_Version ), |
|
545 FT_FRAME_ULONG ( Font_Revision ), |
|
546 FT_FRAME_LONG ( CheckSum_Adjust ), |
|
547 FT_FRAME_LONG ( Magic_Number ), |
|
548 FT_FRAME_USHORT( Flags ), |
|
549 FT_FRAME_USHORT( Units_Per_EM ), |
|
550 FT_FRAME_LONG ( Created[0] ), |
|
551 FT_FRAME_LONG ( Created[1] ), |
|
552 FT_FRAME_LONG ( Modified[0] ), |
|
553 FT_FRAME_LONG ( Modified[1] ), |
|
554 FT_FRAME_SHORT ( xMin ), |
|
555 FT_FRAME_SHORT ( yMin ), |
|
556 FT_FRAME_SHORT ( xMax ), |
|
557 FT_FRAME_SHORT ( yMax ), |
|
558 FT_FRAME_USHORT( Mac_Style ), |
|
559 FT_FRAME_USHORT( Lowest_Rec_PPEM ), |
|
560 FT_FRAME_SHORT ( Font_Direction ), |
|
561 FT_FRAME_SHORT ( Index_To_Loc_Format ), |
|
562 FT_FRAME_SHORT ( Glyph_Data_Format ), |
|
563 FT_FRAME_END |
|
564 }; |
|
565 |
|
566 |
|
567 error = face->goto_table( face, tag, stream, 0 ); |
|
568 if ( error ) |
|
569 goto Exit; |
|
570 |
|
571 header = &face->header; |
|
572 |
|
573 if ( FT_STREAM_READ_FIELDS( header_fields, header ) ) |
|
574 goto Exit; |
|
575 |
|
576 FT_TRACE3(( "Units per EM: %4u\n", header->Units_Per_EM )); |
|
577 FT_TRACE3(( "IndexToLoc: %4d\n", header->Index_To_Loc_Format )); |
|
578 |
|
579 Exit: |
|
580 return error; |
|
581 } |
|
582 |
|
583 |
|
584 FT_LOCAL_DEF( FT_Error ) |
|
585 tt_face_load_head( TT_Face face, |
|
586 FT_Stream stream ) |
|
587 { |
|
588 return tt_face_load_generic_header( face, stream, TTAG_head ); |
|
589 } |
|
590 |
|
591 |
|
592 #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS |
|
593 |
|
594 FT_LOCAL_DEF( FT_Error ) |
|
595 tt_face_load_bhed( TT_Face face, |
|
596 FT_Stream stream ) |
|
597 { |
|
598 return tt_face_load_generic_header( face, stream, TTAG_bhed ); |
|
599 } |
|
600 |
|
601 #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ |
|
602 |
|
603 |
|
604 /*************************************************************************/ |
|
605 /* */ |
|
606 /* <Function> */ |
|
607 /* tt_face_load_max_profile */ |
|
608 /* */ |
|
609 /* <Description> */ |
|
610 /* Loads the maximum profile into a face object. */ |
|
611 /* */ |
|
612 /* <Input> */ |
|
613 /* face :: A handle to the target face object. */ |
|
614 /* */ |
|
615 /* stream :: The input stream. */ |
|
616 /* */ |
|
617 /* <Return> */ |
|
618 /* FreeType error code. 0 means success. */ |
|
619 /* */ |
|
620 FT_LOCAL_DEF( FT_Error ) |
|
621 tt_face_load_maxp( TT_Face face, |
|
622 FT_Stream stream ) |
|
623 { |
|
624 FT_Error error; |
|
625 TT_MaxProfile* maxProfile = &face->max_profile; |
|
626 |
|
627 const FT_Frame_Field maxp_fields[] = |
|
628 { |
|
629 #undef FT_STRUCTURE |
|
630 #define FT_STRUCTURE TT_MaxProfile |
|
631 |
|
632 FT_FRAME_START( 6 ), |
|
633 FT_FRAME_LONG ( version ), |
|
634 FT_FRAME_USHORT( numGlyphs ), |
|
635 FT_FRAME_END |
|
636 }; |
|
637 |
|
638 const FT_Frame_Field maxp_fields_extra[] = |
|
639 { |
|
640 FT_FRAME_START( 26 ), |
|
641 FT_FRAME_USHORT( maxPoints ), |
|
642 FT_FRAME_USHORT( maxContours ), |
|
643 FT_FRAME_USHORT( maxCompositePoints ), |
|
644 FT_FRAME_USHORT( maxCompositeContours ), |
|
645 FT_FRAME_USHORT( maxZones ), |
|
646 FT_FRAME_USHORT( maxTwilightPoints ), |
|
647 FT_FRAME_USHORT( maxStorage ), |
|
648 FT_FRAME_USHORT( maxFunctionDefs ), |
|
649 FT_FRAME_USHORT( maxInstructionDefs ), |
|
650 FT_FRAME_USHORT( maxStackElements ), |
|
651 FT_FRAME_USHORT( maxSizeOfInstructions ), |
|
652 FT_FRAME_USHORT( maxComponentElements ), |
|
653 FT_FRAME_USHORT( maxComponentDepth ), |
|
654 FT_FRAME_END |
|
655 }; |
|
656 |
|
657 |
|
658 error = face->goto_table( face, TTAG_maxp, stream, 0 ); |
|
659 if ( error ) |
|
660 goto Exit; |
|
661 |
|
662 if ( FT_STREAM_READ_FIELDS( maxp_fields, maxProfile ) ) |
|
663 goto Exit; |
|
664 |
|
665 maxProfile->maxPoints = 0; |
|
666 maxProfile->maxContours = 0; |
|
667 maxProfile->maxCompositePoints = 0; |
|
668 maxProfile->maxCompositeContours = 0; |
|
669 maxProfile->maxZones = 0; |
|
670 maxProfile->maxTwilightPoints = 0; |
|
671 maxProfile->maxStorage = 0; |
|
672 maxProfile->maxFunctionDefs = 0; |
|
673 maxProfile->maxInstructionDefs = 0; |
|
674 maxProfile->maxStackElements = 0; |
|
675 maxProfile->maxSizeOfInstructions = 0; |
|
676 maxProfile->maxComponentElements = 0; |
|
677 maxProfile->maxComponentDepth = 0; |
|
678 |
|
679 if ( maxProfile->version >= 0x10000L ) |
|
680 { |
|
681 if ( FT_STREAM_READ_FIELDS( maxp_fields_extra, maxProfile ) ) |
|
682 goto Exit; |
|
683 |
|
684 /* XXX: an adjustment that is necessary to load certain */ |
|
685 /* broken fonts like `Keystrokes MT' :-( */ |
|
686 /* */ |
|
687 /* We allocate 64 function entries by default when */ |
|
688 /* the maxFunctionDefs value is smaller. */ |
|
689 |
|
690 if ( maxProfile->maxFunctionDefs < 64 ) |
|
691 maxProfile->maxFunctionDefs = 64; |
|
692 |
|
693 /* we add 4 phantom points later */ |
|
694 if ( maxProfile->maxTwilightPoints > ( 0xFFFFU - 4 ) ) |
|
695 { |
|
696 FT_TRACE0(( "tt_face_load_maxp:" |
|
697 " too much twilight points in `maxp' table;\n" |
|
698 " " |
|
699 " some glyphs might be rendered incorrectly\n" )); |
|
700 |
|
701 maxProfile->maxTwilightPoints = 0xFFFFU - 4; |
|
702 } |
|
703 |
|
704 /* we arbitrarily limit recursion to avoid stack exhaustion */ |
|
705 if ( maxProfile->maxComponentDepth > 100 ) |
|
706 { |
|
707 FT_TRACE0(( "tt_face_load_maxp:" |
|
708 " abnormally large component depth (%d) set to 100\n", |
|
709 maxProfile->maxComponentDepth )); |
|
710 maxProfile->maxComponentDepth = 100; |
|
711 } |
|
712 } |
|
713 |
|
714 FT_TRACE3(( "numGlyphs: %u\n", maxProfile->numGlyphs )); |
|
715 |
|
716 Exit: |
|
717 return error; |
|
718 } |
|
719 |
|
720 |
|
721 /*************************************************************************/ |
|
722 /* */ |
|
723 /* <Function> */ |
|
724 /* tt_face_load_names */ |
|
725 /* */ |
|
726 /* <Description> */ |
|
727 /* Loads the name records. */ |
|
728 /* */ |
|
729 /* <Input> */ |
|
730 /* face :: A handle to the target face object. */ |
|
731 /* */ |
|
732 /* stream :: The input stream. */ |
|
733 /* */ |
|
734 /* <Return> */ |
|
735 /* FreeType error code. 0 means success. */ |
|
736 /* */ |
|
737 FT_LOCAL_DEF( FT_Error ) |
|
738 tt_face_load_name( TT_Face face, |
|
739 FT_Stream stream ) |
|
740 { |
|
741 FT_Error error; |
|
742 FT_Memory memory = stream->memory; |
|
743 FT_ULong table_pos, table_len; |
|
744 FT_ULong storage_start, storage_limit; |
|
745 FT_UInt count; |
|
746 TT_NameTable table; |
|
747 |
|
748 static const FT_Frame_Field name_table_fields[] = |
|
749 { |
|
750 #undef FT_STRUCTURE |
|
751 #define FT_STRUCTURE TT_NameTableRec |
|
752 |
|
753 FT_FRAME_START( 6 ), |
|
754 FT_FRAME_USHORT( format ), |
|
755 FT_FRAME_USHORT( numNameRecords ), |
|
756 FT_FRAME_USHORT( storageOffset ), |
|
757 FT_FRAME_END |
|
758 }; |
|
759 |
|
760 static const FT_Frame_Field name_record_fields[] = |
|
761 { |
|
762 #undef FT_STRUCTURE |
|
763 #define FT_STRUCTURE TT_NameEntryRec |
|
764 |
|
765 /* no FT_FRAME_START */ |
|
766 FT_FRAME_USHORT( platformID ), |
|
767 FT_FRAME_USHORT( encodingID ), |
|
768 FT_FRAME_USHORT( languageID ), |
|
769 FT_FRAME_USHORT( nameID ), |
|
770 FT_FRAME_USHORT( stringLength ), |
|
771 FT_FRAME_USHORT( stringOffset ), |
|
772 FT_FRAME_END |
|
773 }; |
|
774 |
|
775 |
|
776 table = &face->name_table; |
|
777 table->stream = stream; |
|
778 |
|
779 error = face->goto_table( face, TTAG_name, stream, &table_len ); |
|
780 if ( error ) |
|
781 goto Exit; |
|
782 |
|
783 table_pos = FT_STREAM_POS(); |
|
784 |
|
785 |
|
786 if ( FT_STREAM_READ_FIELDS( name_table_fields, table ) ) |
|
787 goto Exit; |
|
788 |
|
789 /* Some popular Asian fonts have an invalid `storageOffset' value */ |
|
790 /* (it should be at least "6 + 12*num_names"). However, the string */ |
|
791 /* offsets, computed as "storageOffset + entry->stringOffset", are */ |
|
792 /* valid pointers within the name table... */ |
|
793 /* */ |
|
794 /* We thus can't check `storageOffset' right now. */ |
|
795 /* */ |
|
796 storage_start = table_pos + 6 + 12*table->numNameRecords; |
|
797 storage_limit = table_pos + table_len; |
|
798 |
|
799 if ( storage_start > storage_limit ) |
|
800 { |
|
801 FT_ERROR(( "tt_face_load_name: invalid `name' table\n" )); |
|
802 error = SFNT_Err_Name_Table_Missing; |
|
803 goto Exit; |
|
804 } |
|
805 |
|
806 /* Allocate the array of name records. */ |
|
807 count = table->numNameRecords; |
|
808 table->numNameRecords = 0; |
|
809 |
|
810 if ( FT_NEW_ARRAY( table->names, count ) || |
|
811 FT_FRAME_ENTER( count * 12 ) ) |
|
812 goto Exit; |
|
813 |
|
814 /* Load the name records and determine how much storage is needed */ |
|
815 /* to hold the strings themselves. */ |
|
816 { |
|
817 TT_NameEntryRec* entry = table->names; |
|
818 |
|
819 |
|
820 for ( ; count > 0; count-- ) |
|
821 { |
|
822 if ( FT_STREAM_READ_FIELDS( name_record_fields, entry ) ) |
|
823 continue; |
|
824 |
|
825 /* check that the name is not empty */ |
|
826 if ( entry->stringLength == 0 ) |
|
827 continue; |
|
828 |
|
829 /* check that the name string is within the table */ |
|
830 entry->stringOffset += table_pos + table->storageOffset; |
|
831 if ( entry->stringOffset < storage_start || |
|
832 entry->stringOffset + entry->stringLength > storage_limit ) |
|
833 { |
|
834 /* invalid entry - ignore it */ |
|
835 entry->stringOffset = 0; |
|
836 entry->stringLength = 0; |
|
837 continue; |
|
838 } |
|
839 |
|
840 entry++; |
|
841 } |
|
842 |
|
843 table->numNameRecords = (FT_UInt)( entry - table->names ); |
|
844 } |
|
845 |
|
846 FT_FRAME_EXIT(); |
|
847 |
|
848 /* everything went well, update face->num_names */ |
|
849 face->num_names = (FT_UShort) table->numNameRecords; |
|
850 |
|
851 Exit: |
|
852 return error; |
|
853 } |
|
854 |
|
855 |
|
856 /*************************************************************************/ |
|
857 /* */ |
|
858 /* <Function> */ |
|
859 /* tt_face_free_names */ |
|
860 /* */ |
|
861 /* <Description> */ |
|
862 /* Frees the name records. */ |
|
863 /* */ |
|
864 /* <Input> */ |
|
865 /* face :: A handle to the target face object. */ |
|
866 /* */ |
|
867 FT_LOCAL_DEF( void ) |
|
868 tt_face_free_name( TT_Face face ) |
|
869 { |
|
870 FT_Memory memory = face->root.driver->root.memory; |
|
871 TT_NameTable table = &face->name_table; |
|
872 TT_NameEntry entry = table->names; |
|
873 FT_UInt count = table->numNameRecords; |
|
874 |
|
875 |
|
876 if ( table->names ) |
|
877 { |
|
878 for ( ; count > 0; count--, entry++ ) |
|
879 { |
|
880 FT_FREE( entry->string ); |
|
881 entry->stringLength = 0; |
|
882 } |
|
883 |
|
884 /* free strings table */ |
|
885 FT_FREE( table->names ); |
|
886 } |
|
887 |
|
888 table->numNameRecords = 0; |
|
889 table->format = 0; |
|
890 table->storageOffset = 0; |
|
891 } |
|
892 |
|
893 |
|
894 /*************************************************************************/ |
|
895 /* */ |
|
896 /* <Function> */ |
|
897 /* tt_face_load_cmap */ |
|
898 /* */ |
|
899 /* <Description> */ |
|
900 /* Loads the cmap directory in a face object. The cmaps themselves */ |
|
901 /* are loaded on demand in the `ttcmap.c' module. */ |
|
902 /* */ |
|
903 /* <Input> */ |
|
904 /* face :: A handle to the target face object. */ |
|
905 /* */ |
|
906 /* stream :: A handle to the input stream. */ |
|
907 /* */ |
|
908 /* <Return> */ |
|
909 /* FreeType error code. 0 means success. */ |
|
910 /* */ |
|
911 |
|
912 FT_LOCAL_DEF( FT_Error ) |
|
913 tt_face_load_cmap( TT_Face face, |
|
914 FT_Stream stream ) |
|
915 { |
|
916 FT_Error error; |
|
917 |
|
918 |
|
919 error = face->goto_table( face, TTAG_cmap, stream, &face->cmap_size ); |
|
920 if ( error ) |
|
921 goto Exit; |
|
922 |
|
923 if ( FT_FRAME_EXTRACT( face->cmap_size, face->cmap_table ) ) |
|
924 face->cmap_size = 0; |
|
925 |
|
926 Exit: |
|
927 return error; |
|
928 } |
|
929 |
|
930 |
|
931 |
|
932 /*************************************************************************/ |
|
933 /* */ |
|
934 /* <Function> */ |
|
935 /* tt_face_load_os2 */ |
|
936 /* */ |
|
937 /* <Description> */ |
|
938 /* Loads the OS2 table. */ |
|
939 /* */ |
|
940 /* <Input> */ |
|
941 /* face :: A handle to the target face object. */ |
|
942 /* */ |
|
943 /* stream :: A handle to the input stream. */ |
|
944 /* */ |
|
945 /* <Return> */ |
|
946 /* FreeType error code. 0 means success. */ |
|
947 /* */ |
|
948 FT_LOCAL_DEF( FT_Error ) |
|
949 tt_face_load_os2( TT_Face face, |
|
950 FT_Stream stream ) |
|
951 { |
|
952 FT_Error error; |
|
953 TT_OS2* os2; |
|
954 |
|
955 const FT_Frame_Field os2_fields[] = |
|
956 { |
|
957 #undef FT_STRUCTURE |
|
958 #define FT_STRUCTURE TT_OS2 |
|
959 |
|
960 FT_FRAME_START( 78 ), |
|
961 FT_FRAME_USHORT( version ), |
|
962 FT_FRAME_SHORT ( xAvgCharWidth ), |
|
963 FT_FRAME_USHORT( usWeightClass ), |
|
964 FT_FRAME_USHORT( usWidthClass ), |
|
965 FT_FRAME_SHORT ( fsType ), |
|
966 FT_FRAME_SHORT ( ySubscriptXSize ), |
|
967 FT_FRAME_SHORT ( ySubscriptYSize ), |
|
968 FT_FRAME_SHORT ( ySubscriptXOffset ), |
|
969 FT_FRAME_SHORT ( ySubscriptYOffset ), |
|
970 FT_FRAME_SHORT ( ySuperscriptXSize ), |
|
971 FT_FRAME_SHORT ( ySuperscriptYSize ), |
|
972 FT_FRAME_SHORT ( ySuperscriptXOffset ), |
|
973 FT_FRAME_SHORT ( ySuperscriptYOffset ), |
|
974 FT_FRAME_SHORT ( yStrikeoutSize ), |
|
975 FT_FRAME_SHORT ( yStrikeoutPosition ), |
|
976 FT_FRAME_SHORT ( sFamilyClass ), |
|
977 FT_FRAME_BYTE ( panose[0] ), |
|
978 FT_FRAME_BYTE ( panose[1] ), |
|
979 FT_FRAME_BYTE ( panose[2] ), |
|
980 FT_FRAME_BYTE ( panose[3] ), |
|
981 FT_FRAME_BYTE ( panose[4] ), |
|
982 FT_FRAME_BYTE ( panose[5] ), |
|
983 FT_FRAME_BYTE ( panose[6] ), |
|
984 FT_FRAME_BYTE ( panose[7] ), |
|
985 FT_FRAME_BYTE ( panose[8] ), |
|
986 FT_FRAME_BYTE ( panose[9] ), |
|
987 FT_FRAME_ULONG ( ulUnicodeRange1 ), |
|
988 FT_FRAME_ULONG ( ulUnicodeRange2 ), |
|
989 FT_FRAME_ULONG ( ulUnicodeRange3 ), |
|
990 FT_FRAME_ULONG ( ulUnicodeRange4 ), |
|
991 FT_FRAME_BYTE ( achVendID[0] ), |
|
992 FT_FRAME_BYTE ( achVendID[1] ), |
|
993 FT_FRAME_BYTE ( achVendID[2] ), |
|
994 FT_FRAME_BYTE ( achVendID[3] ), |
|
995 |
|
996 FT_FRAME_USHORT( fsSelection ), |
|
997 FT_FRAME_USHORT( usFirstCharIndex ), |
|
998 FT_FRAME_USHORT( usLastCharIndex ), |
|
999 FT_FRAME_SHORT ( sTypoAscender ), |
|
1000 FT_FRAME_SHORT ( sTypoDescender ), |
|
1001 FT_FRAME_SHORT ( sTypoLineGap ), |
|
1002 FT_FRAME_USHORT( usWinAscent ), |
|
1003 FT_FRAME_USHORT( usWinDescent ), |
|
1004 FT_FRAME_END |
|
1005 }; |
|
1006 |
|
1007 const FT_Frame_Field os2_fields_extra[] = |
|
1008 { |
|
1009 FT_FRAME_START( 8 ), |
|
1010 FT_FRAME_ULONG( ulCodePageRange1 ), |
|
1011 FT_FRAME_ULONG( ulCodePageRange2 ), |
|
1012 FT_FRAME_END |
|
1013 }; |
|
1014 |
|
1015 const FT_Frame_Field os2_fields_extra2[] = |
|
1016 { |
|
1017 FT_FRAME_START( 10 ), |
|
1018 FT_FRAME_SHORT ( sxHeight ), |
|
1019 FT_FRAME_SHORT ( sCapHeight ), |
|
1020 FT_FRAME_USHORT( usDefaultChar ), |
|
1021 FT_FRAME_USHORT( usBreakChar ), |
|
1022 FT_FRAME_USHORT( usMaxContext ), |
|
1023 FT_FRAME_END |
|
1024 }; |
|
1025 |
|
1026 |
|
1027 /* We now support old Mac fonts where the OS/2 table doesn't */ |
|
1028 /* exist. Simply put, we set the `version' field to 0xFFFF */ |
|
1029 /* and test this value each time we need to access the table. */ |
|
1030 error = face->goto_table( face, TTAG_OS2, stream, 0 ); |
|
1031 if ( error ) |
|
1032 goto Exit; |
|
1033 |
|
1034 os2 = &face->os2; |
|
1035 |
|
1036 if ( FT_STREAM_READ_FIELDS( os2_fields, os2 ) ) |
|
1037 goto Exit; |
|
1038 |
|
1039 os2->ulCodePageRange1 = 0; |
|
1040 os2->ulCodePageRange2 = 0; |
|
1041 os2->sxHeight = 0; |
|
1042 os2->sCapHeight = 0; |
|
1043 os2->usDefaultChar = 0; |
|
1044 os2->usBreakChar = 0; |
|
1045 os2->usMaxContext = 0; |
|
1046 |
|
1047 if ( os2->version >= 0x0001 ) |
|
1048 { |
|
1049 /* only version 1 tables */ |
|
1050 if ( FT_STREAM_READ_FIELDS( os2_fields_extra, os2 ) ) |
|
1051 goto Exit; |
|
1052 |
|
1053 if ( os2->version >= 0x0002 ) |
|
1054 { |
|
1055 /* only version 2 tables */ |
|
1056 if ( FT_STREAM_READ_FIELDS( os2_fields_extra2, os2 ) ) |
|
1057 goto Exit; |
|
1058 } |
|
1059 } |
|
1060 |
|
1061 FT_TRACE3(( "sTypoAscender: %4d\n", os2->sTypoAscender )); |
|
1062 FT_TRACE3(( "sTypoDescender: %4d\n", os2->sTypoDescender )); |
|
1063 FT_TRACE3(( "usWinAscent: %4u\n", os2->usWinAscent )); |
|
1064 FT_TRACE3(( "usWinDescent: %4u\n", os2->usWinDescent )); |
|
1065 FT_TRACE3(( "fsSelection: 0x%2x\n", os2->fsSelection )); |
|
1066 |
|
1067 Exit: |
|
1068 return error; |
|
1069 } |
|
1070 |
|
1071 |
|
1072 /*************************************************************************/ |
|
1073 /* */ |
|
1074 /* <Function> */ |
|
1075 /* tt_face_load_postscript */ |
|
1076 /* */ |
|
1077 /* <Description> */ |
|
1078 /* Loads the Postscript table. */ |
|
1079 /* */ |
|
1080 /* <Input> */ |
|
1081 /* face :: A handle to the target face object. */ |
|
1082 /* */ |
|
1083 /* stream :: A handle to the input stream. */ |
|
1084 /* */ |
|
1085 /* <Return> */ |
|
1086 /* FreeType error code. 0 means success. */ |
|
1087 /* */ |
|
1088 FT_LOCAL_DEF( FT_Error ) |
|
1089 tt_face_load_post( TT_Face face, |
|
1090 FT_Stream stream ) |
|
1091 { |
|
1092 FT_Error error; |
|
1093 TT_Postscript* post = &face->postscript; |
|
1094 |
|
1095 static const FT_Frame_Field post_fields[] = |
|
1096 { |
|
1097 #undef FT_STRUCTURE |
|
1098 #define FT_STRUCTURE TT_Postscript |
|
1099 |
|
1100 FT_FRAME_START( 32 ), |
|
1101 FT_FRAME_ULONG( FormatType ), |
|
1102 FT_FRAME_ULONG( italicAngle ), |
|
1103 FT_FRAME_SHORT( underlinePosition ), |
|
1104 FT_FRAME_SHORT( underlineThickness ), |
|
1105 FT_FRAME_ULONG( isFixedPitch ), |
|
1106 FT_FRAME_ULONG( minMemType42 ), |
|
1107 FT_FRAME_ULONG( maxMemType42 ), |
|
1108 FT_FRAME_ULONG( minMemType1 ), |
|
1109 FT_FRAME_ULONG( maxMemType1 ), |
|
1110 FT_FRAME_END |
|
1111 }; |
|
1112 |
|
1113 |
|
1114 error = face->goto_table( face, TTAG_post, stream, 0 ); |
|
1115 if ( error ) |
|
1116 return error; |
|
1117 |
|
1118 if ( FT_STREAM_READ_FIELDS( post_fields, post ) ) |
|
1119 return error; |
|
1120 |
|
1121 /* we don't load the glyph names, we do that in another */ |
|
1122 /* module (ttpost). */ |
|
1123 |
|
1124 FT_TRACE3(( "FormatType: 0x%x\n", post->FormatType )); |
|
1125 FT_TRACE3(( "isFixedPitch: %s\n", post->isFixedPitch |
|
1126 ? " yes" : " no" )); |
|
1127 |
|
1128 return SFNT_Err_Ok; |
|
1129 } |
|
1130 |
|
1131 |
|
1132 /*************************************************************************/ |
|
1133 /* */ |
|
1134 /* <Function> */ |
|
1135 /* tt_face_load_pclt */ |
|
1136 /* */ |
|
1137 /* <Description> */ |
|
1138 /* Loads the PCL 5 Table. */ |
|
1139 /* */ |
|
1140 /* <Input> */ |
|
1141 /* face :: A handle to the target face object. */ |
|
1142 /* */ |
|
1143 /* stream :: A handle to the input stream. */ |
|
1144 /* */ |
|
1145 /* <Return> */ |
|
1146 /* FreeType error code. 0 means success. */ |
|
1147 /* */ |
|
1148 FT_LOCAL_DEF( FT_Error ) |
|
1149 tt_face_load_pclt( TT_Face face, |
|
1150 FT_Stream stream ) |
|
1151 { |
|
1152 static const FT_Frame_Field pclt_fields[] = |
|
1153 { |
|
1154 #undef FT_STRUCTURE |
|
1155 #define FT_STRUCTURE TT_PCLT |
|
1156 |
|
1157 FT_FRAME_START( 54 ), |
|
1158 FT_FRAME_ULONG ( Version ), |
|
1159 FT_FRAME_ULONG ( FontNumber ), |
|
1160 FT_FRAME_USHORT( Pitch ), |
|
1161 FT_FRAME_USHORT( xHeight ), |
|
1162 FT_FRAME_USHORT( Style ), |
|
1163 FT_FRAME_USHORT( TypeFamily ), |
|
1164 FT_FRAME_USHORT( CapHeight ), |
|
1165 FT_FRAME_BYTES ( TypeFace, 16 ), |
|
1166 FT_FRAME_BYTES ( CharacterComplement, 8 ), |
|
1167 FT_FRAME_BYTES ( FileName, 6 ), |
|
1168 FT_FRAME_CHAR ( StrokeWeight ), |
|
1169 FT_FRAME_CHAR ( WidthType ), |
|
1170 FT_FRAME_BYTE ( SerifStyle ), |
|
1171 FT_FRAME_BYTE ( Reserved ), |
|
1172 FT_FRAME_END |
|
1173 }; |
|
1174 |
|
1175 FT_Error error; |
|
1176 TT_PCLT* pclt = &face->pclt; |
|
1177 |
|
1178 |
|
1179 /* optional table */ |
|
1180 error = face->goto_table( face, TTAG_PCLT, stream, 0 ); |
|
1181 if ( error ) |
|
1182 goto Exit; |
|
1183 |
|
1184 if ( FT_STREAM_READ_FIELDS( pclt_fields, pclt ) ) |
|
1185 goto Exit; |
|
1186 |
|
1187 Exit: |
|
1188 return error; |
|
1189 } |
|
1190 |
|
1191 |
|
1192 /*************************************************************************/ |
|
1193 /* */ |
|
1194 /* <Function> */ |
|
1195 /* tt_face_load_gasp */ |
|
1196 /* */ |
|
1197 /* <Description> */ |
|
1198 /* Loads the `gasp' table into a face object. */ |
|
1199 /* */ |
|
1200 /* <Input> */ |
|
1201 /* face :: A handle to the target face object. */ |
|
1202 /* */ |
|
1203 /* stream :: The input stream. */ |
|
1204 /* */ |
|
1205 /* <Return> */ |
|
1206 /* FreeType error code. 0 means success. */ |
|
1207 /* */ |
|
1208 FT_LOCAL_DEF( FT_Error ) |
|
1209 tt_face_load_gasp( TT_Face face, |
|
1210 FT_Stream stream ) |
|
1211 { |
|
1212 FT_Error error; |
|
1213 FT_Memory memory = stream->memory; |
|
1214 |
|
1215 FT_UInt j,num_ranges; |
|
1216 TT_GaspRange gaspranges; |
|
1217 |
|
1218 |
|
1219 /* the gasp table is optional */ |
|
1220 error = face->goto_table( face, TTAG_gasp, stream, 0 ); |
|
1221 if ( error ) |
|
1222 goto Exit; |
|
1223 |
|
1224 if ( FT_FRAME_ENTER( 4L ) ) |
|
1225 goto Exit; |
|
1226 |
|
1227 face->gasp.version = FT_GET_USHORT(); |
|
1228 face->gasp.numRanges = FT_GET_USHORT(); |
|
1229 |
|
1230 FT_FRAME_EXIT(); |
|
1231 |
|
1232 /* only support versions 0 and 1 of the table */ |
|
1233 if ( face->gasp.version >= 2 ) |
|
1234 { |
|
1235 face->gasp.numRanges = 0; |
|
1236 error = SFNT_Err_Invalid_Table; |
|
1237 goto Exit; |
|
1238 } |
|
1239 |
|
1240 num_ranges = face->gasp.numRanges; |
|
1241 FT_TRACE3(( "numRanges: %u\n", num_ranges )); |
|
1242 |
|
1243 if ( FT_QNEW_ARRAY( gaspranges, num_ranges ) || |
|
1244 FT_FRAME_ENTER( num_ranges * 4L ) ) |
|
1245 goto Exit; |
|
1246 |
|
1247 face->gasp.gaspRanges = gaspranges; |
|
1248 |
|
1249 for ( j = 0; j < num_ranges; j++ ) |
|
1250 { |
|
1251 gaspranges[j].maxPPEM = FT_GET_USHORT(); |
|
1252 gaspranges[j].gaspFlag = FT_GET_USHORT(); |
|
1253 |
|
1254 FT_TRACE3(( "gaspRange %d: rangeMaxPPEM %5d, rangeGaspBehavior 0x%x\n", |
|
1255 j, |
|
1256 gaspranges[j].maxPPEM, |
|
1257 gaspranges[j].gaspFlag )); |
|
1258 } |
|
1259 |
|
1260 FT_FRAME_EXIT(); |
|
1261 |
|
1262 Exit: |
|
1263 return error; |
|
1264 } |
|
1265 |
|
1266 |
|
1267 /* END */ |
|