xref: /inferno-os/libfreetype/ttload.c (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
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 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 /***************************************************************************/
18 
19 
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"
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  )
tt_face_lookup_table(TT_Face face,FT_ULong tag)57   tt_face_lookup_table( TT_Face   face,
58                         FT_ULong  tag  )
59   {
60     TT_Table  entry;
61     TT_Table  limit;
62 
63 
64     FT_TRACE3(( "tt_face_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       ) ));
70 
71     entry = face->dir_tables;
72     limit = entry + face->num_tables;
73 
74     for ( ; entry < limit; entry++ )
75     {
76       /* For compatibility with Windows, we consider 0-length */
77       /* tables the same as missing tables.                   */
78       if ( entry->Tag == tag && entry->Length != 0 )
79       {
80         FT_TRACE3(( "found table.\n" ));
81         return entry;
82       }
83     }
84 
85     FT_TRACE3(( "could not find table!\n" ));
86     return 0;
87   }
88 
89 
90   /*************************************************************************/
91   /*                                                                       */
92   /* <Function>                                                            */
93   /*    tt_face_goto_table                                                 */
94   /*                                                                       */
95   /* <Description>                                                         */
96   /*    Looks for a TrueType table by name, then seek a stream to it.      */
97   /*                                                                       */
98   /* <Input>                                                               */
99   /*    face   :: A face object handle.                                    */
100   /*                                                                       */
101   /*    tag    :: The searched tag.                                        */
102   /*                                                                       */
103   /*    stream :: The stream to seek when the table is found.              */
104   /*                                                                       */
105   /* <Output>                                                              */
106   /*    length :: The length of the table if found, undefined otherwise.   */
107   /*                                                                       */
108   /* <Return>                                                              */
109   /*    FreeType error code.  0 means success.                             */
110   /*                                                                       */
111   FT_LOCAL_DEF( FT_Error )
tt_face_goto_table(TT_Face face,FT_ULong tag,FT_Stream stream,FT_ULong * length)112   tt_face_goto_table( TT_Face    face,
113                       FT_ULong   tag,
114                       FT_Stream  stream,
115                       FT_ULong*  length )
116   {
117     TT_Table  table;
118     FT_Error  error;
119 
120 
121     table = tt_face_lookup_table( face, tag );
122     if ( table )
123     {
124       if ( length )
125         *length = table->Length;
126 
127       if ( FT_STREAM_SEEK( table->Offset ) )
128        goto Exit;
129     }
130     else
131       error = SFNT_Err_Table_Missing;
132 
133   Exit:
134     return error;
135   }
136 
137 
138  /* In theory, we should check the values of `search_range',               */
139  /* `entry_selector', and `range_shift' to detect non-SFNT based files     */
140  /* whose header might also start with 0x100000L (yes, these exist).       */
141  /*                                                                        */
142  /* Very unfortunately, many TrueType fonts don't have these fields        */
143  /* set correctly and we must ignore them to support them.  An alternative */
144  /* way to check the font file is thus to:                                 */
145  /*                                                                        */
146  /* - check that `num_tables' is valid                                     */
147  /* - look for a "head" table, check its size, and parse it to             */
148  /*   see if its "magic" field is correctly set                            */
149  /*                                                                        */
150  /* When checking directory entries, ignore the tables `glyx' and `locx'   */
151  /* which are hacked-out versions of `glyf' and `loca' in some PostScript  */
152  /* Type 42 fonts, and will generally be invalid.                          */
153  /*                                                                        */
154   static FT_Error
sfnt_dir_check(FT_Stream stream,FT_ULong offset,FT_UInt num_tables)155   sfnt_dir_check( FT_Stream  stream,
156                   FT_ULong   offset,
157                   FT_UInt    num_tables )
158    {
159     FT_Error        error;
160     FT_UInt         nn, has_head = 0;
161 
162     const FT_ULong  glyx_tag = FT_MAKE_TAG( 'g', 'l', 'y', 'x' );
163     const FT_ULong  locx_tag = FT_MAKE_TAG( 'l', 'o', 'c', 'x' );
164 
165     static const FT_Frame_Field  sfnt_dir_entry_fields[] =
166     {
167 #undef  FT_STRUCTURE
168 #define FT_STRUCTURE  TT_TableRec
169 
170       FT_FRAME_START( 16 ),
171         FT_FRAME_ULONG( Tag ),
172         FT_FRAME_ULONG( CheckSum ),
173         FT_FRAME_ULONG( Offset ),
174         FT_FRAME_ULONG( Length ),
175       FT_FRAME_END
176     };
177 
178 
179     /* if 'num_tables' is 0, read the table count from the file */
180     if ( num_tables == 0 )
181     {
182       FT_ULong  format_tag;
183 
184 
185       if ( FT_STREAM_SEEK( offset )     ||
186            FT_READ_ULONG ( format_tag ) ||
187            FT_READ_USHORT( num_tables ) ||
188            FT_STREAM_SKIP( 6 )          )
189         goto Bad_Format;
190 
191       if ( offset + 12 + num_tables*16 > stream->size )
192         goto Bad_Format;
193     }
194     else if ( FT_STREAM_SEEK( offset + 12 ) )
195       goto Bad_Format;
196 
197     for ( nn = 0; nn < num_tables; nn++ )
198     {
199       TT_TableRec  table;
200 
201 
202       if ( FT_STREAM_READ_FIELDS( sfnt_dir_entry_fields, &table ) )
203         goto Bad_Format;
204 
205       if ( table.Offset + table.Length > stream->size     &&
206            table.Tag != glyx_tag && table.Tag != locx_tag )
207         goto Bad_Format;
208 
209       if ( table.Tag == TTAG_head )
210       {
211         FT_UInt32  magic;
212 
213 
214         has_head = 1;
215 
216         if ( table.Length != 0x36                ||
217              FT_STREAM_SEEK( table.Offset + 12 ) ||
218              FT_READ_ULONG( magic )              ||
219              magic != 0x5F0F3CF5UL               )
220           goto Bad_Format;
221 
222         if ( FT_STREAM_SEEK( offset + 28 + 16*nn ) )
223           goto Bad_Format;
224       }
225     }
226 
227     if ( has_head == 0 )
228       goto Bad_Format;
229 
230   Exit:
231     return  error;
232 
233   Bad_Format:
234     error = FT_Err_Unknown_File_Format;
235     goto Exit;
236   }
237 
238 
239   /*************************************************************************/
240   /*                                                                       */
241   /* <Function>                                                            */
242   /*    tt_face_load_sfnt_header                                           */
243   /*                                                                       */
244   /* <Description>                                                         */
245   /*    Loads the header of a SFNT font file.  Supports collections.       */
246   /*                                                                       */
247   /* <Input>                                                               */
248   /*    face       :: A handle to the target face object.                  */
249   /*                                                                       */
250   /*    stream     :: The input stream.                                    */
251   /*                                                                       */
252   /*    face_index :: If the font is a collection, the number of the font  */
253   /*                  in the collection, ignored otherwise.                */
254   /*                                                                       */
255   /* <Output>                                                              */
256   /*    sfnt       :: The SFNT header.                                     */
257   /*                                                                       */
258   /* <Return>                                                              */
259   /*    FreeType error code.  0 means success.                             */
260   /*                                                                       */
261   /* <Note>                                                                */
262   /*    The stream cursor must be at the font file's origin.               */
263   /*                                                                       */
264   /*    This function recognizes fonts embedded in a `TrueType collection' */
265   /*                                                                       */
266   /*    The header will be checked whether it is valid by looking at the   */
267   /*    values of `search_range', `entry_selector', and `range_shift'.     */
268   /*                                                                       */
269   FT_LOCAL_DEF( FT_Error )
tt_face_load_sfnt_header(TT_Face face,FT_Stream stream,FT_Long face_index,SFNT_Header sfnt)270   tt_face_load_sfnt_header( TT_Face      face,
271                             FT_Stream    stream,
272                             FT_Long      face_index,
273                             SFNT_Header  sfnt )
274   {
275     FT_Error   error;
276     FT_ULong   format_tag, offset;
277     FT_Memory  memory = stream->memory;
278 
279     static const FT_Frame_Field  sfnt_header_fields[] =
280     {
281 #undef  FT_STRUCTURE
282 #define FT_STRUCTURE  SFNT_HeaderRec
283 
284       FT_FRAME_START( 8 ),
285         FT_FRAME_USHORT( num_tables ),
286         FT_FRAME_USHORT( search_range ),
287         FT_FRAME_USHORT( entry_selector ),
288         FT_FRAME_USHORT( range_shift ),
289       FT_FRAME_END
290     };
291 
292     static const FT_Frame_Field  ttc_header_fields[] =
293     {
294 #undef  FT_STRUCTURE
295 #define FT_STRUCTURE  TTC_HeaderRec
296 
297       FT_FRAME_START( 8 ),
298         FT_FRAME_LONG( version ),
299         FT_FRAME_LONG( count   ),
300       FT_FRAME_END
301     };
302 
303 
304     FT_TRACE2(( "tt_face_load_sfnt_header: %08p, %ld\n",
305                 face, face_index ));
306 
307     face->ttc_header.tag     = 0;
308     face->ttc_header.version = 0;
309     face->ttc_header.count   = 0;
310 
311     face->num_tables = 0;
312 
313     /* first of all, read the first 4 bytes.  If it is `ttcf', then the */
314     /* file is a TrueType collection, otherwise it can be any other     */
315     /* kind of font.                                                    */
316     /*                                                                  */
317     offset = FT_STREAM_POS();
318 
319     if ( FT_READ_ULONG( format_tag ) )
320       goto Exit;
321 
322     if ( format_tag == TTAG_ttcf )
323     {
324       FT_Int  n;
325 
326 
327       FT_TRACE3(( "tt_face_load_sfnt_header: file is a collection\n" ));
328 
329       /* It is a TrueType collection, i.e. a file containing several */
330       /* font files.  Read the font directory now                    */
331       if ( FT_STREAM_READ_FIELDS( ttc_header_fields, &face->ttc_header ) )
332         goto Exit;
333 
334       /* now read the offsets of each font in the file */
335       if ( FT_NEW_ARRAY( face->ttc_header.offsets, face->ttc_header.count ) ||
336            FT_FRAME_ENTER( face->ttc_header.count * 4L )                    )
337         goto Exit;
338 
339       for ( n = 0; n < face->ttc_header.count; n++ )
340         face->ttc_header.offsets[n] = FT_GET_ULONG();
341 
342       FT_FRAME_EXIT();
343 
344       /* check face index */
345       if ( face_index >= face->ttc_header.count )
346       {
347         error = SFNT_Err_Bad_Argument;
348         goto Exit;
349       }
350 
351       /* seek to the appropriate TrueType file, then read tag */
352       offset = face->ttc_header.offsets[face_index];
353 
354       if ( FT_STREAM_SEEK( offset ) ||
355            FT_READ_LONG( format_tag )                             )
356         goto Exit;
357     }
358 
359     /* the format tag was read, now check the rest of the header */
360     sfnt->format_tag = format_tag;
361     sfnt->offset     = offset;
362 
363     if ( FT_STREAM_READ_FIELDS( sfnt_header_fields, sfnt ) )
364       goto Exit;
365 
366     /* now check the sfnt directory */
367     error = sfnt_dir_check( stream, offset, sfnt->num_tables );
368     if ( error )
369     {
370       FT_TRACE2(( "tt_face_load_sfnt_header: file is not SFNT!\n" ));
371       error = SFNT_Err_Unknown_File_Format;
372     }
373 
374   Exit:
375     return error;
376   }
377 
378 
379   /*************************************************************************/
380   /*                                                                       */
381   /* <Function>                                                            */
382   /*    tt_face_load_directory                                             */
383   /*                                                                       */
384   /* <Description>                                                         */
385   /*    Loads the table directory into a face object.                      */
386   /*                                                                       */
387   /* <InOut>                                                               */
388   /*    face   :: A handle to the target face object.                      */
389   /*                                                                       */
390   /* <Input>                                                               */
391   /*    stream :: The input stream.                                        */
392   /*                                                                       */
393   /*    sfnt   :: The SFNT directory header.                               */
394   /*                                                                       */
395   /* <Return>                                                              */
396   /*    FreeType error code.  0 means success.                             */
397   /*                                                                       */
398   /* <Note>                                                                */
399   /*    The stream cursor must be at the font file's origin.               */
400   /*                                                                       */
401   FT_LOCAL_DEF( FT_Error )
tt_face_load_directory(TT_Face face,FT_Stream stream,SFNT_Header sfnt)402   tt_face_load_directory( TT_Face      face,
403                           FT_Stream    stream,
404                           SFNT_Header  sfnt )
405   {
406     FT_Error     error;
407     FT_Memory    memory = stream->memory;
408 
409     TT_TableRec  *entry, *limit;
410 
411 
412     FT_TRACE2(( "tt_face_load_directory: %08p\n", face ));
413 
414     FT_TRACE2(( "-- Tables count:   %12u\n",  sfnt->num_tables ));
415     FT_TRACE2(( "-- Format version: %08lx\n", sfnt->format_tag ));
416 
417     face->num_tables = sfnt->num_tables;
418 
419     if ( FT_NEW_ARRAY( face->dir_tables, face->num_tables ) )
420       goto Exit;
421 
422     if ( FT_STREAM_SEEK( sfnt->offset + 12 )      ||
423          FT_FRAME_ENTER( face->num_tables * 16L ) )
424       goto Exit;
425 
426     entry = face->dir_tables;
427     limit = entry + face->num_tables;
428 
429     for ( ; entry < limit; entry++ )
430     {                    /* loop through the tables and get all entries */
431       entry->Tag      = FT_GET_TAG4();
432       entry->CheckSum = FT_GET_ULONG();
433       entry->Offset   = FT_GET_LONG();
434       entry->Length   = FT_GET_LONG();
435 
436       FT_TRACE2(( "  %c%c%c%c  -  %08lx  -  %08lx\n",
437                   (FT_Char)( entry->Tag >> 24 ),
438                   (FT_Char)( entry->Tag >> 16 ),
439                   (FT_Char)( entry->Tag >> 8  ),
440                   (FT_Char)( entry->Tag       ),
441                   entry->Offset,
442                   entry->Length ));
443     }
444 
445     FT_FRAME_EXIT();
446 
447     FT_TRACE2(( "Directory loaded\n\n" ));
448 
449   Exit:
450     return error;
451   }
452 
453 
454   /*************************************************************************/
455   /*                                                                       */
456   /* <Function>                                                            */
457   /*    tt_face_load_any                                                   */
458   /*                                                                       */
459   /* <Description>                                                         */
460   /*    Loads any font table into client memory.                           */
461   /*                                                                       */
462   /* <Input>                                                               */
463   /*    face   :: The face object to look for.                             */
464   /*                                                                       */
465   /*    tag    :: The tag of table to load.  Use the value 0 if you want   */
466   /*              to access the whole font file, else set this parameter   */
467   /*              to a valid TrueType table tag that you can forge with    */
468   /*              the MAKE_TT_TAG macro.                                   */
469   /*                                                                       */
470   /*    offset :: The starting offset in the table (or the file if         */
471   /*              tag == 0).                                               */
472   /*                                                                       */
473   /*    length :: The address of the decision variable:                    */
474   /*                                                                       */
475   /*                If length == NULL:                                     */
476   /*                  Loads the whole table.  Returns an error if          */
477   /*                  `offset' == 0!                                       */
478   /*                                                                       */
479   /*                If *length == 0:                                       */
480   /*                  Exits immediately; returning the length of the given */
481   /*                  table or of the font file, depending on the value of */
482   /*                  `tag'.                                               */
483   /*                                                                       */
484   /*                If *length != 0:                                       */
485   /*                  Loads the next `length' bytes of table or font,      */
486   /*                  starting at offset `offset' (in table or font too).  */
487   /*                                                                       */
488   /* <Output>                                                              */
489   /*    buffer :: The address of target buffer.                            */
490   /*                                                                       */
491   /* <Return>                                                              */
492   /*    FreeType error code.  0 means success.                             */
493   /*                                                                       */
494   FT_LOCAL_DEF( FT_Error )
tt_face_load_any(TT_Face face,FT_ULong tag,FT_Long offset,FT_Byte * buffer,FT_ULong * length)495   tt_face_load_any( TT_Face    face,
496                     FT_ULong   tag,
497                     FT_Long    offset,
498                     FT_Byte*   buffer,
499                     FT_ULong*  length )
500   {
501     FT_Error   error;
502     FT_Stream  stream;
503     TT_Table   table;
504     FT_ULong   size;
505 
506 
507     if ( tag != 0 )
508     {
509       /* look for tag in font directory */
510       table = tt_face_lookup_table( face, tag );
511       if ( !table )
512       {
513         error = SFNT_Err_Table_Missing;
514         goto Exit;
515       }
516 
517       offset += table->Offset;
518       size    = table->Length;
519     }
520     else
521       /* tag == 0 -- the user wants to access the font file directly */
522       size = face->root.stream->size;
523 
524     if ( length && *length == 0 )
525     {
526       *length = size;
527 
528       return SFNT_Err_Ok;
529     }
530 
531     if ( length )
532       size = *length;
533 
534     stream = face->root.stream;
535     /* the `if' is syntactic sugar for picky compilers */
536     if ( FT_STREAM_READ_AT( offset, buffer, size ) )
537       goto Exit;
538 
539   Exit:
540     return error;
541   }
542 
543 
544   /*************************************************************************/
545   /*                                                                       */
546   /* <Function>                                                            */
547   /*    tt_face_load_generic_header                                        */
548   /*                                                                       */
549   /* <Description>                                                         */
550   /*    Loads the TrueType table `head' or `bhed'.                         */
551   /*                                                                       */
552   /* <Input>                                                               */
553   /*    face   :: A handle to the target face object.                      */
554   /*                                                                       */
555   /*    stream :: The input stream.                                        */
556   /*                                                                       */
557   /* <Return>                                                              */
558   /*    FreeType error code.  0 means success.                             */
559   /*                                                                       */
560   static FT_Error
tt_face_load_generic_header(TT_Face face,FT_Stream stream,FT_ULong tag)561   tt_face_load_generic_header( TT_Face    face,
562                                FT_Stream  stream,
563                                FT_ULong   tag )
564   {
565     FT_Error    error;
566     TT_Header*  header;
567 
568     static const FT_Frame_Field  header_fields[] =
569     {
570 #undef  FT_STRUCTURE
571 #define FT_STRUCTURE  TT_Header
572 
573       FT_FRAME_START( 54 ),
574         FT_FRAME_ULONG ( Table_Version ),
575         FT_FRAME_ULONG ( Font_Revision ),
576         FT_FRAME_LONG  ( CheckSum_Adjust ),
577         FT_FRAME_LONG  ( Magic_Number ),
578         FT_FRAME_USHORT( Flags ),
579         FT_FRAME_USHORT( Units_Per_EM ),
580         FT_FRAME_LONG  ( Created[0] ),
581         FT_FRAME_LONG  ( Created[1] ),
582         FT_FRAME_LONG  ( Modified[0] ),
583         FT_FRAME_LONG  ( Modified[1] ),
584         FT_FRAME_SHORT ( xMin ),
585         FT_FRAME_SHORT ( yMin ),
586         FT_FRAME_SHORT ( xMax ),
587         FT_FRAME_SHORT ( yMax ),
588         FT_FRAME_USHORT( Mac_Style ),
589         FT_FRAME_USHORT( Lowest_Rec_PPEM ),
590         FT_FRAME_SHORT ( Font_Direction ),
591         FT_FRAME_SHORT ( Index_To_Loc_Format ),
592         FT_FRAME_SHORT ( Glyph_Data_Format ),
593       FT_FRAME_END
594     };
595 
596 
597     FT_TRACE2(( "tt_face_load_generic_header: "
598                 "%08p, looking up font table `%c%c%c%c'.\n",
599                 face,
600                 (FT_Char)( tag >> 24 ),
601                 (FT_Char)( tag >> 16 ),
602                 (FT_Char)( tag >> 8  ),
603                 (FT_Char)( tag       ) ));
604 
605     error = face->goto_table( face, tag, stream, 0 );
606     if ( error )
607     {
608       FT_TRACE2(( "tt_face_load_generic_header: Font table is missing!\n" ));
609       goto Exit;
610     }
611 
612     header = &face->header;
613 
614     if ( FT_STREAM_READ_FIELDS( header_fields, header ) )
615       goto Exit;
616 
617     FT_TRACE2(( "    Units per EM: %8u\n", header->Units_Per_EM ));
618     FT_TRACE2(( "    IndexToLoc:   %8d\n", header->Index_To_Loc_Format ));
619     FT_TRACE2(( "tt_face_load_generic_header: Font table loaded.\n" ));
620 
621   Exit:
622     return error;
623   }
624 
625 
626   FT_LOCAL_DEF( FT_Error )
tt_face_load_header(TT_Face face,FT_Stream stream)627   tt_face_load_header( TT_Face    face,
628                        FT_Stream  stream )
629   {
630     return tt_face_load_generic_header( face, stream, TTAG_head );
631   }
632 
633 
634 #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
635 
636   FT_LOCAL_DEF( FT_Error )
tt_face_load_bitmap_header(TT_Face face,FT_Stream stream)637   tt_face_load_bitmap_header( TT_Face    face,
638                               FT_Stream  stream )
639   {
640     return tt_face_load_generic_header( face, stream, TTAG_bhed );
641   }
642 
643 #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
644 
645 
646   /*************************************************************************/
647   /*                                                                       */
648   /* <Function>                                                            */
649   /*    tt_face_load_max_profile                                           */
650   /*                                                                       */
651   /* <Description>                                                         */
652   /*    Loads the maximum profile into a face object.                      */
653   /*                                                                       */
654   /* <Input>                                                               */
655   /*    face   :: A handle to the target face object.                      */
656   /*                                                                       */
657   /*    stream :: The input stream.                                        */
658   /*                                                                       */
659   /* <Return>                                                              */
660   /*    FreeType error code.  0 means success.                             */
661   /*                                                                       */
662   FT_LOCAL_DEF( FT_Error )
tt_face_load_max_profile(TT_Face face,FT_Stream stream)663   tt_face_load_max_profile( TT_Face    face,
664                             FT_Stream  stream )
665   {
666     FT_Error        error;
667     TT_MaxProfile*  maxProfile = &face->max_profile;
668 
669     const FT_Frame_Field  maxp_fields[] =
670     {
671 #undef  FT_STRUCTURE
672 #define FT_STRUCTURE  TT_MaxProfile
673 
674       FT_FRAME_START( 6 ),
675         FT_FRAME_LONG  ( version ),
676         FT_FRAME_USHORT( numGlyphs ),
677       FT_FRAME_END
678     };
679 
680     const FT_Frame_Field  maxp_fields_extra[] =
681     {
682       FT_FRAME_START( 26 ),
683         FT_FRAME_USHORT( maxPoints ),
684         FT_FRAME_USHORT( maxContours ),
685         FT_FRAME_USHORT( maxCompositePoints ),
686         FT_FRAME_USHORT( maxCompositeContours ),
687         FT_FRAME_USHORT( maxZones ),
688         FT_FRAME_USHORT( maxTwilightPoints ),
689         FT_FRAME_USHORT( maxStorage ),
690         FT_FRAME_USHORT( maxFunctionDefs ),
691         FT_FRAME_USHORT( maxInstructionDefs ),
692         FT_FRAME_USHORT( maxStackElements ),
693         FT_FRAME_USHORT( maxSizeOfInstructions ),
694         FT_FRAME_USHORT( maxComponentElements ),
695         FT_FRAME_USHORT( maxComponentDepth ),
696       FT_FRAME_END
697     };
698 
699 
700     FT_TRACE2(( "Load_TT_MaxProfile: %08p\n", face ));
701 
702     error = face->goto_table( face, TTAG_maxp, stream, 0 );
703     if ( error )
704       goto Exit;
705 
706     if ( FT_STREAM_READ_FIELDS( maxp_fields, maxProfile ) )
707       goto Exit;
708 
709     maxProfile->maxPoints             = 0;
710     maxProfile->maxContours           = 0;
711     maxProfile->maxCompositePoints    = 0;
712     maxProfile->maxCompositeContours  = 0;
713     maxProfile->maxZones              = 0;
714     maxProfile->maxTwilightPoints     = 0;
715     maxProfile->maxStorage            = 0;
716     maxProfile->maxFunctionDefs       = 0;
717     maxProfile->maxInstructionDefs    = 0;
718     maxProfile->maxStackElements      = 0;
719     maxProfile->maxSizeOfInstructions = 0;
720     maxProfile->maxComponentElements  = 0;
721     maxProfile->maxComponentDepth     = 0;
722 
723     if ( maxProfile->version >= 0x10000L )
724     {
725       if ( FT_STREAM_READ_FIELDS( maxp_fields_extra, maxProfile ) )
726         goto Exit;
727 
728       /* XXX: an adjustment that is necessary to load certain */
729       /*      broken fonts like `Keystrokes MT' :-(           */
730       /*                                                      */
731       /*   We allocate 64 function entries by default when    */
732       /*   the maxFunctionDefs field is null.                 */
733 
734       if ( maxProfile->maxFunctionDefs == 0 )
735         maxProfile->maxFunctionDefs = 64;
736 
737       face->root.num_glyphs = maxProfile->numGlyphs;
738 
739       face->root.internal->max_points =
740         (FT_UShort)MAX( maxProfile->maxCompositePoints,
741                         maxProfile->maxPoints );
742 
743       face->root.internal->max_contours =
744         (FT_Short)MAX( maxProfile->maxCompositeContours,
745                        maxProfile->maxContours );
746 
747       face->max_components = (FT_ULong)maxProfile->maxComponentElements +
748                              maxProfile->maxComponentDepth;
749 
750       /* XXX: some fonts have maxComponents set to 0; we will */
751       /*      then use 16 of them by default.                 */
752       if ( face->max_components == 0 )
753         face->max_components = 16;
754 
755       /* We also increase maxPoints and maxContours in order to support */
756       /* some broken fonts.                                             */
757       face->root.internal->max_points   += (FT_UShort)8;
758       face->root.internal->max_contours += (FT_Short) 4;
759     }
760 
761     FT_TRACE2(( "MAXP loaded.\n" ));
762 
763   Exit:
764     return error;
765   }
766 
767 
768   /*************************************************************************/
769   /*                                                                       */
770   /* <Function>                                                            */
771   /*    tt_face_load_metrics                                               */
772   /*                                                                       */
773   /* <Description>                                                         */
774   /*    Loads the horizontal or vertical metrics table into a face object. */
775   /*                                                                       */
776   /* <Input>                                                               */
777   /*    face     :: A handle to the target face object.                    */
778   /*                                                                       */
779   /*    stream   :: The input stream.                                      */
780   /*                                                                       */
781   /*    vertical :: A boolean flag.  If set, load vertical metrics.        */
782   /*                                                                       */
783   /* <Return>                                                              */
784   /*    FreeType error code.  0 means success.                             */
785   /*                                                                       */
786   static FT_Error
tt_face_load_metrics(TT_Face face,FT_Stream stream,FT_Bool vertical)787   tt_face_load_metrics( TT_Face    face,
788                         FT_Stream  stream,
789                         FT_Bool    vertical )
790   {
791     FT_Error   error;
792     FT_Memory  memory = stream->memory;
793 
794     FT_ULong   table_len;
795     FT_Long    num_shorts, num_longs, num_shorts_checked;
796 
797     TT_LongMetrics *   longs;
798     TT_ShortMetrics**  shorts;
799 
800 
801     FT_TRACE2(( "TT_Load_%s_Metrics: %08p\n", vertical ? "Vertical"
802                                                        : "Horizontal",
803                                               face ));
804 
805     if ( vertical )
806     {
807       /* The table is optional, quit silently if it wasn't found       */
808       /*                                                               */
809       /* XXX: Some fonts have a valid vertical header with a non-null  */
810       /*      `number_of_VMetrics' fields, but no corresponding `vmtx' */
811       /*      table to get the metrics from (e.g. mingliu).            */
812       /*                                                               */
813       /*      For safety, we set the field to 0!                       */
814       /*                                                               */
815       error = face->goto_table( face, TTAG_vmtx, stream, &table_len );
816       if ( error )
817       {
818         /* Set number_Of_VMetrics to 0! */
819         FT_TRACE2(( "  no vertical header in file.\n" ));
820         face->vertical.number_Of_VMetrics = 0;
821         error = SFNT_Err_Ok;
822         goto Exit;
823       }
824 
825       num_longs = face->vertical.number_Of_VMetrics;
826       longs     = (TT_LongMetrics *)&face->vertical.long_metrics;
827       shorts    = (TT_ShortMetrics**)&face->vertical.short_metrics;
828     }
829     else
830     {
831       error = face->goto_table( face, TTAG_hmtx, stream, &table_len );
832       if ( error )
833       {
834         FT_ERROR(( " no horizontal metrics in file!\n" ));
835         error = SFNT_Err_Hmtx_Table_Missing;
836         goto Exit;
837       }
838 
839       num_longs = face->horizontal.number_Of_HMetrics;
840       longs     = (TT_LongMetrics *)&face->horizontal.long_metrics;
841       shorts    = (TT_ShortMetrics**)&face->horizontal.short_metrics;
842     }
843 
844     /* never trust derived values */
845 
846     num_shorts         = face->max_profile.numGlyphs - num_longs;
847     num_shorts_checked = ( table_len - num_longs * 4L ) / 2;
848 
849     if ( num_shorts < 0 )
850     {
851       FT_ERROR(( "TT_Load_%s_Metrics: more metrics than glyphs!\n",
852                  vertical ? "Vertical"
853                           : "Horizontal" ));
854 
855       error = vertical ? SFNT_Err_Invalid_Vert_Metrics
856                        : SFNT_Err_Invalid_Horiz_Metrics;
857       goto Exit;
858     }
859 
860     if ( FT_NEW_ARRAY( *longs,  num_longs  ) ||
861          FT_NEW_ARRAY( *shorts, num_shorts ) )
862       goto Exit;
863 
864     if ( FT_FRAME_ENTER( table_len ) )
865       goto Exit;
866 
867     {
868       TT_LongMetrics  cur   = *longs;
869       TT_LongMetrics  limit = cur + num_longs;
870 
871 
872       for ( ; cur < limit; cur++ )
873       {
874         cur->advance = FT_GET_USHORT();
875         cur->bearing = FT_GET_SHORT();
876       }
877     }
878 
879     /* do we have an inconsistent number of metric values? */
880     {
881       TT_ShortMetrics*  cur   = *shorts;
882       TT_ShortMetrics*  limit = cur + MIN( num_shorts, num_shorts_checked );
883 
884 
885       for ( ; cur < limit; cur++ )
886         *cur = FT_GET_SHORT();
887 
888       /* we fill up the missing left side bearings with the     */
889       /* last valid value.  Since this will occur for buggy CJK */
890       /* fonts usually only, nothing serious will happen        */
891       if ( num_shorts > num_shorts_checked && num_shorts_checked > 0 )
892       {
893         FT_Short  val = (*shorts)[num_shorts_checked - 1];
894 
895 
896         limit = *shorts + num_shorts;
897         for ( ; cur < limit; cur++ )
898           *cur = val;
899       }
900     }
901 
902     FT_FRAME_EXIT();
903 
904     FT_TRACE2(( "loaded\n" ));
905 
906   Exit:
907     return error;
908   }
909 
910 
911   /*************************************************************************/
912   /*                                                                       */
913   /* <Function>                                                            */
914   /*    tt_face_load_metrics_header                                        */
915   /*                                                                       */
916   /* <Description>                                                         */
917   /*    Loads the horizontal or vertical header in a face object.          */
918   /*                                                                       */
919   /* <Input>                                                               */
920   /*    face     :: A handle to the target face object.                    */
921   /*                                                                       */
922   /*    stream   :: The input stream.                                      */
923   /*                                                                       */
924   /*    vertical :: A boolean flag.  If set, load vertical metrics.        */
925   /*                                                                       */
926   /* <Return>                                                              */
927   /*    FreeType error code.  0 means success.                             */
928   /*                                                                       */
929   FT_LOCAL_DEF( FT_Error )
tt_face_load_metrics_header(TT_Face face,FT_Stream stream,FT_Bool vertical)930   tt_face_load_metrics_header( TT_Face    face,
931                                FT_Stream  stream,
932                                FT_Bool    vertical )
933   {
934     FT_Error        error;
935     TT_HoriHeader*  header;
936 
937     const FT_Frame_Field  metrics_header_fields[] =
938     {
939 #undef  FT_STRUCTURE
940 #define FT_STRUCTURE  TT_HoriHeader
941 
942       FT_FRAME_START( 36 ),
943         FT_FRAME_ULONG ( Version ),
944         FT_FRAME_SHORT ( Ascender ),
945         FT_FRAME_SHORT ( Descender ),
946         FT_FRAME_SHORT ( Line_Gap ),
947         FT_FRAME_USHORT( advance_Width_Max ),
948         FT_FRAME_SHORT ( min_Left_Side_Bearing ),
949         FT_FRAME_SHORT ( min_Right_Side_Bearing ),
950         FT_FRAME_SHORT ( xMax_Extent ),
951         FT_FRAME_SHORT ( caret_Slope_Rise ),
952         FT_FRAME_SHORT ( caret_Slope_Run ),
953         FT_FRAME_SHORT ( caret_Offset ),
954         FT_FRAME_SHORT ( Reserved[0] ),
955         FT_FRAME_SHORT ( Reserved[1] ),
956         FT_FRAME_SHORT ( Reserved[2] ),
957         FT_FRAME_SHORT ( Reserved[3] ),
958         FT_FRAME_SHORT ( metric_Data_Format ),
959         FT_FRAME_USHORT( number_Of_HMetrics ),
960       FT_FRAME_END
961     };
962 
963 
964     FT_TRACE2(( vertical ? "Vertical header " : "Horizontal header " ));
965 
966     if ( vertical )
967     {
968       face->vertical_info = 0;
969 
970       /* The vertical header table is optional, so return quietly if */
971       /* we don't find it.                                           */
972       error = face->goto_table( face, TTAG_vhea, stream, 0 );
973       if ( error )
974       {
975         error = SFNT_Err_Ok;
976         goto Exit;
977       }
978 
979       face->vertical_info = 1;
980       header = (TT_HoriHeader*)&face->vertical;
981     }
982     else
983     {
984       /* The horizontal header is mandatory; return an error if we */
985       /* don't find it.                                            */
986       error = face->goto_table( face, TTAG_hhea, stream, 0 );
987       if ( error )
988       {
989         error = SFNT_Err_Horiz_Header_Missing;
990         goto Exit;
991       }
992 
993       header = &face->horizontal;
994     }
995 
996     if ( FT_STREAM_READ_FIELDS( metrics_header_fields, header ) )
997       goto Exit;
998 
999     header->long_metrics  = NULL;
1000     header->short_metrics = NULL;
1001 
1002     FT_TRACE2(( "loaded\n" ));
1003 
1004     /* Now try to load the corresponding metrics */
1005 
1006     error = tt_face_load_metrics( face, stream, vertical );
1007 
1008   Exit:
1009     return error;
1010   }
1011 
1012 
1013   /*************************************************************************/
1014   /*                                                                       */
1015   /* <Function>                                                            */
1016   /*    tt_face_load_names                                                 */
1017   /*                                                                       */
1018   /* <Description>                                                         */
1019   /*    Loads the name records.                                            */
1020   /*                                                                       */
1021   /* <Input>                                                               */
1022   /*    face   :: A handle to the target face object.                      */
1023   /*                                                                       */
1024   /*    stream :: The input stream.                                        */
1025   /*                                                                       */
1026   /* <Return>                                                              */
1027   /*    FreeType error code.  0 means success.                             */
1028   /*                                                                       */
1029   FT_LOCAL_DEF( FT_Error )
tt_face_load_names(TT_Face face,FT_Stream stream)1030   tt_face_load_names( TT_Face    face,
1031                       FT_Stream  stream )
1032   {
1033     FT_Error      error;
1034     FT_Memory     memory = stream->memory;
1035     FT_ULong      table_pos, table_len;
1036     FT_ULong      storage_start, storage_limit;
1037     FT_UInt       count;
1038     TT_NameTable  table;
1039 
1040     static const FT_Frame_Field  name_table_fields[] =
1041     {
1042 #undef  FT_STRUCTURE
1043 #define FT_STRUCTURE  TT_NameTableRec
1044 
1045       FT_FRAME_START( 6 ),
1046         FT_FRAME_USHORT( format ),
1047         FT_FRAME_USHORT( numNameRecords ),
1048         FT_FRAME_USHORT( storageOffset ),
1049       FT_FRAME_END
1050     };
1051 
1052     static const FT_Frame_Field  name_record_fields[] =
1053     {
1054 #undef  FT_STRUCTURE
1055 #define FT_STRUCTURE  TT_NameEntryRec
1056 
1057       /* no FT_FRAME_START */
1058         FT_FRAME_USHORT( platformID ),
1059         FT_FRAME_USHORT( encodingID ),
1060         FT_FRAME_USHORT( languageID ),
1061         FT_FRAME_USHORT( nameID ),
1062         FT_FRAME_USHORT( stringLength ),
1063         FT_FRAME_USHORT( stringOffset ),
1064       FT_FRAME_END
1065     };
1066 
1067 
1068     table         = &face->name_table;
1069     table->stream = stream;
1070 
1071     FT_TRACE2(( "Names " ));
1072 
1073     error = face->goto_table( face, TTAG_name, stream, &table_len );
1074     if ( error )
1075     {
1076       /* The name table is required so indicate failure. */
1077       FT_TRACE2(( "is missing!\n" ));
1078       error = SFNT_Err_Name_Table_Missing;
1079       goto Exit;
1080     }
1081 
1082     table_pos = FT_STREAM_POS();
1083 
1084 
1085     if ( FT_STREAM_READ_FIELDS( name_table_fields, table ) )
1086       goto Exit;
1087 
1088     /* Some popular asian fonts have an invalid `storageOffset' value   */
1089     /* (it should be at least "6 + 12*num_names").  However, the string */
1090     /* offsets, computed as "storageOffset + entry->stringOffset", are  */
1091     /* valid pointers within the name table...                          */
1092     /*                                                                  */
1093     /* We thus can't check `storageOffset' right now.                   */
1094     /*                                                                  */
1095     storage_start = table_pos + 6 + 12*table->numNameRecords;
1096     storage_limit = table_pos + table_len;
1097 
1098     if ( storage_start > storage_limit )
1099     {
1100       FT_ERROR(( "tt_face_load_names: invalid `name' table\n" ));
1101       error = SFNT_Err_Name_Table_Missing;
1102       goto Exit;
1103     }
1104 
1105     /* Allocate the array of name records. */
1106     count                 = table->numNameRecords;
1107     table->numNameRecords = 0;
1108 
1109     if ( FT_NEW_ARRAY( table->names, count ) ||
1110          FT_FRAME_ENTER( count * 12 )        )
1111       goto Exit;
1112 
1113     /* Load the name records and determine how much storage is needed */
1114     /* to hold the strings themselves.                                */
1115     {
1116       TT_NameEntryRec*  entry = table->names;
1117 
1118 
1119       for ( ; count > 0; count-- )
1120       {
1121         if ( FT_STREAM_READ_FIELDS( name_record_fields, entry ) )
1122           continue;
1123 
1124         /* check that the name is not empty */
1125         if ( entry->stringLength == 0 )
1126           continue;
1127 
1128         /* check that the name string is within the table */
1129         entry->stringOffset += table_pos + table->storageOffset;
1130         if ( entry->stringOffset                       < storage_start ||
1131              entry->stringOffset + entry->stringLength > storage_limit )
1132         {
1133           /* invalid entry - ignore it */
1134           entry->stringOffset = 0;
1135           entry->stringLength = 0;
1136           continue;
1137         }
1138 
1139         entry++;
1140       }
1141 
1142       table->numNameRecords = (FT_UInt)( entry - table->names );
1143     }
1144 
1145     FT_FRAME_EXIT();
1146 
1147     FT_TRACE2(( "loaded\n" ));
1148 
1149     /* everything went well, update face->num_names */
1150     face->num_names = (FT_UShort) table->numNameRecords;
1151 
1152   Exit:
1153     return error;
1154   }
1155 
1156 
1157   /*************************************************************************/
1158   /*                                                                       */
1159   /* <Function>                                                            */
1160   /*    tt_face_free_names                                                 */
1161   /*                                                                       */
1162   /* <Description>                                                         */
1163   /*    Frees the name records.                                            */
1164   /*                                                                       */
1165   /* <Input>                                                               */
1166   /*    face :: A handle to the target face object.                        */
1167   /*                                                                       */
1168   FT_LOCAL_DEF( void )
tt_face_free_names(TT_Face face)1169   tt_face_free_names( TT_Face  face )
1170   {
1171     FT_Memory     memory = face->root.driver->root.memory;
1172     TT_NameTable  table  = &face->name_table;
1173     TT_NameEntry  entry  = table->names;
1174     FT_UInt       count  = table->numNameRecords;
1175 
1176 
1177     for ( ; count > 0; count--, entry++ )
1178     {
1179       FT_FREE( entry->string );
1180       entry->stringLength = 0;
1181     }
1182 
1183     /* free strings table */
1184     FT_FREE( table->names );
1185 
1186     table->numNameRecords = 0;
1187     table->format         = 0;
1188     table->storageOffset  = 0;
1189   }
1190 
1191 
1192   /*************************************************************************/
1193   /*                                                                       */
1194   /* <Function>                                                            */
1195   /*    tt_face_load_cmap                                                  */
1196   /*                                                                       */
1197   /* <Description>                                                         */
1198   /*    Loads the cmap directory in a face object.  The cmaps itselves are */
1199   /*    loaded on demand in the `ttcmap.c' module.                         */
1200   /*                                                                       */
1201   /* <Input>                                                               */
1202   /*    face   :: A handle to the target face object.                      */
1203   /*                                                                       */
1204   /*    stream :: A handle to the input stream.                            */
1205   /*                                                                       */
1206   /* <Return>                                                              */
1207   /*    FreeType error code.  0 means success.                             */
1208   /*                                                                       */
1209 
1210   FT_LOCAL_DEF( FT_Error )
tt_face_load_cmap(TT_Face face,FT_Stream stream)1211   tt_face_load_cmap( TT_Face    face,
1212                      FT_Stream  stream )
1213   {
1214     FT_Error  error;
1215 
1216 
1217     error = face->goto_table( face, TTAG_cmap, stream, &face->cmap_size );
1218     if ( error )
1219     {
1220       FT_TRACE2(( "No `cmap' table in font !\n" ));
1221       error = SFNT_Err_CMap_Table_Missing;
1222       goto Exit;
1223     }
1224 
1225     if ( !FT_FRAME_EXTRACT( face->cmap_size, face->cmap_table ) )
1226       FT_TRACE2(( "`cmap' table loaded\n" ));
1227     else
1228     {
1229       FT_ERROR(( "`cmap' table is too short!\n" ));
1230       face->cmap_size = 0;
1231     }
1232 
1233   Exit:
1234     return error;
1235   }
1236 
1237 
1238 
1239   /*************************************************************************/
1240   /*                                                                       */
1241   /* <Function>                                                            */
1242   /*    tt_face_load_os2                                                   */
1243   /*                                                                       */
1244   /* <Description>                                                         */
1245   /*    Loads the OS2 table.                                               */
1246   /*                                                                       */
1247   /* <Input>                                                               */
1248   /*    face   :: A handle to the target face object.                      */
1249   /*                                                                       */
1250   /*    stream :: A handle to the input stream.                            */
1251   /*                                                                       */
1252   /* <Return>                                                              */
1253   /*    FreeType error code.  0 means success.                             */
1254   /*                                                                       */
1255   FT_LOCAL_DEF( FT_Error )
tt_face_load_os2(TT_Face face,FT_Stream stream)1256   tt_face_load_os2( TT_Face    face,
1257                     FT_Stream  stream )
1258   {
1259     FT_Error  error;
1260     TT_OS2*   os2;
1261 
1262     const FT_Frame_Field  os2_fields[] =
1263     {
1264 #undef  FT_STRUCTURE
1265 #define FT_STRUCTURE  TT_OS2
1266 
1267       FT_FRAME_START( 78 ),
1268         FT_FRAME_USHORT( version ),
1269         FT_FRAME_SHORT ( xAvgCharWidth ),
1270         FT_FRAME_USHORT( usWeightClass ),
1271         FT_FRAME_USHORT( usWidthClass ),
1272         FT_FRAME_SHORT ( fsType ),
1273         FT_FRAME_SHORT ( ySubscriptXSize ),
1274         FT_FRAME_SHORT ( ySubscriptYSize ),
1275         FT_FRAME_SHORT ( ySubscriptXOffset ),
1276         FT_FRAME_SHORT ( ySubscriptYOffset ),
1277         FT_FRAME_SHORT ( ySuperscriptXSize ),
1278         FT_FRAME_SHORT ( ySuperscriptYSize ),
1279         FT_FRAME_SHORT ( ySuperscriptXOffset ),
1280         FT_FRAME_SHORT ( ySuperscriptYOffset ),
1281         FT_FRAME_SHORT ( yStrikeoutSize ),
1282         FT_FRAME_SHORT ( yStrikeoutPosition ),
1283         FT_FRAME_SHORT ( sFamilyClass ),
1284         FT_FRAME_BYTE  ( panose[0] ),
1285         FT_FRAME_BYTE  ( panose[1] ),
1286         FT_FRAME_BYTE  ( panose[2] ),
1287         FT_FRAME_BYTE  ( panose[3] ),
1288         FT_FRAME_BYTE  ( panose[4] ),
1289         FT_FRAME_BYTE  ( panose[5] ),
1290         FT_FRAME_BYTE  ( panose[6] ),
1291         FT_FRAME_BYTE  ( panose[7] ),
1292         FT_FRAME_BYTE  ( panose[8] ),
1293         FT_FRAME_BYTE  ( panose[9] ),
1294         FT_FRAME_ULONG ( ulUnicodeRange1 ),
1295         FT_FRAME_ULONG ( ulUnicodeRange2 ),
1296         FT_FRAME_ULONG ( ulUnicodeRange3 ),
1297         FT_FRAME_ULONG ( ulUnicodeRange4 ),
1298         FT_FRAME_BYTE  ( achVendID[0] ),
1299         FT_FRAME_BYTE  ( achVendID[1] ),
1300         FT_FRAME_BYTE  ( achVendID[2] ),
1301         FT_FRAME_BYTE  ( achVendID[3] ),
1302 
1303         FT_FRAME_USHORT( fsSelection ),
1304         FT_FRAME_USHORT( usFirstCharIndex ),
1305         FT_FRAME_USHORT( usLastCharIndex ),
1306         FT_FRAME_SHORT ( sTypoAscender ),
1307         FT_FRAME_SHORT ( sTypoDescender ),
1308         FT_FRAME_SHORT ( sTypoLineGap ),
1309         FT_FRAME_USHORT( usWinAscent ),
1310         FT_FRAME_USHORT( usWinDescent ),
1311       FT_FRAME_END
1312     };
1313 
1314     const FT_Frame_Field  os2_fields_extra[] =
1315     {
1316       FT_FRAME_START( 8 ),
1317         FT_FRAME_ULONG( ulCodePageRange1 ),
1318         FT_FRAME_ULONG( ulCodePageRange2 ),
1319       FT_FRAME_END
1320     };
1321 
1322     const FT_Frame_Field  os2_fields_extra2[] =
1323     {
1324       FT_FRAME_START( 10 ),
1325         FT_FRAME_SHORT ( sxHeight ),
1326         FT_FRAME_SHORT ( sCapHeight ),
1327         FT_FRAME_USHORT( usDefaultChar ),
1328         FT_FRAME_USHORT( usBreakChar ),
1329         FT_FRAME_USHORT( usMaxContext ),
1330       FT_FRAME_END
1331     };
1332 
1333 
1334     FT_TRACE2(( "OS/2 Table " ));
1335 
1336     /* We now support old Mac fonts where the OS/2 table doesn't  */
1337     /* exist.  Simply put, we set the `version' field to 0xFFFF   */
1338     /* and test this value each time we need to access the table. */
1339     error = face->goto_table( face, TTAG_OS2, stream, 0 );
1340     if ( error )
1341     {
1342       FT_TRACE2(( "is missing!\n" ));
1343       face->os2.version = 0xFFFFU;
1344       error = SFNT_Err_Ok;
1345       goto Exit;
1346     }
1347 
1348     os2 = &face->os2;
1349 
1350     if ( FT_STREAM_READ_FIELDS( os2_fields, os2 ) )
1351       goto Exit;
1352 
1353     os2->ulCodePageRange1 = 0;
1354     os2->ulCodePageRange2 = 0;
1355     os2->sxHeight         = 0;
1356     os2->sCapHeight       = 0;
1357     os2->usDefaultChar    = 0;
1358     os2->usBreakChar      = 0;
1359     os2->usMaxContext     = 0;
1360 
1361     if ( os2->version >= 0x0001 )
1362     {
1363       /* only version 1 tables */
1364       if ( FT_STREAM_READ_FIELDS( os2_fields_extra, os2 ) )
1365         goto Exit;
1366 
1367       if ( os2->version >= 0x0002 )
1368       {
1369         /* only version 2 tables */
1370         if ( FT_STREAM_READ_FIELDS( os2_fields_extra2, os2 ) )
1371           goto Exit;
1372       }
1373     }
1374 
1375     FT_TRACE2(( "loaded\n" ));
1376 
1377   Exit:
1378     return error;
1379   }
1380 
1381 
1382   /*************************************************************************/
1383   /*                                                                       */
1384   /* <Function>                                                            */
1385   /*    tt_face_load_postscript                                            */
1386   /*                                                                       */
1387   /* <Description>                                                         */
1388   /*    Loads the Postscript table.                                        */
1389   /*                                                                       */
1390   /* <Input>                                                               */
1391   /*    face   :: A handle to the target face object.                      */
1392   /*                                                                       */
1393   /*    stream :: A handle to the input stream.                            */
1394   /*                                                                       */
1395   /* <Return>                                                              */
1396   /*    FreeType error code.  0 means success.                             */
1397   /*                                                                       */
1398   FT_LOCAL_DEF( FT_Error )
tt_face_load_postscript(TT_Face face,FT_Stream stream)1399   tt_face_load_postscript( TT_Face    face,
1400                            FT_Stream  stream )
1401   {
1402     FT_Error        error;
1403     TT_Postscript*  post = &face->postscript;
1404 
1405     static const FT_Frame_Field  post_fields[] =
1406     {
1407 #undef  FT_STRUCTURE
1408 #define FT_STRUCTURE  TT_Postscript
1409 
1410       FT_FRAME_START( 32 ),
1411         FT_FRAME_ULONG( FormatType ),
1412         FT_FRAME_ULONG( italicAngle ),
1413         FT_FRAME_SHORT( underlinePosition ),
1414         FT_FRAME_SHORT( underlineThickness ),
1415         FT_FRAME_ULONG( isFixedPitch ),
1416         FT_FRAME_ULONG( minMemType42 ),
1417         FT_FRAME_ULONG( maxMemType42 ),
1418         FT_FRAME_ULONG( minMemType1 ),
1419         FT_FRAME_ULONG( maxMemType1 ),
1420       FT_FRAME_END
1421     };
1422 
1423 
1424     FT_TRACE2(( "PostScript " ));
1425 
1426     error = face->goto_table( face, TTAG_post, stream, 0 );
1427     if ( error )
1428       return SFNT_Err_Post_Table_Missing;
1429 
1430     if ( FT_STREAM_READ_FIELDS( post_fields, post ) )
1431       return error;
1432 
1433     /* we don't load the glyph names, we do that in another */
1434     /* module (ttpost).                                     */
1435     FT_TRACE2(( "loaded\n" ));
1436 
1437     return SFNT_Err_Ok;
1438   }
1439 
1440 
1441   /*************************************************************************/
1442   /*                                                                       */
1443   /* <Function>                                                            */
1444   /*    tt_face_load_pclt                                                  */
1445   /*                                                                       */
1446   /* <Description>                                                         */
1447   /*    Loads the PCL 5 Table.                                             */
1448   /*                                                                       */
1449   /* <Input>                                                               */
1450   /*    face   :: A handle to the target face object.                      */
1451   /*                                                                       */
1452   /*    stream :: A handle to the input stream.                            */
1453   /*                                                                       */
1454   /* <Return>                                                              */
1455   /*    FreeType error code.  0 means success.                             */
1456   /*                                                                       */
1457   FT_LOCAL_DEF( FT_Error )
tt_face_load_pclt(TT_Face face,FT_Stream stream)1458   tt_face_load_pclt( TT_Face    face,
1459                      FT_Stream  stream )
1460   {
1461     static const FT_Frame_Field  pclt_fields[] =
1462     {
1463 #undef  FT_STRUCTURE
1464 #define FT_STRUCTURE  TT_PCLT
1465 
1466       FT_FRAME_START( 54 ),
1467         FT_FRAME_ULONG ( Version ),
1468         FT_FRAME_ULONG ( FontNumber ),
1469         FT_FRAME_USHORT( Pitch ),
1470         FT_FRAME_USHORT( xHeight ),
1471         FT_FRAME_USHORT( Style ),
1472         FT_FRAME_USHORT( TypeFamily ),
1473         FT_FRAME_USHORT( CapHeight ),
1474         FT_FRAME_BYTES ( TypeFace, 16 ),
1475         FT_FRAME_BYTES ( CharacterComplement, 8 ),
1476         FT_FRAME_BYTES ( FileName, 6 ),
1477         FT_FRAME_CHAR  ( StrokeWeight ),
1478         FT_FRAME_CHAR  ( WidthType ),
1479         FT_FRAME_BYTE  ( SerifStyle ),
1480         FT_FRAME_BYTE  ( Reserved ),
1481       FT_FRAME_END
1482     };
1483 
1484     FT_Error  error;
1485     TT_PCLT*  pclt = &face->pclt;
1486 
1487 
1488     FT_TRACE2(( "PCLT " ));
1489 
1490     /* optional table */
1491     error = face->goto_table( face, TTAG_PCLT, stream, 0 );
1492     if ( error )
1493     {
1494       FT_TRACE2(( "missing (optional)\n" ));
1495       pclt->Version = 0;
1496       return SFNT_Err_Ok;
1497     }
1498 
1499     if ( FT_STREAM_READ_FIELDS( pclt_fields, pclt ) )
1500       goto Exit;
1501 
1502     FT_TRACE2(( "loaded\n" ));
1503 
1504   Exit:
1505     return error;
1506   }
1507 
1508 
1509   /*************************************************************************/
1510   /*                                                                       */
1511   /* <Function>                                                            */
1512   /*    tt_face_load_gasp                                                  */
1513   /*                                                                       */
1514   /* <Description>                                                         */
1515   /*    Loads the `gasp' table into a face object.                         */
1516   /*                                                                       */
1517   /* <Input>                                                               */
1518   /*    face   :: A handle to the target face object.                      */
1519   /*                                                                       */
1520   /*    stream :: The input stream.                                        */
1521   /*                                                                       */
1522   /* <Return>                                                              */
1523   /*    FreeType error code.  0 means success.                             */
1524   /*                                                                       */
1525   FT_LOCAL_DEF( FT_Error )
tt_face_load_gasp(TT_Face face,FT_Stream stream)1526   tt_face_load_gasp( TT_Face    face,
1527                      FT_Stream  stream )
1528   {
1529     FT_Error   error;
1530     FT_Memory  memory = stream->memory;
1531 
1532     FT_UInt        j,num_ranges;
1533     TT_GaspRange   gaspranges;
1534 
1535 
1536     FT_TRACE2(( "tt_face_load_gasp: %08p\n", face ));
1537 
1538     /* the gasp table is optional */
1539     error = face->goto_table( face, TTAG_gasp, stream, 0 );
1540     if ( error )
1541       return SFNT_Err_Ok;
1542 
1543     if ( FT_FRAME_ENTER( 4L ) )
1544       goto Exit;
1545 
1546     face->gasp.version   = FT_GET_USHORT();
1547     face->gasp.numRanges = FT_GET_USHORT();
1548 
1549     FT_FRAME_EXIT();
1550 
1551     num_ranges = face->gasp.numRanges;
1552     FT_TRACE3(( "number of ranges = %d\n", num_ranges ));
1553 
1554     if ( FT_NEW_ARRAY( gaspranges, num_ranges ) ||
1555          FT_FRAME_ENTER( num_ranges * 4L )      )
1556       goto Exit;
1557 
1558     face->gasp.gaspRanges = gaspranges;
1559 
1560     for ( j = 0; j < num_ranges; j++ )
1561     {
1562       gaspranges[j].maxPPEM  = FT_GET_USHORT();
1563       gaspranges[j].gaspFlag = FT_GET_USHORT();
1564 
1565       FT_TRACE3(( " [max:%d flag:%d]",
1566                     gaspranges[j].maxPPEM,
1567                     gaspranges[j].gaspFlag ));
1568     }
1569     FT_TRACE3(( "\n" ));
1570 
1571     FT_FRAME_EXIT();
1572     FT_TRACE2(( "GASP loaded\n" ));
1573 
1574   Exit:
1575     return error;
1576   }
1577 
1578 
1579   FT_CALLBACK_DEF( int )
1580   tt_kern_pair_compare( const void*  a,
1581                         const void*  b );
1582 
1583 
1584   /*************************************************************************/
1585   /*                                                                       */
1586   /* <Function>                                                            */
1587   /*    tt_face_load_kern                                                  */
1588   /*                                                                       */
1589   /* <Description>                                                         */
1590   /*    Loads the first kerning table with format 0 in the font.  Only     */
1591   /*    accepts the first horizontal kerning table.  Developers should use */
1592   /*    the `ftxkern' extension to access other kerning tables in the font */
1593   /*    file, if they really want to.                                      */
1594   /*                                                                       */
1595   /* <Input>                                                               */
1596   /*    face   :: A handle to the target face object.                      */
1597   /*                                                                       */
1598   /*    stream :: The input stream.                                        */
1599   /*                                                                       */
1600   /* <Return>                                                              */
1601   /*    FreeType error code.  0 means success.                             */
1602   /*                                                                       */
1603   FT_LOCAL_DEF( FT_Error )
tt_face_load_kern(TT_Face face,FT_Stream stream)1604   tt_face_load_kern( TT_Face    face,
1605                      FT_Stream  stream )
1606   {
1607     FT_Error   error;
1608     FT_Memory  memory = stream->memory;
1609 
1610     FT_UInt    n, num_tables;
1611 
1612 
1613     /* the kern table is optional; exit silently if it is missing */
1614     error = face->goto_table( face, TTAG_kern, stream, 0 );
1615     if ( error )
1616       return SFNT_Err_Ok;
1617 
1618     if ( FT_FRAME_ENTER( 4L ) )
1619       goto Exit;
1620 
1621     (void)FT_GET_USHORT();         /* version */
1622     num_tables = FT_GET_USHORT();
1623 
1624     FT_FRAME_EXIT();
1625 
1626     for ( n = 0; n < num_tables; n++ )
1627     {
1628       FT_UInt  coverage;
1629       FT_UInt  length;
1630 
1631 
1632       if ( FT_FRAME_ENTER( 6L ) )
1633         goto Exit;
1634 
1635       (void)FT_GET_USHORT();           /* version                 */
1636       length   = FT_GET_USHORT() - 6;  /* substract header length */
1637       coverage = FT_GET_USHORT();
1638 
1639       FT_FRAME_EXIT();
1640 
1641       if ( coverage == 0x0001 )
1642       {
1643         FT_UInt        num_pairs;
1644         TT_Kern0_Pair  pair;
1645         TT_Kern0_Pair  limit;
1646 
1647 
1648         /* found a horizontal format 0 kerning table! */
1649         if ( FT_FRAME_ENTER( 8L ) )
1650           goto Exit;
1651 
1652         num_pairs = FT_GET_USHORT();
1653 
1654         /* skip the rest */
1655 
1656         FT_FRAME_EXIT();
1657 
1658         /* allocate array of kerning pairs */
1659         if ( FT_NEW_ARRAY( face->kern_pairs, num_pairs ) ||
1660              FT_FRAME_ENTER( 6L * num_pairs )            )
1661           goto Exit;
1662 
1663         pair  = face->kern_pairs;
1664         limit = pair + num_pairs;
1665         for ( ; pair < limit; pair++ )
1666         {
1667           pair->left  = FT_GET_USHORT();
1668           pair->right = FT_GET_USHORT();
1669           pair->value = FT_GET_USHORT();
1670         }
1671 
1672         FT_FRAME_EXIT();
1673 
1674         face->num_kern_pairs   = num_pairs;
1675         face->kern_table_index = n;
1676 
1677         /* ensure that the kerning pair table is sorted (yes, some */
1678         /* fonts have unsorted tables!)                            */
1679         {
1680           FT_UInt        i;
1681           TT_Kern0_Pair  pair0;
1682 
1683 
1684           pair0 = face->kern_pairs;
1685 
1686           for ( i = 1; i < num_pairs; i++, pair0++ )
1687           {
1688             if ( tt_kern_pair_compare( pair0, pair0 + 1 ) != -1 )
1689             {
1690               ft_qsort( (void*)face->kern_pairs, (int)num_pairs,
1691                         sizeof ( TT_Kern0_PairRec ), tt_kern_pair_compare );
1692               break;
1693             }
1694           }
1695         }
1696 
1697         goto Exit;
1698       }
1699 
1700       if ( FT_STREAM_SKIP( length ) )
1701         goto Exit;
1702     }
1703 
1704     /* no kern table found -- doesn't matter */
1705     face->kern_table_index = -1;
1706     face->num_kern_pairs   = 0;
1707     face->kern_pairs       = NULL;
1708 
1709   Exit:
1710     return error;
1711   }
1712 
1713 
1714 #undef  TT_KERN_INDEX
1715 #define TT_KERN_INDEX( g1, g2 )  ( ( (FT_ULong)g1 << 16 ) | g2 )
1716 
1717 
1718   FT_CALLBACK_DEF( int )
tt_kern_pair_compare(const void * a,const void * b)1719   tt_kern_pair_compare( const void*  a,
1720                         const void*  b )
1721   {
1722     TT_Kern0_Pair  pair1 = (TT_Kern0_Pair)a;
1723     TT_Kern0_Pair  pair2 = (TT_Kern0_Pair)b;
1724 
1725     FT_ULong  index1 = TT_KERN_INDEX( pair1->left, pair1->right );
1726     FT_ULong  index2 = TT_KERN_INDEX( pair2->left, pair2->right );
1727 
1728 
1729     return ( index1 < index2 ? -1 :
1730            ( index1 > index2 ?  1 : 0 ));
1731   }
1732 
1733 
1734 #undef TT_KERN_INDEX
1735 
1736 
1737   /*************************************************************************/
1738   /*                                                                       */
1739   /* <Function>                                                            */
1740   /*    tt_face_load_hdmx                                                  */
1741   /*                                                                       */
1742   /* <Description>                                                         */
1743   /*    Loads the horizontal device metrics table.                         */
1744   /*                                                                       */
1745   /* <Input>                                                               */
1746   /*    face   :: A handle to the target face object.                      */
1747   /*                                                                       */
1748   /*    stream :: A handle to the input stream.                            */
1749   /*                                                                       */
1750   /* <Return>                                                              */
1751   /*    FreeType error code.  0 means success.                             */
1752   /*                                                                       */
1753   FT_LOCAL_DEF( FT_Error )
tt_face_load_hdmx(TT_Face face,FT_Stream stream)1754   tt_face_load_hdmx( TT_Face    face,
1755                      FT_Stream  stream )
1756   {
1757     FT_Error   error;
1758     FT_Memory  memory = stream->memory;
1759 
1760     TT_Hdmx    hdmx = &face->hdmx;
1761     FT_Long    num_glyphs;
1762     FT_Long    record_size;
1763 
1764 
1765     hdmx->version     = 0;
1766     hdmx->num_records = 0;
1767     hdmx->records     = 0;
1768 
1769     /* this table is optional */
1770     error = face->goto_table( face, TTAG_hdmx, stream, 0 );
1771     if ( error )
1772       return SFNT_Err_Ok;
1773 
1774     if ( FT_FRAME_ENTER( 8L ) )
1775       goto Exit;
1776 
1777     hdmx->version     = FT_GET_USHORT();
1778     hdmx->num_records = FT_GET_SHORT();
1779     record_size       = FT_GET_LONG();
1780 
1781     FT_FRAME_EXIT();
1782 
1783     /* Only recognize format 0 */
1784     if ( hdmx->version != 0 )
1785       goto Exit;
1786 
1787     if ( FT_NEW_ARRAY( hdmx->records, hdmx->num_records ) )
1788       goto Exit;
1789 
1790     num_glyphs   = face->root.num_glyphs;
1791     record_size -= num_glyphs + 2;
1792 
1793     {
1794       TT_HdmxEntry  cur   = hdmx->records;
1795       TT_HdmxEntry  limit = cur + hdmx->num_records;
1796 
1797 
1798       for ( ; cur < limit; cur++ )
1799       {
1800         /* read record */
1801         if ( FT_READ_BYTE( cur->ppem      ) ||
1802              FT_READ_BYTE( cur->max_width ) )
1803           goto Exit;
1804 
1805         if ( FT_ALLOC( cur->widths, num_glyphs )       ||
1806              FT_STREAM_READ( cur->widths, num_glyphs ) )
1807           goto Exit;
1808 
1809         /* skip padding bytes */
1810         if ( record_size > 0 && FT_STREAM_SKIP( record_size ) )
1811             goto Exit;
1812       }
1813     }
1814 
1815   Exit:
1816     return error;
1817   }
1818 
1819 
1820   /*************************************************************************/
1821   /*                                                                       */
1822   /* <Function>                                                            */
1823   /*    tt_face_free_hdmx                                                  */
1824   /*                                                                       */
1825   /* <Description>                                                         */
1826   /*    Frees the horizontal device metrics table.                         */
1827   /*                                                                       */
1828   /* <Input>                                                               */
1829   /*    face :: A handle to the target face object.                        */
1830   /*                                                                       */
1831   FT_LOCAL_DEF( void )
tt_face_free_hdmx(TT_Face face)1832   tt_face_free_hdmx( TT_Face  face )
1833   {
1834     if ( face )
1835     {
1836       FT_Int     n;
1837       FT_Memory  memory = face->root.driver->root.memory;
1838 
1839 
1840       for ( n = 0; n < face->hdmx.num_records; n++ )
1841         FT_FREE( face->hdmx.records[n].widths );
1842 
1843       FT_FREE( face->hdmx.records );
1844       face->hdmx.num_records = 0;
1845     }
1846   }
1847 
1848 
1849 /* END */
1850