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