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 by */
9 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
10 /* */
11 /* This file is part of the FreeType project, and may only be used, */
12 /* modified, and distributed under the terms of the FreeType project */
13 /* 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 /* */
17 /***************************************************************************/
20 #include <ft2build.h>
21 #include FT_INTERNAL_DEBUG_H
22 #include FT_INTERNAL_STREAM_H
23 #include FT_TRUETYPE_TAGS_H
24 #include "ttload.h"
25 #include "ttcmap.h"
27 #include "sferrors.h"
29 #include <stdlib.h> /* for qsort */
31 /*************************************************************************/
32 /* */
33 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
34 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
35 /* messages during execution. */
36 /* */
37 #undef FT_COMPONENT
38 #define FT_COMPONENT trace_ttload
41 /*************************************************************************/
42 /* */
43 /* <Function> */
44 /* TT_LookUp_Table */
45 /* */
46 /* <Description> */
47 /* Looks for a TrueType table by name. */
48 /* */
49 /* <Input> */
50 /* face :: A face object handle. */
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_LookUp_Table( TT_Face face,
58 FT_ULong tag )
59 {
60 TT_Table* entry;
61 TT_Table* limit;
64 FT_TRACE3(( "TT_LookUp_Table: %08p, `%c%c%c%c' -- ",
65 face,
66 (FT_Char)( tag >> 24 ),
67 (FT_Char)( tag >> 16 ),
68 (FT_Char)( tag >> 8 ),
69 (FT_Char)( tag ) ));
71 entry = face->dir_tables;
72 limit = entry + face->num_tables;
74 for ( ; entry < limit; entry++ )
75 {
76 if ( entry->Tag == tag )
77 {
78 FT_TRACE3(( "found table.\n" ));
79 return entry;
80 }
81 }
83 FT_TRACE3(( "could not find table!\n" ));
84 return 0;
85 }
88 /*************************************************************************/
89 /* */
90 /* <Function> */
91 /* TT_Goto_Table */
92 /* */
93 /* <Description> */
94 /* Looks for a TrueType table by name, then seek a stream to it. */
95 /* */
96 /* <Input> */
97 /* face :: A face object handle. */
98 /* tag :: The searched tag. */
99 /* stream :: The stream to seek when the table is found. */
100 /* */
101 /* <Output> */
102 /* length :: The length of the table if found, undefined otherwise. */
103 /* */
104 /* <Return> */
105 /* FreeType error code. 0 means success. */
106 /* */
107 FT_LOCAL_DEF FT_Error
108 TT_Goto_Table( TT_Face face,
109 FT_ULong tag,
110 FT_Stream stream,
111 FT_ULong* length )
112 {
113 TT_Table* table;
114 FT_Error error;
117 table = TT_LookUp_Table( face, tag );
118 if ( table )
119 {
120 if ( length )
121 *length = table->Length;
123 if ( FILE_Seek( table->Offset ) )
124 goto Exit;
125 }
126 else
127 error = SFNT_Err_Table_Missing;
129 Exit:
130 return error;
131 }
134 /*************************************************************************/
135 /* */
136 /* <Function> */
137 /* TT_Load_SFNT_Header */
138 /* */
139 /* <Description> */
140 /* Loads the header of a SFNT font file. Supports collections. */
141 /* */
142 /* <Input> */
143 /* face :: A handle to the target face object. */
144 /* stream :: The input stream. */
145 /* face_index :: If the font is a collection, the number of the font */
146 /* in the collection, ignored otherwise. */
147 /* */
148 /* <Output> */
149 /* sfnt :: The SFNT header. */
150 /* */
151 /* <Return> */
152 /* FreeType error code. 0 means success. */
153 /* */
154 /* <Note> */
155 /* The stream cursor must be at the font file's origin. */
156 /* */
157 /* This function recognizes fonts embedded in a `TrueType collection' */
158 /* */
159 /* The header will be checked whether it is valid by looking at the */
160 /* values of `search_range', `entry_selector', and `range_shift'. */
161 /* */
162 FT_LOCAL_DEF FT_Error
163 TT_Load_SFNT_Header( TT_Face face,
164 FT_Stream stream,
165 FT_Long face_index,
166 SFNT_Header* sfnt )
167 {
168 FT_Error error;
169 FT_ULong format_tag;
170 FT_Memory memory = stream->memory;
172 const FT_Frame_Field sfnt_header_fields[] =
173 {
174 #undef FT_STRUCTURE
175 #define FT_STRUCTURE SFNT_Header
177 FT_FRAME_START( 8 ),
178 FT_FRAME_USHORT( num_tables ),
179 FT_FRAME_USHORT( search_range ),
180 FT_FRAME_USHORT( entry_selector ),
181 FT_FRAME_USHORT( range_shift ),
182 FT_FRAME_END
183 };
185 const FT_Frame_Field ttc_header_fields[] =
186 {
187 #undef FT_STRUCTURE
188 #define FT_STRUCTURE TTC_Header
190 FT_FRAME_START( 8 ),
191 FT_FRAME_LONG( version ),
192 FT_FRAME_LONG( count ),
193 FT_FRAME_END };
196 FT_TRACE2(( "TT_Load_SFNT_Header: %08p, %ld\n",
197 face, face_index ));
199 face->ttc_header.tag = 0;
200 face->ttc_header.version = 0;
201 face->ttc_header.count = 0;
203 face->num_tables = 0;
205 /* first of all, read the first 4 bytes. If it is `ttcf', then the */
206 /* file is a TrueType collection, otherwise it can be any other */
207 /* kind of font. */
208 if ( READ_ULong( format_tag ) )
209 goto Exit;
211 if ( format_tag == TTAG_ttcf )
212 {
213 FT_Int n;
216 FT_TRACE3(( "TT_Load_SFNT_Header: file is a collection\n" ));
218 /* it's a TrueType collection, i.e. a file containing several */
219 /* font files. Read the font directory now */
220 if ( READ_Fields( ttc_header_fields, &face->ttc_header ) )
221 goto Exit;
223 /* now read the offsets of each font in the file */
224 if ( ALLOC_ARRAY( face->ttc_header.offsets,
225 face->ttc_header.count,
226 FT_ULong ) ||
227 ACCESS_Frame( face->ttc_header.count * 4L ) )
228 goto Exit;
230 for ( n = 0; n < face->ttc_header.count; n++ )
231 face->ttc_header.offsets[n] = GET_ULong();
233 FORGET_Frame();
235 /* check face index */
236 if ( face_index >= face->ttc_header.count )
237 {
238 error = SFNT_Err_Bad_Argument;
239 goto Exit;
240 }
242 /* seek to the appropriate TrueType file, then read tag */
243 if ( FILE_Seek( face->ttc_header.offsets[face_index] ) ||
244 READ_Long( format_tag ) )
245 goto Exit;
246 }
248 /* the format tag was read, now check the rest of the header */
249 sfnt->format_tag = format_tag;
250 if ( READ_Fields( sfnt_header_fields, sfnt ) )
251 goto Exit;
253 /* now, check the values of `num_tables', `seach_range', etc. */
254 {
255 FT_UInt num_tables = sfnt->num_tables;
256 FT_ULong entry_selector = 1L << sfnt->entry_selector;
259 /* IMPORTANT: Many fonts have an incorrect `search_range' value, so */
260 /* we only check the `entry_selector' correctness here. */
261 /* */
262 if ( num_tables == 0 ||
263 entry_selector > num_tables ||
264 entry_selector * 2 <= num_tables )
265 {
266 FT_TRACE2(( "TT_Load_SFNT_Header: file is not SFNT!\n" ));
267 error = SFNT_Err_Unknown_File_Format;
268 }
269 }
271 Exit:
272 return error;
273 }
276 /*************************************************************************/
277 /* */
278 /* <Function> */
279 /* TT_Load_Directory */
280 /* */
281 /* <Description> */
282 /* Loads the table directory into a face object. */
283 /* */
284 /* <InOut> */
285 /* face :: A handle to the target face object. */
286 /* */
287 /* <Input> */
288 /* stream :: The input stream. */
289 /* sfnt :: The SFNT directory header. */
290 /* */
291 /* <Return> */
292 /* FreeType error code. 0 means success. */
293 /* */
294 /* <Note> */
295 /* The stream cursor must be at the font file's origin. */
296 /* */
297 FT_LOCAL_DEF FT_Error
298 TT_Load_Directory( TT_Face face,
299 FT_Stream stream,
300 SFNT_Header* sfnt )
301 {
302 FT_Error error;
303 FT_Memory memory = stream->memory;
305 TT_Table *entry, *limit;
308 FT_TRACE2(( "TT_Load_Directory: %08p\n", face ));
310 FT_TRACE2(( "-- Tables count: %12u\n", sfnt->num_tables ));
311 FT_TRACE2(( "-- Format version: %08lx\n", sfnt->format_tag ));
313 face->num_tables = sfnt->num_tables;
315 if ( ALLOC_ARRAY( face->dir_tables,
316 face->num_tables,
317 TT_Table ) )
318 goto Exit;
320 if ( ACCESS_Frame( face->num_tables * 16L ) )
321 goto Exit;
323 entry = face->dir_tables;
324 limit = entry + face->num_tables;
326 for ( ; entry < limit; entry++ )
327 { /* loop through the tables and get all entries */
328 entry->Tag = GET_Tag4();
329 entry->CheckSum = GET_ULong();
330 entry->Offset = GET_Long();
331 entry->Length = GET_Long();
333 FT_TRACE2(( " %c%c%c%c - %08lx - %08lx\n",
334 (FT_Char)( entry->Tag >> 24 ),
335 (FT_Char)( entry->Tag >> 16 ),
336 (FT_Char)( entry->Tag >> 8 ),
337 (FT_Char)( entry->Tag ),
338 entry->Offset,
339 entry->Length ));
340 }
342 FORGET_Frame();
344 FT_TRACE2(( "Directory loaded\n\n" ));
346 Exit:
347 return error;
348 }
351 /*************************************************************************/
352 /* */
353 /* <Function> */
354 /* TT_Load_Any */
355 /* */
356 /* <Description> */
357 /* Loads any font table into client memory. */
358 /* */
359 /* <Input> */
360 /* face :: The face object to look for. */
361 /* */
362 /* tag :: The tag of table to load. Use the value 0 if you want */
363 /* to access the whole font file, else set this parameter */
364 /* to a valid TrueType table tag that you can forge with */
365 /* the MAKE_TT_TAG macro. */
366 /* */
367 /* offset :: The starting offset in the table (or the file if */
368 /* tag == 0). */
369 /* */
370 /* length :: The address of the decision variable: */
371 /* */
372 /* If length == NULL: */
373 /* Loads the whole table. Returns an error if */
374 /* `offset' == 0! */
375 /* */
376 /* If *length == 0: */
377 /* Exits immediately; returning the length of the given */
378 /* table or of the font file, depending on the value of */
379 /* `tag'. */
380 /* */
381 /* If *length != 0: */
382 /* Loads the next `length' bytes of table or font, */
383 /* starting at offset `offset' (in table or font too). */
384 /* */
385 /* <Output> */
386 /* buffer :: The address of target buffer. */
387 /* */
388 /* <Return> */
389 /* FreeType error code. 0 means success. */
390 /* */
391 FT_LOCAL_DEF FT_Error
392 TT_Load_Any( TT_Face face,
393 FT_ULong tag,
394 FT_Long offset,
395 FT_Byte* buffer,
396 FT_ULong* length )
397 {
398 FT_Error error;
399 FT_Stream stream;
400 TT_Table* table;
401 FT_ULong size;
404 if ( tag != 0 )
405 {
406 /* look for tag in font directory */
407 table = TT_LookUp_Table( face, tag );
408 if ( !table )
409 {
410 error = SFNT_Err_Table_Missing;
411 goto Exit;
412 }
414 offset += table->Offset;
415 size = table->Length;
416 }
417 else
418 /* tag == 0 -- the user wants to access the font file directly */
419 size = face->root.stream->size;
421 if ( length && *length == 0 )
422 {
423 *length = size;
425 return SFNT_Err_Ok;
426 }
428 if ( length )
429 size = *length;
431 stream = face->root.stream;
432 /* the `if' is syntactic sugar for picky compilers */
433 if ( FILE_Read_At( offset, buffer, size ) )
434 goto Exit;
436 Exit:
437 return error;
438 }
441 /*************************************************************************/
442 /* */
443 /* <Function> */
444 /* TT_Load_Generic_Header */
445 /* */
446 /* <Description> */
447 /* Loads the TrueType table `head' or `bhed'. */
448 /* */
449 /* <Input> */
450 /* face :: A handle to the target face object. */
451 /* stream :: The input stream. */
452 /* */
453 /* <Return> */
454 /* FreeType error code. 0 means success. */
455 /* */
456 static FT_Error
457 TT_Load_Generic_Header( TT_Face face,
458 FT_Stream stream,
459 FT_ULong tag )
460 {
461 FT_Error error;
462 TT_Header* header;
464 static const FT_Frame_Field header_fields[] =
465 {
466 #undef FT_STRUCTURE
467 #define FT_STRUCTURE TT_Header
469 FT_FRAME_START( 54 ),
470 FT_FRAME_ULONG ( Table_Version ),
471 FT_FRAME_ULONG ( Font_Revision ),
472 FT_FRAME_LONG ( CheckSum_Adjust ),
473 FT_FRAME_LONG ( Magic_Number ),
474 FT_FRAME_USHORT( Flags ),
475 FT_FRAME_USHORT( Units_Per_EM ),
476 FT_FRAME_LONG ( Created[0] ),
477 FT_FRAME_LONG ( Created[1] ),
478 FT_FRAME_LONG ( Modified[0] ),
479 FT_FRAME_LONG ( Modified[1] ),
480 FT_FRAME_SHORT ( xMin ),
481 FT_FRAME_SHORT ( yMin ),
482 FT_FRAME_SHORT ( xMax ),
483 FT_FRAME_SHORT ( yMax ),
484 FT_FRAME_USHORT( Mac_Style ),
485 FT_FRAME_USHORT( Lowest_Rec_PPEM ),
486 FT_FRAME_SHORT ( Font_Direction ),
487 FT_FRAME_SHORT ( Index_To_Loc_Format ),
488 FT_FRAME_SHORT ( Glyph_Data_Format ),
489 FT_FRAME_END
490 };
493 FT_TRACE2(( "TT_Load_Generic_Header: "
494 "%08p, looking up font table `%c%c%c%c'.\n",
495 face,
496 (FT_Char)( tag >> 24 ),
497 (FT_Char)( tag >> 16 ),
498 (FT_Char)( tag >> 8 ),
499 (FT_Char)( tag ) ));
501 error = face->goto_table( face, tag, stream, 0 );
502 if ( error )
503 {
504 FT_TRACE2(( "TT_Load_Generic_Table: Font table is missing!\n" ));
505 goto Exit;
506 }
508 header = &face->header;
510 if ( READ_Fields( header_fields, header ) )
511 goto Exit;
513 FT_TRACE2(( " Units per EM: %8u\n", header->Units_Per_EM ));
514 FT_TRACE2(( " IndexToLoc: %8d\n", header->Index_To_Loc_Format ));
515 FT_TRACE2(( "TT_Load_Generic_Table: Font table loaded.\n" ));
517 Exit:
518 return error;
519 }
522 FT_LOCAL_DEF FT_Error
523 TT_Load_Header( TT_Face face,
524 FT_Stream stream )
525 {
526 return TT_Load_Generic_Header( face, stream, TTAG_head );
527 }
530 #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
532 FT_LOCAL_DEF FT_Error
533 TT_Load_Bitmap_Header( TT_Face face,
534 FT_Stream stream )
535 {
536 return TT_Load_Generic_Header( face, stream, TTAG_bhed );
537 }
539 #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
542 /*************************************************************************/
543 /* */
544 /* <Function> */
545 /* TT_Load_MaxProfile */
546 /* */
547 /* <Description> */
548 /* Loads the maximum profile into a face object. */
549 /* */
550 /* <Input> */
551 /* face :: A handle to the target face object. */
552 /* stream :: The input stream. */
553 /* */
554 /* <Return> */
555 /* FreeType error code. 0 means success. */
556 /* */
557 FT_LOCAL_DEF FT_Error
558 TT_Load_MaxProfile( TT_Face face,
559 FT_Stream stream )
560 {
561 FT_Error error;
562 TT_MaxProfile* maxProfile = &face->max_profile;
564 const FT_Frame_Field maxp_fields[] =
565 {
566 #undef FT_STRUCTURE
567 #define FT_STRUCTURE TT_MaxProfile
569 FT_FRAME_START( 6 ),
570 FT_FRAME_LONG ( version ),
571 FT_FRAME_USHORT( numGlyphs ),
572 FT_FRAME_END
573 };
575 const FT_Frame_Field maxp_fields_extra[] =
576 {
577 FT_FRAME_START( 26 ),
578 FT_FRAME_USHORT( maxPoints ),
579 FT_FRAME_USHORT( maxContours ),
580 FT_FRAME_USHORT( maxCompositePoints ),
581 FT_FRAME_USHORT( maxCompositeContours ),
582 FT_FRAME_USHORT( maxZones ),
583 FT_FRAME_USHORT( maxTwilightPoints ),
584 FT_FRAME_USHORT( maxStorage ),
585 FT_FRAME_USHORT( maxFunctionDefs ),
586 FT_FRAME_USHORT( maxInstructionDefs ),
587 FT_FRAME_USHORT( maxStackElements ),
588 FT_FRAME_USHORT( maxSizeOfInstructions ),
589 FT_FRAME_USHORT( maxComponentElements ),
590 FT_FRAME_USHORT( maxComponentDepth ),
591 FT_FRAME_END
592 };
595 FT_TRACE2(( "Load_TT_MaxProfile: %08p\n", face ));
597 error = face->goto_table( face, TTAG_maxp, stream, 0 );
598 if ( error )
599 goto Exit;
601 if ( READ_Fields( maxp_fields, maxProfile ) )
602 goto Exit;
604 maxProfile->maxPoints = 0;
605 maxProfile->maxContours = 0;
606 maxProfile->maxCompositePoints = 0;
607 maxProfile->maxCompositeContours = 0;
608 maxProfile->maxZones = 0;
609 maxProfile->maxTwilightPoints = 0;
610 maxProfile->maxStorage = 0;
611 maxProfile->maxFunctionDefs = 0;
612 maxProfile->maxInstructionDefs = 0;
613 maxProfile->maxStackElements = 0;
614 maxProfile->maxSizeOfInstructions = 0;
615 maxProfile->maxComponentElements = 0;
616 maxProfile->maxComponentDepth = 0;
618 if ( maxProfile->version >= 0x10000L )
619 {
620 if ( READ_Fields( maxp_fields_extra, maxProfile ) )
621 goto Exit;
623 /* XXX: an adjustment that is necessary to load certain */
624 /* broken fonts like `Keystrokes MT' :-( */
625 /* */
626 /* We allocate 64 function entries by default when */
627 /* the maxFunctionDefs field is null. */
629 if ( maxProfile->maxFunctionDefs == 0 )
630 maxProfile->maxFunctionDefs = 64;
632 face->root.num_glyphs = maxProfile->numGlyphs;
634 face->root.internal->max_points =
635 (FT_UShort)MAX( maxProfile->maxCompositePoints,
636 maxProfile->maxPoints );
638 face->root.internal->max_contours =
639 (FT_Short)MAX( maxProfile->maxCompositeContours,
640 maxProfile->maxContours );
642 face->max_components = (FT_ULong)maxProfile->maxComponentElements +
643 maxProfile->maxComponentDepth;
645 /* XXX: some fonts have maxComponents set to 0; we will */
646 /* then use 16 of them by default. */
647 if ( face->max_components == 0 )
648 face->max_components = 16;
650 /* We also increase maxPoints and maxContours in order to support */
651 /* some broken fonts. */
652 face->root.internal->max_points += 8;
653 face->root.internal->max_contours += 4;
654 }
656 FT_TRACE2(( "MAXP loaded.\n" ));
658 Exit:
659 return error;
660 }
663 /*************************************************************************/
664 /* */
665 /* <Function> */
666 /* TT_Load_Metrics */
667 /* */
668 /* <Description> */
669 /* Loads the horizontal or vertical metrics table into a face object. */
670 /* */
671 /* <Input> */
672 /* face :: A handle to the target face object. */
673 /* stream :: The input stream. */
674 /* vertical :: A boolean flag. If set, load vertical metrics. */
675 /* */
676 /* <Return> */
677 /* FreeType error code. 0 means success. */
678 /* */
679 static FT_Error
680 TT_Load_Metrics( TT_Face face,
681 FT_Stream stream,
682 FT_Bool vertical )
683 {
684 FT_Error error;
685 FT_Memory memory = stream->memory;
687 FT_ULong table_len;
688 FT_Long num_shorts, num_longs, num_shorts_checked;
690 TT_LongMetrics** longs;
691 TT_ShortMetrics** shorts;
694 FT_TRACE2(( "TT_Load_%s_Metrics: %08p\n", vertical ? "Vertical"
695 : "Horizontal",
696 face ));
698 if ( vertical )
699 {
700 /* The table is optional, quit silently if it wasn't found */
701 /* XXX: Some fonts have a valid vertical header with a non-null */
702 /* `number_of_VMetrics' fields, but no corresponding `vmtx' */
703 /* table to get the metrics from (e.g. mingliu). */
704 /* */
705 /* For safety, we set the field to 0! */
706 /* */
707 error = face->goto_table( face, TTAG_vmtx, stream, &table_len );
708 if ( error )
709 {
710 /* Set number_Of_VMetrics to 0! */
711 FT_TRACE2(( " no vertical header in file.\n" ));
712 face->vertical.number_Of_VMetrics = 0;
713 error = SFNT_Err_Ok;
714 goto Exit;
715 }
717 num_longs = face->vertical.number_Of_VMetrics;
718 longs = (TT_LongMetrics**)&face->vertical.long_metrics;
719 shorts = (TT_ShortMetrics**)&face->vertical.short_metrics;
720 }
721 else
722 {
723 error = face->goto_table( face, TTAG_hmtx, stream, &table_len );
724 if ( error )
725 {
726 FT_ERROR(( " no horizontal metrics in file!\n" ));
727 error = SFNT_Err_Hmtx_Table_Missing;
728 goto Exit;
729 }
731 num_longs = face->horizontal.number_Of_HMetrics;
732 longs = (TT_LongMetrics**)&face->horizontal.long_metrics;
733 shorts = (TT_ShortMetrics**)&face->horizontal.short_metrics;
734 }
736 /* never trust derived values */
738 num_shorts = face->max_profile.numGlyphs - num_longs;
739 num_shorts_checked = ( table_len - num_longs * 4L ) / 2;
741 if ( num_shorts < 0 )
742 {
743 FT_ERROR(( "TT_Load_%s_Metrics: more metrics than glyphs!\n",
744 vertical ? "Vertical"
745 : "Horizontal" ));
747 error = vertical ? SFNT_Err_Invalid_Vert_Metrics
748 : SFNT_Err_Invalid_Horiz_Metrics;
749 goto Exit;
750 }
752 if ( ALLOC_ARRAY( *longs, num_longs, TT_LongMetrics ) ||
753 ALLOC_ARRAY( *shorts, num_shorts, TT_ShortMetrics ) )
754 goto Exit;
756 if ( ACCESS_Frame( table_len ) )
757 goto Exit;
759 {
760 TT_LongMetrics* cur = *longs;
761 TT_LongMetrics* limit = cur + num_longs;
764 for ( ; cur < limit; cur++ )
765 {
766 cur->advance = GET_UShort();
767 cur->bearing = GET_Short();
768 }
769 }
771 /* do we have an inconsistent number of metric values? */
772 {
773 TT_ShortMetrics* cur = *shorts;
774 TT_ShortMetrics* limit = cur + MIN( num_shorts, num_shorts_checked );
777 for ( ; cur < limit; cur++ )
778 *cur = GET_Short();
780 /* we fill up the missing left side bearings with the */
781 /* last valid value. Since this will occur for buggy CJK */
782 /* fonts usually only, nothing serious will happen */
783 if ( num_shorts > num_shorts_checked && num_shorts_checked > 0 )
784 {
785 FT_Short val = (*shorts)[num_shorts_checked - 1];
788 limit = *shorts + num_shorts;
789 for ( ; cur < limit; cur++ )
790 *cur = val;
791 }
792 }
794 FORGET_Frame();
796 FT_TRACE2(( "loaded\n" ));
798 Exit:
799 return error;
800 }
803 /*************************************************************************/
804 /* */
805 /* <Function> */
806 /* TT_Load_Metrics_Header */
807 /* */
808 /* <Description> */
809 /* Loads the horizontal or vertical header in a face object. */
810 /* */
811 /* <Input> */
812 /* face :: A handle to the target face object. */
813 /* stream :: The input stream. */
814 /* vertical :: A boolean flag. If set, load vertical metrics. */
815 /* */
816 /* <Return> */
817 /* FreeType error code. 0 means success. */
818 /* */
819 FT_LOCAL_DEF FT_Error
820 TT_Load_Metrics_Header( TT_Face face,
821 FT_Stream stream,
822 FT_Bool vertical )
823 {
824 FT_Error error;
825 TT_HoriHeader* header;
827 const FT_Frame_Field metrics_header_fields[] =
828 {
829 #undef FT_STRUCTURE
830 #define FT_STRUCTURE TT_HoriHeader
832 FT_FRAME_START( 36 ),
833 FT_FRAME_ULONG ( Version ),
834 FT_FRAME_SHORT ( Ascender ),
835 FT_FRAME_SHORT ( Descender ),
836 FT_FRAME_SHORT ( Line_Gap ),
837 FT_FRAME_USHORT( advance_Width_Max ),
838 FT_FRAME_SHORT ( min_Left_Side_Bearing ),
839 FT_FRAME_SHORT ( min_Right_Side_Bearing ),
840 FT_FRAME_SHORT ( xMax_Extent ),
841 FT_FRAME_SHORT ( caret_Slope_Rise ),
842 FT_FRAME_SHORT ( caret_Slope_Run ),
843 FT_FRAME_SHORT ( caret_Offset ),
844 FT_FRAME_SHORT ( Reserved[0] ),
845 FT_FRAME_SHORT ( Reserved[1] ),
846 FT_FRAME_SHORT ( Reserved[2] ),
847 FT_FRAME_SHORT ( Reserved[3] ),
848 FT_FRAME_SHORT ( metric_Data_Format ),
849 FT_FRAME_USHORT( number_Of_HMetrics ),
850 FT_FRAME_END
851 };
854 FT_TRACE2(( vertical ? "Vertical header " : "Horizontal header " ));
856 if ( vertical )
857 {
858 face->vertical_info = 0;
860 /* The vertical header table is optional, so return quietly if */
861 /* we don't find it. */
862 error = face->goto_table( face, TTAG_vhea, stream, 0 );
863 if ( error )
864 {
865 error = SFNT_Err_Ok;
866 goto Exit;
867 }
869 face->vertical_info = 1;
870 header = (TT_HoriHeader*)&face->vertical;
871 }
872 else
873 {
874 /* The horizontal header is mandatory; return an error if we */
875 /* don't find it. */
876 error = face->goto_table( face, TTAG_hhea, stream, 0 );
877 if ( error )
878 {
879 error = SFNT_Err_Horiz_Header_Missing;
880 goto Exit;
881 }
883 header = &face->horizontal;
884 }
886 if ( READ_Fields( metrics_header_fields, header ) )
887 goto Exit;
889 header->long_metrics = NULL;
890 header->short_metrics = NULL;
892 FT_TRACE2(( "loaded\n" ));
894 /* Now try to load the corresponding metrics */
896 error = TT_Load_Metrics( face, stream, vertical );
898 Exit:
899 return error;
900 }
903 /*************************************************************************/
904 /* */
905 /* <Function> */
906 /* TT_Load_Names */
907 /* */
908 /* <Description> */
909 /* Loads the name records. */
910 /* */
911 /* <Input> */
912 /* face :: A handle to the target face object. */
913 /* stream :: The input stream. */
914 /* */
915 /* <Return> */
916 /* FreeType error code. 0 means success. */
917 /* */
918 FT_LOCAL_DEF FT_Error
919 TT_Load_Names( TT_Face face,
920 FT_Stream stream )
921 {
922 FT_Error error;
923 FT_Memory memory = stream->memory;
925 FT_ULong table_pos, table_len;
926 FT_ULong storageSize;
928 TT_NameTable* names;
930 const FT_Frame_Field name_table_fields[] =
931 {
932 #undef FT_STRUCTURE
933 #define FT_STRUCTURE TT_NameTable
935 FT_FRAME_START( 6 ),
936 FT_FRAME_USHORT( format ),
937 FT_FRAME_USHORT( numNameRecords ),
938 FT_FRAME_USHORT( storageOffset ),
939 FT_FRAME_END
940 };
942 const FT_Frame_Field name_record_fields[] =
943 {
944 #undef FT_STRUCTURE
945 #define FT_STRUCTURE TT_NameRec
947 /* no FT_FRAME_START */
948 FT_FRAME_USHORT( platformID ),
949 FT_FRAME_USHORT( encodingID ),
950 FT_FRAME_USHORT( languageID ),
951 FT_FRAME_USHORT( nameID ),
952 FT_FRAME_USHORT( stringLength ),
953 FT_FRAME_USHORT( stringOffset ),
954 FT_FRAME_END
955 };
958 FT_TRACE2(( "Names " ));
960 error = face->goto_table( face, TTAG_name, stream, &table_len );
961 if ( error )
962 {
963 /* The name table is required so indicate failure. */
964 FT_TRACE2(( "is missing!\n" ));
965 error = SFNT_Err_Name_Table_Missing;
966 goto Exit;
967 }
969 table_pos = FILE_Pos();
971 names = &face->name_table;
973 if ( READ_Fields( name_table_fields, names ) )
974 goto Exit;
976 /* Allocate the array of name records. */
977 if ( ALLOC_ARRAY( names->names,
978 names->numNameRecords,
979 TT_NameRec ) ||
980 ACCESS_Frame( names->numNameRecords * 12L ) )
981 goto Exit;
983 /* Load the name records and determine how much storage is needed */
984 /* to hold the strings themselves. */
985 {
986 TT_NameRec* cur = names->names;
987 TT_NameRec* limit = cur + names->numNameRecords;
990 storageSize = 0;
992 for ( ; cur < limit; cur ++ )
993 {
994 FT_ULong upper;
997 if ( READ_Fields( name_record_fields, cur ) )
998 break;
1000 upper = (FT_ULong)( cur->stringOffset + cur->stringLength );
1001 if ( upper > storageSize )
1002 storageSize = upper;
1003 }
1004 }
1006 FORGET_Frame();
1008 if ( storageSize > 0 )
1009 {
1010 /* allocate the name storage area in memory, then read it */
1011 if ( ALLOC( names->storage, storageSize ) ||
1012 FILE_Read_At( table_pos + names->storageOffset,
1013 names->storage, storageSize ) )
1014 goto Exit;
1016 /* Go through and assign the string pointers to the name records. */
1017 {
1018 TT_NameRec* cur = names->names;
1019 TT_NameRec* limit = cur + names->numNameRecords;
1022 for ( ; cur < limit; cur++ )
1023 cur->string = names->storage + cur->stringOffset;
1024 }
1026 #ifdef FT_DEBUG_LEVEL_TRACE
1028 /* Print Name Record Table in case of debugging */
1029 {
1030 TT_NameRec* cur = names->names;
1031 TT_NameRec* limit = cur + names->numNameRecords;
1034 for ( ; cur < limit; cur++ )
1035 {
1036 FT_UInt j;
1039 FT_TRACE3(( "%d %d %x %d\n ",
1040 cur->platformID,
1041 cur->encodingID,
1042 cur->languageID,
1043 cur->nameID ));
1045 /* I know that M$ encoded strings are Unicode, */
1046 /* but this works reasonable well for debugging purposes. */
1047 if ( cur->string )
1048 for ( j = 0; j < (FT_UInt)cur->stringLength; j++ )
1049 {
1050 FT_Char c = *( cur->string + j );
1053 if ( (FT_Byte)c < 128 )
1054 FT_TRACE3(( "%c", c ));
1055 }
1056 }
1057 }
1058 FT_TRACE3(( "\n" ));
1060 #endif /* FT_DEBUG_LEVEL_TRACE */
1062 }
1063 FT_TRACE2(( "loaded\n" ));
1065 /* everything went well, update face->num_names */
1066 face->num_names = names->numNameRecords;
1068 Exit:
1069 return error;
1070 }
1073 /*************************************************************************/
1074 /* */
1075 /* <Function> */
1076 /* TT_Free_Names */
1077 /* */
1078 /* <Description> */
1079 /* Frees the name records. */
1080 /* */
1081 /* <Input> */
1082 /* face :: A handle to the target face object. */
1083 /* */
1084 FT_LOCAL_DEF void
1085 TT_Free_Names( TT_Face face )
1086 {
1087 FT_Memory memory = face->root.driver->root.memory;
1088 TT_NameTable* names = &face->name_table;
1091 /* free strings table */
1092 FREE( names->names );
1094 /* free strings storage */
1095 FREE( names->storage );
1097 names->numNameRecords = 0;
1098 names->format = 0;
1099 names->storageOffset = 0;
1100 }
1103 /*************************************************************************/
1104 /* */
1105 /* <Function> */
1106 /* TT_Load_CMap */
1107 /* */
1108 /* <Description> */
1109 /* Loads the cmap directory in a face object. The cmaps itselves are */
1110 /* loaded on demand in the `ttcmap.c' module. */
1111 /* */
1112 /* <Input> */
1113 /* face :: A handle to the target face object. */
1114 /* stream :: A handle to the input stream. */
1115 /* */
1116 /* <Return> */
1117 /* FreeType error code. 0 means success. */
1118 /* */
1119 FT_LOCAL_DEF FT_Error
1120 TT_Load_CMap( TT_Face face,
1121 FT_Stream stream )
1122 {
1123 FT_Error error;
1124 FT_Memory memory = stream->memory;
1125 FT_Long table_start;
1126 TT_CMapDir cmap_dir;
1128 const FT_Frame_Field cmap_fields[] =
1129 {
1130 #undef FT_STRUCTURE
1131 #define FT_STRUCTURE TT_CMapDir
1133 FT_FRAME_START( 4 ),
1134 FT_FRAME_USHORT( tableVersionNumber ),
1135 FT_FRAME_USHORT( numCMaps ),
1136 FT_FRAME_END
1137 };
1139 const FT_Frame_Field cmap_rec_fields[] =
1140 {
1141 #undef FT_STRUCTURE
1142 #define FT_STRUCTURE TT_CMapTable
1144 FT_FRAME_START( 4 ),
1145 FT_FRAME_USHORT( format ),
1146 FT_FRAME_USHORT( length ),
1147 FT_FRAME_END
1148 };
1151 FT_TRACE2(( "CMaps " ));
1153 error = face->goto_table( face, TTAG_cmap, stream, 0 );
1154 if ( error )
1155 {
1156 error = SFNT_Err_CMap_Table_Missing;
1157 goto Exit;
1158 }
1160 table_start = FILE_Pos();
1162 if ( READ_Fields( cmap_fields, &cmap_dir ) )
1163 goto Exit;
1165 /* reserve space in face table for cmap tables */
1166 if ( ALLOC_ARRAY( face->charmaps,
1167 cmap_dir.numCMaps,
1168 TT_CharMapRec ) )
1169 goto Exit;
1171 face->num_charmaps = cmap_dir.numCMaps;
1172 {
1173 TT_CharMap charmap = face->charmaps;
1174 TT_CharMap limit = charmap + face->num_charmaps;
1177 /* read the header of each charmap first */
1178 if ( ACCESS_Frame( face->num_charmaps * 8L ) )
1179 goto Exit;
1181 for ( ; charmap < limit; charmap++ )
1182 {
1183 TT_CMapTable* cmap;
1186 charmap->root.face = (FT_Face)face;
1187 cmap = &charmap->cmap;
1189 cmap->loaded = FALSE;
1190 cmap->platformID = GET_UShort();
1191 cmap->platformEncodingID = GET_UShort();
1192 cmap->offset = (FT_ULong)GET_Long();
1193 }
1195 FORGET_Frame();
1197 /* now read the rest of each table */
1198 for ( charmap = face->charmaps; charmap < limit; charmap++ )
1199 {
1200 TT_CMapTable* cmap = &charmap->cmap;
1203 if ( FILE_Seek( table_start + (FT_Long)cmap->offset ) ||
1204 READ_Fields( cmap_rec_fields, cmap ) )
1205 goto Exit;
1207 cmap->offset = FILE_Pos();
1208 }
1209 }
1211 FT_TRACE2(( "loaded\n" ));
1213 Exit:
1214 return error;
1215 }
1218 /*************************************************************************/
1219 /* */
1220 /* <Function> */
1221 /* TT_Load_OS2 */
1222 /* */
1223 /* <Description> */
1224 /* Loads the OS2 table. */
1225 /* */
1226 /* <Input> */
1227 /* face :: A handle to the target face object. */
1228 /* stream :: A handle to the input stream. */
1229 /* */
1230 /* <Return> */
1231 /* FreeType error code. 0 means success. */
1232 /* */
1233 FT_LOCAL_DEF FT_Error
1234 TT_Load_OS2( TT_Face face,
1235 FT_Stream stream )
1236 {
1237 FT_Error error;
1238 TT_OS2* os2;
1240 const FT_Frame_Field os2_fields[] =
1241 {
1242 #undef FT_STRUCTURE
1243 #define FT_STRUCTURE TT_OS2
1245 FT_FRAME_START( 78 ),
1246 FT_FRAME_USHORT( version ),
1247 FT_FRAME_SHORT ( xAvgCharWidth ),
1248 FT_FRAME_USHORT( usWeightClass ),
1249 FT_FRAME_USHORT( usWidthClass ),
1250 FT_FRAME_SHORT ( fsType ),
1251 FT_FRAME_SHORT ( ySubscriptXSize ),
1252 FT_FRAME_SHORT ( ySubscriptYSize ),
1253 FT_FRAME_SHORT ( ySubscriptXOffset ),
1254 FT_FRAME_SHORT ( ySubscriptYOffset ),
1255 FT_FRAME_SHORT ( ySuperscriptXSize ),
1256 FT_FRAME_SHORT ( ySuperscriptYSize ),
1257 FT_FRAME_SHORT ( ySuperscriptXOffset ),
1258 FT_FRAME_SHORT ( ySuperscriptYOffset ),
1259 FT_FRAME_SHORT ( yStrikeoutSize ),
1260 FT_FRAME_SHORT ( yStrikeoutPosition ),
1261 FT_FRAME_SHORT ( sFamilyClass ),
1262 FT_FRAME_BYTE ( panose[0] ),
1263 FT_FRAME_BYTE ( panose[1] ),
1264 FT_FRAME_BYTE ( panose[2] ),
1265 FT_FRAME_BYTE ( panose[3] ),
1266 FT_FRAME_BYTE ( panose[4] ),
1267 FT_FRAME_BYTE ( panose[5] ),
1268 FT_FRAME_BYTE ( panose[6] ),
1269 FT_FRAME_BYTE ( panose[7] ),
1270 FT_FRAME_BYTE ( panose[8] ),
1271 FT_FRAME_BYTE ( panose[9] ),
1272 FT_FRAME_ULONG ( ulUnicodeRange1 ),
1273 FT_FRAME_ULONG ( ulUnicodeRange2 ),
1274 FT_FRAME_ULONG ( ulUnicodeRange3 ),
1275 FT_FRAME_ULONG ( ulUnicodeRange4 ),
1276 FT_FRAME_BYTE ( achVendID[0] ),
1277 FT_FRAME_BYTE ( achVendID[1] ),
1278 FT_FRAME_BYTE ( achVendID[2] ),
1279 FT_FRAME_BYTE ( achVendID[3] ),
1281 FT_FRAME_USHORT( fsSelection ),
1282 FT_FRAME_USHORT( usFirstCharIndex ),
1283 FT_FRAME_USHORT( usLastCharIndex ),
1284 FT_FRAME_SHORT ( sTypoAscender ),
1285 FT_FRAME_SHORT ( sTypoDescender ),
1286 FT_FRAME_SHORT ( sTypoLineGap ),
1287 FT_FRAME_USHORT( usWinAscent ),
1288 FT_FRAME_USHORT( usWinDescent ),
1289 FT_FRAME_END
1290 };
1292 const FT_Frame_Field os2_fields_extra[] =
1293 {
1294 FT_FRAME_START( 8 ),
1295 FT_FRAME_ULONG( ulCodePageRange1 ),
1296 FT_FRAME_ULONG( ulCodePageRange2 ),
1297 FT_FRAME_END
1298 };
1300 const FT_Frame_Field os2_fields_extra2[] =
1301 {
1302 FT_FRAME_START( 10 ),
1303 FT_FRAME_SHORT ( sxHeight ),
1304 FT_FRAME_SHORT ( sCapHeight ),
1305 FT_FRAME_USHORT( usDefaultChar ),
1306 FT_FRAME_USHORT( usBreakChar ),
1307 FT_FRAME_USHORT( usMaxContext ),
1308 FT_FRAME_END
1309 };
1312 FT_TRACE2(( "OS/2 Table " ));
1314 /* We now support old Mac fonts where the OS/2 table doesn't */
1315 /* exist. Simply put, we set the `version' field to 0xFFFF */
1316 /* and test this value each time we need to access the table. */
1317 error = face->goto_table( face, TTAG_OS2, stream, 0 );
1318 if ( error )
1319 {
1320 FT_TRACE2(( "is missing!\n" ));
1321 face->os2.version = 0xFFFF;
1322 error = SFNT_Err_Ok;
1323 goto Exit;
1324 }
1326 os2 = &face->os2;
1328 if ( READ_Fields( os2_fields, os2 ) )
1329 goto Exit;
1331 os2->ulCodePageRange1 = 0;
1332 os2->ulCodePageRange2 = 0;
1333 os2->sxHeight = 0;
1334 os2->sCapHeight = 0;
1335 os2->usDefaultChar = 0;
1336 os2->usBreakChar = 0;
1337 os2->usMaxContext = 0;
1339 if ( os2->version >= 0x0001 )
1340 {
1341 /* only version 1 tables */
1342 if ( READ_Fields( os2_fields_extra, os2 ) )
1343 goto Exit;
1345 if ( os2->version >= 0x0002 )
1346 {
1347 /* only version 2 tables */
1348 if ( READ_Fields( os2_fields_extra2, os2 ) )
1349 goto Exit;
1350 }
1351 }
1353 FT_TRACE2(( "loaded\n" ));
1355 Exit:
1356 return error;
1357 }
1360 /*************************************************************************/
1361 /* */
1362 /* <Function> */
1363 /* TT_Load_Postscript */
1364 /* */
1365 /* <Description> */
1366 /* Loads the Postscript table. */
1367 /* */
1368 /* <Input> */
1369 /* face :: A handle to the target face object. */
1370 /* stream :: A handle to the input stream. */
1371 /* */
1372 /* <Return> */
1373 /* FreeType error code. 0 means success. */
1374 /* */
1375 FT_LOCAL_DEF FT_Error
1376 TT_Load_PostScript( TT_Face face,
1377 FT_Stream stream )
1378 {
1379 FT_Error error;
1380 TT_Postscript* post = &face->postscript;
1382 static const FT_Frame_Field post_fields[] =
1383 {
1384 #undef FT_STRUCTURE
1385 #define FT_STRUCTURE TT_Postscript
1387 FT_FRAME_START( 32 ),
1388 FT_FRAME_ULONG( FormatType ),
1389 FT_FRAME_ULONG( italicAngle ),
1390 FT_FRAME_SHORT( underlinePosition ),
1391 FT_FRAME_SHORT( underlineThickness ),
1392 FT_FRAME_ULONG( isFixedPitch ),
1393 FT_FRAME_ULONG( minMemType42 ),
1394 FT_FRAME_ULONG( maxMemType42 ),
1395 FT_FRAME_ULONG( minMemType1 ),
1396 FT_FRAME_ULONG( maxMemType1 ),
1397 FT_FRAME_END
1398 };
1401 FT_TRACE2(( "PostScript " ));
1403 error = face->goto_table( face, TTAG_post, stream, 0 );
1404 if ( error )
1405 return SFNT_Err_Post_Table_Missing;
1407 if ( READ_Fields( post_fields, post ) )
1408 return error;
1410 /* we don't load the glyph names, we do that in another */
1411 /* module (ttpost). */
1412 FT_TRACE2(( "loaded\n" ));
1414 return SFNT_Err_Ok;
1415 }
1418 /*************************************************************************/
1419 /* */
1420 /* <Function> */
1421 /* TT_Load_PCLT */
1422 /* */
1423 /* <Description> */
1424 /* Loads the PCL 5 Table. */
1425 /* */
1426 /* <Input> */
1427 /* face :: A handle to the target face object. */
1428 /* stream :: A handle to the input stream. */
1429 /* */
1430 /* <Return> */
1431 /* FreeType error code. 0 means success. */
1432 /* */
1433 FT_LOCAL_DEF FT_Error
1434 TT_Load_PCLT( TT_Face face,
1435 FT_Stream stream )
1436 {
1437 static const FT_Frame_Field pclt_fields[] =
1438 {
1439 #undef FT_STRUCTURE
1440 #define FT_STRUCTURE TT_PCLT
1442 FT_FRAME_START( 54 ),
1443 FT_FRAME_ULONG ( Version ),
1444 FT_FRAME_ULONG ( FontNumber ),
1445 FT_FRAME_USHORT( Pitch ),
1446 FT_FRAME_USHORT( xHeight ),
1447 FT_FRAME_USHORT( Style ),
1448 FT_FRAME_USHORT( TypeFamily ),
1449 FT_FRAME_USHORT( CapHeight ),
1450 FT_FRAME_BYTES ( TypeFace, 16 ),
1451 FT_FRAME_BYTES ( CharacterComplement, 8 ),
1452 FT_FRAME_BYTES ( FileName, 6 ),
1453 FT_FRAME_CHAR ( StrokeWeight ),
1454 FT_FRAME_CHAR ( WidthType ),
1455 FT_FRAME_BYTE ( SerifStyle ),
1456 FT_FRAME_BYTE ( Reserved ),
1457 FT_FRAME_END
1458 };
1460 FT_Error error;
1461 TT_PCLT* pclt = &face->pclt;
1464 FT_TRACE2(( "PCLT " ));
1466 /* optional table */
1467 error = face->goto_table( face, TTAG_PCLT, stream, 0 );
1468 if ( error )
1469 {
1470 FT_TRACE2(( "missing (optional)\n" ));
1471 pclt->Version = 0;
1472 return SFNT_Err_Ok;
1473 }
1475 if ( READ_Fields( pclt_fields, pclt ) )
1476 goto Exit;
1478 FT_TRACE2(( "loaded\n" ));
1480 Exit:
1481 return error;
1482 }
1485 /*************************************************************************/
1486 /* */
1487 /* <Function> */
1488 /* TT_Load_Gasp */
1489 /* */
1490 /* <Description> */
1491 /* Loads the `gasp' table into a face object. */
1492 /* */
1493 /* <Input> */
1494 /* face :: A handle to the target face object. */
1495 /* stream :: The input stream. */
1496 /* */
1497 /* <Return> */
1498 /* FreeType error code. 0 means success. */
1499 /* */
1500 FT_LOCAL_DEF FT_Error
1501 TT_Load_Gasp( TT_Face face,
1502 FT_Stream stream )
1503 {
1504 FT_Error error;
1505 FT_Memory memory = stream->memory;
1507 FT_UInt j,num_ranges;
1508 TT_GaspRange* gaspranges;
1511 FT_TRACE2(( "TT_Load_Gasp: %08p\n", face ));
1513 /* the gasp table is optional */
1514 error = face->goto_table( face, TTAG_gasp, stream, 0 );
1515 if ( error )
1516 return SFNT_Err_Ok;
1518 if ( ACCESS_Frame( 4L ) )
1519 goto Exit;
1521 face->gasp.version = GET_UShort();
1522 face->gasp.numRanges = GET_UShort();
1524 FORGET_Frame();
1526 num_ranges = face->gasp.numRanges;
1527 FT_TRACE3(( "number of ranges = %d\n", num_ranges ));
1529 if ( ALLOC_ARRAY( gaspranges, num_ranges, TT_GaspRange ) ||
1530 ACCESS_Frame( num_ranges * 4L ) )
1531 goto Exit;
1533 face->gasp.gaspRanges = gaspranges;
1535 for ( j = 0; j < num_ranges; j++ )
1536 {
1537 gaspranges[j].maxPPEM = GET_UShort();
1538 gaspranges[j].gaspFlag = GET_UShort();
1540 FT_TRACE3(( " [max:%d flag:%d]",
1541 gaspranges[j].maxPPEM,
1542 gaspranges[j].gaspFlag ));
1543 }
1544 FT_TRACE3(( "\n" ));
1546 FORGET_Frame();
1547 FT_TRACE2(( "GASP loaded\n" ));
1549 Exit:
1550 return error;
1551 }
1554 FT_CALLBACK_DEF( int )
1555 tt_kern_pair_compare( const void* a,
1556 const void* b );
1559 /*************************************************************************/
1560 /* */
1561 /* <Function> */
1562 /* TT_Load_Kern */
1563 /* */
1564 /* <Description> */
1565 /* Loads the first kerning table with format 0 in the font. Only */
1566 /* accepts the first horizontal kerning table. Developers should use */
1567 /* the `ftxkern' extension to access other kerning tables in the font */
1568 /* file, if they really want to. */
1569 /* */
1570 /* <Input> */
1571 /* face :: A handle to the target face object. */
1572 /* stream :: The input stream. */
1573 /* */
1574 /* <Return> */
1575 /* FreeType error code. 0 means success. */
1576 /* */
1577 FT_LOCAL_DEF FT_Error
1578 TT_Load_Kern( TT_Face face,
1579 FT_Stream stream )
1580 {
1581 FT_Error error;
1582 FT_Memory memory = stream->memory;
1584 FT_UInt n, num_tables;
1587 /* the kern table is optional; exit silently if it is missing */
1588 error = face->goto_table( face, TTAG_kern, stream, 0 );
1589 if ( error )
1590 return SFNT_Err_Ok;
1592 if ( ACCESS_Frame( 4L ) )
1593 goto Exit;
1595 (void)GET_UShort(); /* version */
1596 num_tables = GET_UShort();
1598 FORGET_Frame();
1600 for ( n = 0; n < num_tables; n++ )
1601 {
1602 FT_UInt coverage;
1603 FT_UInt length;
1606 if ( ACCESS_Frame( 6L ) )
1607 goto Exit;
1609 (void)GET_UShort(); /* version */
1610 length = GET_UShort() - 6; /* substract header length */
1611 coverage = GET_UShort();
1613 FORGET_Frame();
1615 if ( coverage == 0x0001 )
1616 {
1617 FT_UInt num_pairs;
1618 TT_Kern_0_Pair* pair;
1619 TT_Kern_0_Pair* limit;
1622 /* found a horizontal format 0 kerning table! */
1623 if ( ACCESS_Frame( 8L ) )
1624 goto Exit;
1626 num_pairs = GET_UShort();
1628 /* skip the rest */
1630 FORGET_Frame();
1632 /* allocate array of kerning pairs */
1633 if ( ALLOC_ARRAY( face->kern_pairs, num_pairs, TT_Kern_0_Pair ) ||
1634 ACCESS_Frame( 6L * num_pairs ) )
1635 goto Exit;
1637 pair = face->kern_pairs;
1638 limit = pair + num_pairs;
1639 for ( ; pair < limit; pair++ )
1640 {
1641 pair->left = GET_UShort();
1642 pair->right = GET_UShort();
1643 pair->value = GET_UShort();
1644 }
1646 FORGET_Frame();
1648 face->num_kern_pairs = num_pairs;
1649 face->kern_table_index = n;
1651 /* ensure that the kerning pair table is sorted (yes, some */
1652 /* fonts have unsorted tables!) */
1653 {
1654 FT_UInt i;
1655 TT_Kern_0_Pair* pair0;
1658 pair0 = face->kern_pairs;
1660 for ( i = 1; i < num_pairs; i++, pair0++ )
1661 {
1662 if ( tt_kern_pair_compare( pair0, pair0 + 1 ) != -1 )
1663 {
1664 qsort( (void*)face->kern_pairs, (int)num_pairs,
1665 sizeof ( TT_Kern_0_Pair ), tt_kern_pair_compare );
1666 break;
1667 }
1668 }
1669 }
1671 goto Exit;
1672 }
1674 if ( FILE_Skip( length ) )
1675 goto Exit;
1676 }
1678 /* no kern table found -- doesn't matter */
1679 face->kern_table_index = -1;
1680 face->num_kern_pairs = 0;
1681 face->kern_pairs = NULL;
1683 Exit:
1684 return error;
1685 }
1688 #undef TT_KERN_INDEX
1689 #define TT_KERN_INDEX( g1, g2 ) ( ( (FT_ULong)g1 << 16 ) | g2 )
1691 FT_CALLBACK_DEF( int )
1692 tt_kern_pair_compare( const void* a,
1693 const void* b )
1694 {
1695 TT_Kern_0_Pair* pair1 = (TT_Kern_0_Pair*)a;
1696 TT_Kern_0_Pair* pair2 = (TT_Kern_0_Pair*)b;
1698 FT_ULong index1 = TT_KERN_INDEX( pair1->left, pair1->right );
1699 FT_ULong index2 = TT_KERN_INDEX( pair2->left, pair2->right );
1702 return ( index1 < index2 ? -1 :
1703 ( index1 > index2 ? 1 : 0 ));
1704 }
1706 #undef TT_KERN_INDEX
1709 /*************************************************************************/
1710 /* */
1711 /* <Function> */
1712 /* TT_Load_Hdmx */
1713 /* */
1714 /* <Description> */
1715 /* Loads the horizontal device metrics table. */
1716 /* */
1717 /* <Input> */
1718 /* face :: A handle to the target face object. */
1719 /* stream :: A handle to the input stream. */
1720 /* */
1721 /* <Return> */
1722 /* FreeType error code. 0 means success. */
1723 /* */
1724 FT_LOCAL_DEF FT_Error
1725 TT_Load_Hdmx( TT_Face face,
1726 FT_Stream stream )
1727 {
1728 FT_Error error;
1729 FT_Memory memory = stream->memory;
1731 TT_Hdmx* hdmx = &face->hdmx;
1732 FT_Long num_glyphs;
1733 FT_Long record_size;
1736 hdmx->version = 0;
1737 hdmx->num_records = 0;
1738 hdmx->records = 0;
1740 /* this table is optional */
1741 error = face->goto_table( face, TTAG_hdmx, stream, 0 );
1742 if ( error )
1743 return SFNT_Err_Ok;
1745 if ( ACCESS_Frame( 8L ) )
1746 goto Exit;
1748 hdmx->version = GET_UShort();
1749 hdmx->num_records = GET_Short();
1750 record_size = GET_Long();
1752 FORGET_Frame();
1754 /* Only recognize format 0 */
1755 if ( hdmx->version != 0 )
1756 goto Exit;
1758 if ( ALLOC_ARRAY( hdmx->records, hdmx->num_records, TT_HdmxRec ) )
1759 goto Exit;
1761 num_glyphs = face->root.num_glyphs;
1762 record_size -= num_glyphs + 2;
1764 {
1765 TT_HdmxRec* cur = hdmx->records;
1766 TT_HdmxRec* limit = cur + hdmx->num_records;
1769 for ( ; cur < limit; cur++ )
1770 {
1771 /* read record */
1772 if ( READ_Byte( cur->ppem ) ||
1773 READ_Byte( cur->max_width ) )
1774 goto Exit;
1776 if ( ALLOC( cur->widths, num_glyphs ) ||
1777 FILE_Read( cur->widths, num_glyphs ) )
1778 goto Exit;
1780 /* skip padding bytes */
1781 if ( record_size > 0 && FILE_Skip( record_size ) )
1782 goto Exit;
1783 }
1784 }
1786 Exit:
1787 return error;
1788 }
1791 /*************************************************************************/
1792 /* */
1793 /* <Function> */
1794 /* TT_Free_Hdmx */
1795 /* */
1796 /* <Description> */
1797 /* Frees the horizontal device metrics table. */
1798 /* */
1799 /* <Input> */
1800 /* face :: A handle to the target face object. */
1801 /* */
1802 FT_LOCAL_DEF void
1803 TT_Free_Hdmx( TT_Face face )
1804 {
1805 if ( face )
1806 {
1807 FT_Int n;
1808 FT_Memory memory = face->root.driver->root.memory;
1811 for ( n = 0; n < face->hdmx.num_records; n++ )
1812 FREE( face->hdmx.records[n].widths );
1814 FREE( face->hdmx.records );
1815 face->hdmx.num_records = 0;
1816 }
1817 }
1820 /* END */