1/***************************************************************************/
2/*                                                                         */
3/*  sfobjs.c                                                               */
4/*                                                                         */
5/*    SFNT object management (base).                                       */
6/*                                                                         */
7/*  Copyright 1996-2008, 2010-2014 by                                      */
8/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
9/*                                                                         */
10/*  This file is part of the FreeType project, and may only be used,       */
11/*  modified, and distributed under the terms of the FreeType project      */
12/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
13/*  this file you indicate that you have read the license and              */
14/*  understand and accept it fully.                                        */
15/*                                                                         */
16/***************************************************************************/
17
18
19#include <ft2build.h>
20#include "sfobjs.h"
21#include "ttload.h"
22#include "ttcmap.h"
23#include "ttkern.h"
24#include FT_INTERNAL_SFNT_H
25#include FT_INTERNAL_DEBUG_H
26#include FT_TRUETYPE_IDS_H
27#include FT_TRUETYPE_TAGS_H
28#include FT_SERVICE_POSTSCRIPT_CMAPS_H
29#include FT_SFNT_NAMES_H
30#include FT_GZIP_H
31#include "sferrors.h"
32
33#ifdef TT_CONFIG_OPTION_BDF
34#include "ttbdf.h"
35#endif
36
37
38  /*************************************************************************/
39  /*                                                                       */
40  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
41  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
42  /* messages during execution.                                            */
43  /*                                                                       */
44#undef  FT_COMPONENT
45#define FT_COMPONENT  trace_sfobjs
46
47
48
49  /* convert a UTF-16 name entry to ASCII */
50  static FT_String*
51  tt_name_entry_ascii_from_utf16( TT_NameEntry  entry,
52                                  FT_Memory     memory )
53  {
54    FT_String*  string = NULL;
55    FT_UInt     len, code, n;
56    FT_Byte*    read   = (FT_Byte*)entry->string;
57    FT_Error    error;
58
59
60    len = (FT_UInt)entry->stringLength / 2;
61
62    if ( FT_NEW_ARRAY( string, len + 1 ) )
63      return NULL;
64
65    for ( n = 0; n < len; n++ )
66    {
67      code = FT_NEXT_USHORT( read );
68
69      if ( code == 0 )
70        break;
71
72      if ( code < 32 || code > 127 )
73        code = '?';
74
75      string[n] = (char)code;
76    }
77
78    string[n] = 0;
79
80    return string;
81  }
82
83
84  /* convert an Apple Roman or symbol name entry to ASCII */
85  static FT_String*
86  tt_name_entry_ascii_from_other( TT_NameEntry  entry,
87                                  FT_Memory     memory )
88  {
89    FT_String*  string = NULL;
90    FT_UInt     len, code, n;
91    FT_Byte*    read   = (FT_Byte*)entry->string;
92    FT_Error    error;
93
94
95    len = (FT_UInt)entry->stringLength;
96
97    if ( FT_NEW_ARRAY( string, len + 1 ) )
98      return NULL;
99
100    for ( n = 0; n < len; n++ )
101    {
102      code = *read++;
103
104      if ( code == 0 )
105        break;
106
107      if ( code < 32 || code > 127 )
108        code = '?';
109
110      string[n] = (char)code;
111    }
112
113    string[n] = 0;
114
115    return string;
116  }
117
118
119  typedef FT_String*  (*TT_NameEntry_ConvertFunc)( TT_NameEntry  entry,
120                                                   FT_Memory     memory );
121
122
123  /*************************************************************************/
124  /*                                                                       */
125  /* <Function>                                                            */
126  /*    tt_face_get_name                                                   */
127  /*                                                                       */
128  /* <Description>                                                         */
129  /*    Returns a given ENGLISH name record in ASCII.                      */
130  /*                                                                       */
131  /* <Input>                                                               */
132  /*    face   :: A handle to the source face object.                      */
133  /*                                                                       */
134  /*    nameid :: The name id of the name record to return.                */
135  /*                                                                       */
136  /* <InOut>                                                               */
137  /*    name   :: The address of a string pointer.  NULL if no name is     */
138  /*              present.                                                 */
139  /*                                                                       */
140  /* <Return>                                                              */
141  /*    FreeType error code.  0 means success.                             */
142  /*                                                                       */
143  static FT_Error
144  tt_face_get_name( TT_Face      face,
145                    FT_UShort    nameid,
146                    FT_String**  name )
147  {
148    FT_Memory         memory = face->root.memory;
149    FT_Error          error  = FT_Err_Ok;
150    FT_String*        result = NULL;
151    FT_UShort         n;
152    TT_NameEntryRec*  rec;
153    FT_Int            found_apple         = -1;
154    FT_Int            found_apple_roman   = -1;
155    FT_Int            found_apple_english = -1;
156    FT_Int            found_win           = -1;
157    FT_Int            found_unicode       = -1;
158
159    FT_Bool           is_english = 0;
160
161    TT_NameEntry_ConvertFunc  convert;
162
163
164    FT_ASSERT( name );
165
166    rec = face->name_table.names;
167    for ( n = 0; n < face->num_names; n++, rec++ )
168    {
169      /* According to the OpenType 1.3 specification, only Microsoft or  */
170      /* Apple platform IDs might be used in the `name' table.  The      */
171      /* `Unicode' platform is reserved for the `cmap' table, and the    */
172      /* `ISO' one is deprecated.                                        */
173      /*                                                                 */
174      /* However, the Apple TrueType specification doesn't say the same  */
175      /* thing and goes to suggest that all Unicode `name' table entries */
176      /* should be coded in UTF-16 (in big-endian format I suppose).     */
177      /*                                                                 */
178      if ( rec->nameID == nameid && rec->stringLength > 0 )
179      {
180        switch ( rec->platformID )
181        {
182        case TT_PLATFORM_APPLE_UNICODE:
183        case TT_PLATFORM_ISO:
184          /* there is `languageID' to check there.  We should use this */
185          /* field only as a last solution when nothing else is        */
186          /* available.                                                */
187          /*                                                           */
188          found_unicode = n;
189          break;
190
191        case TT_PLATFORM_MACINTOSH:
192          /* This is a bit special because some fonts will use either    */
193          /* an English language id, or a Roman encoding id, to indicate */
194          /* the English version of its font name.                       */
195          /*                                                             */
196          if ( rec->languageID == TT_MAC_LANGID_ENGLISH )
197            found_apple_english = n;
198          else if ( rec->encodingID == TT_MAC_ID_ROMAN )
199            found_apple_roman = n;
200          break;
201
202        case TT_PLATFORM_MICROSOFT:
203          /* we only take a non-English name when there is nothing */
204          /* else available in the font                            */
205          /*                                                       */
206          if ( found_win == -1 || ( rec->languageID & 0x3FF ) == 0x009 )
207          {
208            switch ( rec->encodingID )
209            {
210            case TT_MS_ID_SYMBOL_CS:
211            case TT_MS_ID_UNICODE_CS:
212            case TT_MS_ID_UCS_4:
213              is_english = FT_BOOL( ( rec->languageID & 0x3FF ) == 0x009 );
214              found_win  = n;
215              break;
216
217            default:
218              ;
219            }
220          }
221          break;
222
223        default:
224          ;
225        }
226      }
227    }
228
229    found_apple = found_apple_roman;
230    if ( found_apple_english >= 0 )
231      found_apple = found_apple_english;
232
233    /* some fonts contain invalid Unicode or Macintosh formatted entries; */
234    /* we will thus favor names encoded in Windows formats if available   */
235    /* (provided it is an English name)                                   */
236    /*                                                                    */
237    convert = NULL;
238    if ( found_win >= 0 && !( found_apple >= 0 && !is_english ) )
239    {
240      rec = face->name_table.names + found_win;
241      switch ( rec->encodingID )
242      {
243        /* all Unicode strings are encoded using UTF-16BE */
244      case TT_MS_ID_UNICODE_CS:
245      case TT_MS_ID_SYMBOL_CS:
246        convert = tt_name_entry_ascii_from_utf16;
247        break;
248
249      case TT_MS_ID_UCS_4:
250        /* Apparently, if this value is found in a name table entry, it is */
251        /* documented as `full Unicode repertoire'.  Experience with the   */
252        /* MsGothic font shipped with Windows Vista shows that this really */
253        /* means UTF-16 encoded names (UCS-4 values are only used within   */
254        /* charmaps).                                                      */
255        convert = tt_name_entry_ascii_from_utf16;
256        break;
257
258      default:
259        ;
260      }
261    }
262    else if ( found_apple >= 0 )
263    {
264      rec     = face->name_table.names + found_apple;
265      convert = tt_name_entry_ascii_from_other;
266    }
267    else if ( found_unicode >= 0 )
268    {
269      rec     = face->name_table.names + found_unicode;
270      convert = tt_name_entry_ascii_from_utf16;
271    }
272
273    if ( rec && convert )
274    {
275      if ( rec->string == NULL )
276      {
277        FT_Stream  stream = face->name_table.stream;
278
279
280        if ( FT_QNEW_ARRAY ( rec->string, rec->stringLength ) ||
281             FT_STREAM_SEEK( rec->stringOffset )              ||
282             FT_STREAM_READ( rec->string, rec->stringLength ) )
283        {
284          FT_FREE( rec->string );
285          rec->stringLength = 0;
286          result            = NULL;
287          goto Exit;
288        }
289      }
290
291      result = convert( rec, memory );
292    }
293
294  Exit:
295    *name = result;
296    return error;
297  }
298
299
300  static FT_Encoding
301  sfnt_find_encoding( int  platform_id,
302                      int  encoding_id )
303  {
304    typedef struct  TEncoding_
305    {
306      int          platform_id;
307      int          encoding_id;
308      FT_Encoding  encoding;
309
310    } TEncoding;
311
312    static
313    const TEncoding  tt_encodings[] =
314    {
315      { TT_PLATFORM_ISO,           -1,                  FT_ENCODING_UNICODE },
316
317      { TT_PLATFORM_APPLE_UNICODE, -1,                  FT_ENCODING_UNICODE },
318
319      { TT_PLATFORM_MACINTOSH,     TT_MAC_ID_ROMAN,     FT_ENCODING_APPLE_ROMAN },
320
321      { TT_PLATFORM_MICROSOFT,     TT_MS_ID_SYMBOL_CS,  FT_ENCODING_MS_SYMBOL },
322      { TT_PLATFORM_MICROSOFT,     TT_MS_ID_UCS_4,      FT_ENCODING_UNICODE },
323      { TT_PLATFORM_MICROSOFT,     TT_MS_ID_UNICODE_CS, FT_ENCODING_UNICODE },
324      { TT_PLATFORM_MICROSOFT,     TT_MS_ID_SJIS,       FT_ENCODING_SJIS },
325      { TT_PLATFORM_MICROSOFT,     TT_MS_ID_GB2312,     FT_ENCODING_GB2312 },
326      { TT_PLATFORM_MICROSOFT,     TT_MS_ID_BIG_5,      FT_ENCODING_BIG5 },
327      { TT_PLATFORM_MICROSOFT,     TT_MS_ID_WANSUNG,    FT_ENCODING_WANSUNG },
328      { TT_PLATFORM_MICROSOFT,     TT_MS_ID_JOHAB,      FT_ENCODING_JOHAB }
329    };
330
331    const TEncoding  *cur, *limit;
332
333
334    cur   = tt_encodings;
335    limit = cur + sizeof ( tt_encodings ) / sizeof ( tt_encodings[0] );
336
337    for ( ; cur < limit; cur++ )
338    {
339      if ( cur->platform_id == platform_id )
340      {
341        if ( cur->encoding_id == encoding_id ||
342             cur->encoding_id == -1          )
343          return cur->encoding;
344      }
345    }
346
347    return FT_ENCODING_NONE;
348  }
349
350
351#define WRITE_USHORT( p, v )                \
352          do                                \
353          {                                 \
354            *(p)++ = (FT_Byte)( (v) >> 8 ); \
355            *(p)++ = (FT_Byte)( (v) >> 0 ); \
356                                            \
357          } while ( 0 )
358
359#define WRITE_ULONG( p, v )                  \
360          do                                 \
361          {                                  \
362            *(p)++ = (FT_Byte)( (v) >> 24 ); \
363            *(p)++ = (FT_Byte)( (v) >> 16 ); \
364            *(p)++ = (FT_Byte)( (v) >>  8 ); \
365            *(p)++ = (FT_Byte)( (v) >>  0 ); \
366                                             \
367          } while ( 0 )
368
369
370  static void
371  sfnt_stream_close( FT_Stream  stream )
372  {
373    FT_Memory  memory = stream->memory;
374
375
376    FT_FREE( stream->base );
377
378    stream->size  = 0;
379    stream->base  = 0;
380    stream->close = 0;
381  }
382
383
384  FT_CALLBACK_DEF( int )
385  compare_offsets( const void*  a,
386                   const void*  b )
387  {
388    WOFF_Table  table1 = *(WOFF_Table*)a;
389    WOFF_Table  table2 = *(WOFF_Table*)b;
390
391    FT_ULong  offset1 = table1->Offset;
392    FT_ULong  offset2 = table2->Offset;
393
394
395    if ( offset1 > offset2 )
396      return 1;
397    else if ( offset1 < offset2 )
398      return -1;
399    else
400      return 0;
401  }
402
403
404  /* Replace `face->root.stream' with a stream containing the extracted */
405  /* SFNT of a WOFF font.                                               */
406
407  static FT_Error
408  woff_open_font( FT_Stream  stream,
409                  TT_Face    face )
410  {
411    FT_Memory       memory = stream->memory;
412    FT_Error        error  = FT_Err_Ok;
413
414    WOFF_HeaderRec  woff;
415    WOFF_Table      tables  = NULL;
416    WOFF_Table*     indices = NULL;
417
418    FT_ULong        woff_offset;
419
420    FT_Byte*        sfnt        = NULL;
421    FT_Stream       sfnt_stream = NULL;
422
423    FT_Byte*        sfnt_header;
424    FT_ULong        sfnt_offset;
425
426    FT_Int          nn;
427    FT_ULong        old_tag = 0;
428
429    static const FT_Frame_Field  woff_header_fields[] =
430    {
431#undef  FT_STRUCTURE
432#define FT_STRUCTURE  WOFF_HeaderRec
433
434      FT_FRAME_START( 44 ),
435        FT_FRAME_ULONG ( signature ),
436        FT_FRAME_ULONG ( flavor ),
437        FT_FRAME_ULONG ( length ),
438        FT_FRAME_USHORT( num_tables ),
439        FT_FRAME_USHORT( reserved ),
440        FT_FRAME_ULONG ( totalSfntSize ),
441        FT_FRAME_USHORT( majorVersion ),
442        FT_FRAME_USHORT( minorVersion ),
443        FT_FRAME_ULONG ( metaOffset ),
444        FT_FRAME_ULONG ( metaLength ),
445        FT_FRAME_ULONG ( metaOrigLength ),
446        FT_FRAME_ULONG ( privOffset ),
447        FT_FRAME_ULONG ( privLength ),
448      FT_FRAME_END
449    };
450
451
452    FT_ASSERT( stream == face->root.stream );
453    FT_ASSERT( FT_STREAM_POS() == 0 );
454
455    if ( FT_STREAM_READ_FIELDS( woff_header_fields, &woff ) )
456      return error;
457
458    /* Make sure we don't recurse back here or hit TTC code. */
459    if ( woff.flavor == TTAG_wOFF || woff.flavor == TTAG_ttcf )
460      return FT_THROW( Invalid_Table );
461
462    /* Miscellaneous checks. */
463    if ( woff.length != stream->size                              ||
464         woff.num_tables == 0                                     ||
465         44 + woff.num_tables * 20UL >= woff.length               ||
466         12 + woff.num_tables * 16UL >= woff.totalSfntSize        ||
467         ( woff.totalSfntSize & 3 ) != 0                          ||
468         ( woff.metaOffset == 0 && ( woff.metaLength != 0     ||
469                                     woff.metaOrigLength != 0 ) ) ||
470         ( woff.metaLength != 0 && woff.metaOrigLength == 0 )     ||
471         ( woff.privOffset == 0 && woff.privLength != 0 )         )
472      return FT_THROW( Invalid_Table );
473
474    if ( FT_ALLOC( sfnt, woff.totalSfntSize ) ||
475         FT_NEW( sfnt_stream )                )
476      goto Exit;
477
478    sfnt_header = sfnt;
479
480    /* Write sfnt header. */
481    {
482      FT_UInt  searchRange, entrySelector, rangeShift, x;
483
484
485      x             = woff.num_tables;
486      entrySelector = 0;
487      while ( x )
488      {
489        x            >>= 1;
490        entrySelector += 1;
491      }
492      entrySelector--;
493
494      searchRange = ( 1 << entrySelector ) * 16;
495      rangeShift  = woff.num_tables * 16 - searchRange;
496
497      WRITE_ULONG ( sfnt_header, woff.flavor );
498      WRITE_USHORT( sfnt_header, woff.num_tables );
499      WRITE_USHORT( sfnt_header, searchRange );
500      WRITE_USHORT( sfnt_header, entrySelector );
501      WRITE_USHORT( sfnt_header, rangeShift );
502    }
503
504    /* While the entries in the sfnt header must be sorted by the */
505    /* tag value, the tables themselves are not.  We thus have to */
506    /* sort them by offset and check that they don't overlap.     */
507
508    if ( FT_NEW_ARRAY( tables, woff.num_tables )  ||
509         FT_NEW_ARRAY( indices, woff.num_tables ) )
510      goto Exit;
511
512    FT_TRACE2(( "\n"
513                "  tag    offset    compLen  origLen  checksum\n"
514                "  -------------------------------------------\n" ));
515
516    if ( FT_FRAME_ENTER( 20L * woff.num_tables ) )
517      goto Exit;
518
519    for ( nn = 0; nn < woff.num_tables; nn++ )
520    {
521      WOFF_Table  table = tables + nn;
522
523      table->Tag        = FT_GET_TAG4();
524      table->Offset     = FT_GET_ULONG();
525      table->CompLength = FT_GET_ULONG();
526      table->OrigLength = FT_GET_ULONG();
527      table->CheckSum   = FT_GET_ULONG();
528
529      FT_TRACE2(( "  %c%c%c%c  %08lx  %08lx  %08lx  %08lx\n",
530                  (FT_Char)( table->Tag >> 24 ),
531                  (FT_Char)( table->Tag >> 16 ),
532                  (FT_Char)( table->Tag >> 8  ),
533                  (FT_Char)( table->Tag       ),
534                  table->Offset,
535                  table->CompLength,
536                  table->OrigLength,
537                  table->CheckSum ));
538
539      if ( table->Tag <= old_tag )
540      {
541        FT_FRAME_EXIT();
542        error = FT_THROW( Invalid_Table );
543        goto Exit;
544      }
545
546      old_tag     = table->Tag;
547      indices[nn] = table;
548    }
549
550    FT_FRAME_EXIT();
551
552    /* Sort by offset. */
553
554    ft_qsort( indices,
555              woff.num_tables,
556              sizeof ( WOFF_Table ),
557              compare_offsets );
558
559    /* Check offsets and lengths. */
560
561    woff_offset = 44 + woff.num_tables * 20L;
562    sfnt_offset = 12 + woff.num_tables * 16L;
563
564    for ( nn = 0; nn < woff.num_tables; nn++ )
565    {
566      WOFF_Table  table = indices[nn];
567
568
569      if ( table->Offset != woff_offset                         ||
570           table->CompLength > woff.length                      ||
571           table->Offset > woff.length - table->CompLength      ||
572           table->OrigLength > woff.totalSfntSize               ||
573           sfnt_offset > woff.totalSfntSize - table->OrigLength ||
574           table->CompLength > table->OrigLength                )
575      {
576        error = FT_THROW( Invalid_Table );
577        goto Exit;
578      }
579
580      table->OrigOffset = sfnt_offset;
581
582      /* The offsets must be multiples of 4. */
583      woff_offset += ( table->CompLength + 3 ) & ~3;
584      sfnt_offset += ( table->OrigLength + 3 ) & ~3;
585    }
586
587    /*
588     * Final checks!
589     *
590     * We don't decode and check the metadata block.
591     * We don't check table checksums either.
592     * But other than those, I think we implement all
593     * `MUST' checks from the spec.
594     */
595
596    if ( woff.metaOffset )
597    {
598      if ( woff.metaOffset != woff_offset                  ||
599           woff.metaOffset + woff.metaLength > woff.length )
600      {
601        error = FT_THROW( Invalid_Table );
602        goto Exit;
603      }
604
605      /* We have padding only ... */
606      woff_offset += woff.metaLength;
607    }
608
609    if ( woff.privOffset )
610    {
611      /* ... if it isn't the last block. */
612      woff_offset = ( woff_offset + 3 ) & ~3;
613
614      if ( woff.privOffset != woff_offset                  ||
615           woff.privOffset + woff.privLength > woff.length )
616      {
617        error = FT_THROW( Invalid_Table );
618        goto Exit;
619      }
620
621      /* No padding for the last block. */
622      woff_offset += woff.privLength;
623    }
624
625    if ( sfnt_offset != woff.totalSfntSize ||
626         woff_offset != woff.length        )
627    {
628      error = FT_THROW( Invalid_Table );
629      goto Exit;
630    }
631
632    /* Write the tables. */
633
634    for ( nn = 0; nn < woff.num_tables; nn++ )
635    {
636      WOFF_Table  table = tables + nn;
637
638
639      /* Write SFNT table entry. */
640      WRITE_ULONG( sfnt_header, table->Tag );
641      WRITE_ULONG( sfnt_header, table->CheckSum );
642      WRITE_ULONG( sfnt_header, table->OrigOffset );
643      WRITE_ULONG( sfnt_header, table->OrigLength );
644
645      /* Write table data. */
646      if ( FT_STREAM_SEEK( table->Offset )     ||
647           FT_FRAME_ENTER( table->CompLength ) )
648        goto Exit;
649
650      if ( table->CompLength == table->OrigLength )
651      {
652        /* Uncompressed data; just copy. */
653        ft_memcpy( sfnt + table->OrigOffset,
654                   stream->cursor,
655                   table->OrigLength );
656      }
657      else
658      {
659#ifdef FT_CONFIG_OPTION_USE_ZLIB
660
661        /* Uncompress with zlib. */
662        FT_ULong  output_len = table->OrigLength;
663
664
665        error = FT_Gzip_Uncompress( memory,
666                                    sfnt + table->OrigOffset, &output_len,
667                                    stream->cursor, table->CompLength );
668        if ( error )
669          goto Exit;
670        if ( output_len != table->OrigLength )
671        {
672          error = FT_THROW( Invalid_Table );
673          goto Exit;
674        }
675
676#else /* !FT_CONFIG_OPTION_USE_ZLIB */
677
678        error = FT_THROW( Unimplemented_Feature );
679        goto Exit;
680
681#endif /* !FT_CONFIG_OPTION_USE_ZLIB */
682      }
683
684      FT_FRAME_EXIT();
685
686      /* We don't check whether the padding bytes in the WOFF file are     */
687      /* actually '\0'.  For the output, however, we do set them properly. */
688      sfnt_offset = table->OrigOffset + table->OrigLength;
689      while ( sfnt_offset & 3 )
690      {
691        sfnt[sfnt_offset] = '\0';
692        sfnt_offset++;
693      }
694    }
695
696    /* Ok!  Finally ready.  Swap out stream and return. */
697    FT_Stream_OpenMemory( sfnt_stream, sfnt, woff.totalSfntSize );
698    sfnt_stream->memory = stream->memory;
699    sfnt_stream->close  = sfnt_stream_close;
700
701    FT_Stream_Free(
702      face->root.stream,
703      ( face->root.face_flags & FT_FACE_FLAG_EXTERNAL_STREAM ) != 0 );
704
705    face->root.stream = sfnt_stream;
706
707    face->root.face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM;
708
709  Exit:
710    FT_FREE( tables );
711    FT_FREE( indices );
712
713    if ( error )
714    {
715      FT_FREE( sfnt );
716      FT_Stream_Close( sfnt_stream );
717      FT_FREE( sfnt_stream );
718    }
719
720    return error;
721  }
722
723
724#undef WRITE_USHORT
725#undef WRITE_ULONG
726
727
728  /* Fill in face->ttc_header.  If the font is not a TTC, it is */
729  /* synthesized into a TTC with one offset table.              */
730  static FT_Error
731  sfnt_open_font( FT_Stream  stream,
732                  TT_Face    face )
733  {
734    FT_Memory  memory = stream->memory;
735    FT_Error   error;
736    FT_ULong   tag, offset;
737
738    static const FT_Frame_Field  ttc_header_fields[] =
739    {
740#undef  FT_STRUCTURE
741#define FT_STRUCTURE  TTC_HeaderRec
742
743      FT_FRAME_START( 8 ),
744        FT_FRAME_LONG( version ),
745        FT_FRAME_LONG( count   ),  /* this is ULong in the specs */
746      FT_FRAME_END
747    };
748
749
750    face->ttc_header.tag     = 0;
751    face->ttc_header.version = 0;
752    face->ttc_header.count   = 0;
753
754  retry:
755    offset = FT_STREAM_POS();
756
757    if ( FT_READ_ULONG( tag ) )
758      return error;
759
760    if ( tag == TTAG_wOFF )
761    {
762      FT_TRACE2(( "sfnt_open_font: file is a WOFF; synthesizing SFNT\n" ));
763
764      if ( FT_STREAM_SEEK( offset ) )
765        return error;
766
767      error = woff_open_font( stream, face );
768      if ( error )
769        return error;
770
771      /* Swap out stream and retry! */
772      stream = face->root.stream;
773      goto retry;
774    }
775
776    if ( tag != 0x00010000UL &&
777         tag != TTAG_ttcf    &&
778         tag != TTAG_OTTO    &&
779         tag != TTAG_true    &&
780         tag != TTAG_typ1    &&
781         tag != 0x00020000UL )
782    {
783      FT_TRACE2(( "  not a font using the SFNT container format\n" ));
784      return FT_THROW( Unknown_File_Format );
785    }
786
787    face->ttc_header.tag = TTAG_ttcf;
788
789    if ( tag == TTAG_ttcf )
790    {
791      FT_Int  n;
792
793
794      FT_TRACE3(( "sfnt_open_font: file is a collection\n" ));
795
796      if ( FT_STREAM_READ_FIELDS( ttc_header_fields, &face->ttc_header ) )
797        return error;
798
799      if ( face->ttc_header.count == 0 )
800        return FT_THROW( Invalid_Table );
801
802      /* a rough size estimate: let's conservatively assume that there   */
803      /* is just a single table info in each subfont header (12 + 16*1 = */
804      /* 28 bytes), thus we have (at least) `12 + 4*count' bytes for the */
805      /* size of the TTC header plus `28*count' bytes for all subfont    */
806      /* headers                                                         */
807      if ( (FT_ULong)face->ttc_header.count > stream->size / ( 28 + 4 ) )
808        return FT_THROW( Array_Too_Large );
809
810      /* now read the offsets of each font in the file */
811      if ( FT_NEW_ARRAY( face->ttc_header.offsets, face->ttc_header.count ) )
812        return error;
813
814      if ( FT_FRAME_ENTER( face->ttc_header.count * 4L ) )
815        return error;
816
817      for ( n = 0; n < face->ttc_header.count; n++ )
818        face->ttc_header.offsets[n] = FT_GET_ULONG();
819
820      FT_FRAME_EXIT();
821    }
822    else
823    {
824      FT_TRACE3(( "sfnt_open_font: synthesize TTC\n" ));
825
826      face->ttc_header.version = 1 << 16;
827      face->ttc_header.count   = 1;
828
829      if ( FT_NEW( face->ttc_header.offsets ) )
830        return error;
831
832      face->ttc_header.offsets[0] = offset;
833    }
834
835    return error;
836  }
837
838
839  FT_LOCAL_DEF( FT_Error )
840  sfnt_init_face( FT_Stream      stream,
841                  TT_Face        face,
842                  FT_Int         face_index,
843                  FT_Int         num_params,
844                  FT_Parameter*  params )
845  {
846    FT_Error        error;
847    FT_Library      library = face->root.driver->root.library;
848    SFNT_Service    sfnt;
849
850
851    /* for now, parameters are unused */
852    FT_UNUSED( num_params );
853    FT_UNUSED( params );
854
855
856    sfnt = (SFNT_Service)face->sfnt;
857    if ( !sfnt )
858    {
859      sfnt = (SFNT_Service)FT_Get_Module_Interface( library, "sfnt" );
860      if ( !sfnt )
861      {
862        FT_ERROR(( "sfnt_init_face: cannot access `sfnt' module\n" ));
863        return FT_THROW( Missing_Module );
864      }
865
866      face->sfnt       = sfnt;
867      face->goto_table = sfnt->goto_table;
868    }
869
870    FT_FACE_FIND_GLOBAL_SERVICE( face, face->psnames, POSTSCRIPT_CMAPS );
871
872    FT_TRACE2(( "SFNT driver\n" ));
873
874    error = sfnt_open_font( stream, face );
875    if ( error )
876      return error;
877
878    /* Stream may have changed in sfnt_open_font. */
879    stream = face->root.stream;
880
881    FT_TRACE2(( "sfnt_init_face: %08p, %ld\n", face, face_index ));
882
883    if ( face_index < 0 )
884      face_index = 0;
885
886    if ( face_index >= face->ttc_header.count )
887      return FT_THROW( Invalid_Argument );
888
889    if ( FT_STREAM_SEEK( face->ttc_header.offsets[face_index] ) )
890      return error;
891
892    /* check that we have a valid TrueType file */
893    error = sfnt->load_font_dir( face, stream );
894    if ( error )
895      return error;
896
897    face->root.num_faces  = face->ttc_header.count;
898    face->root.face_index = face_index;
899
900    return error;
901  }
902
903
904#define LOAD_( x )                                          \
905  do                                                        \
906  {                                                         \
907    FT_TRACE2(( "`" #x "' " ));                             \
908    FT_TRACE3(( "-->\n" ));                                 \
909                                                            \
910    error = sfnt->load_ ## x( face, stream );               \
911                                                            \
912    FT_TRACE2(( "%s\n", ( !error )                          \
913                        ? "loaded"                          \
914                        : FT_ERR_EQ( error, Table_Missing ) \
915                          ? "missing"                       \
916                          : "failed to load" ));            \
917    FT_TRACE3(( "\n" ));                                    \
918  } while ( 0 )
919
920#define LOADM_( x, vertical )                               \
921  do                                                        \
922  {                                                         \
923    FT_TRACE2(( "`%s" #x "' ",                              \
924                vertical ? "vertical " : "" ));             \
925    FT_TRACE3(( "-->\n" ));                                 \
926                                                            \
927    error = sfnt->load_ ## x( face, stream, vertical );     \
928                                                            \
929    FT_TRACE2(( "%s\n", ( !error )                          \
930                        ? "loaded"                          \
931                        : FT_ERR_EQ( error, Table_Missing ) \
932                          ? "missing"                       \
933                          : "failed to load" ));            \
934    FT_TRACE3(( "\n" ));                                    \
935  } while ( 0 )
936
937#define GET_NAME( id, field )                                   \
938  do                                                            \
939  {                                                             \
940    error = tt_face_get_name( face, TT_NAME_ID_ ## id, field ); \
941    if ( error )                                                \
942      goto Exit;                                                \
943  } while ( 0 )
944
945
946  FT_LOCAL_DEF( FT_Error )
947  sfnt_load_face( FT_Stream      stream,
948                  TT_Face        face,
949                  FT_Int         face_index,
950                  FT_Int         num_params,
951                  FT_Parameter*  params )
952  {
953    FT_Error      error;
954#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
955    FT_Error      psnames_error;
956#endif
957    FT_Bool       has_outline;
958    FT_Bool       is_apple_sbit;
959    FT_Bool       is_apple_sbix;
960    FT_Bool       ignore_preferred_family    = FALSE;
961    FT_Bool       ignore_preferred_subfamily = FALSE;
962
963    SFNT_Service  sfnt = (SFNT_Service)face->sfnt;
964
965    FT_UNUSED( face_index );
966
967
968    /* Check parameters */
969
970    {
971      FT_Int  i;
972
973
974      for ( i = 0; i < num_params; i++ )
975      {
976        if ( params[i].tag == FT_PARAM_TAG_IGNORE_PREFERRED_FAMILY )
977          ignore_preferred_family = TRUE;
978        else if ( params[i].tag == FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY )
979          ignore_preferred_subfamily = TRUE;
980      }
981    }
982
983    /* Load tables */
984
985    /* We now support two SFNT-based bitmapped font formats.  They */
986    /* are recognized easily as they do not include a `glyf'       */
987    /* table.                                                      */
988    /*                                                             */
989    /* The first format comes from Apple, and uses a table named   */
990    /* `bhed' instead of `head' to store the font header (using    */
991    /* the same format).  It also doesn't include horizontal and   */
992    /* vertical metrics tables (i.e. `hhea' and `vhea' tables are  */
993    /* missing).                                                   */
994    /*                                                             */
995    /* The other format comes from Microsoft, and is used with     */
996    /* WinCE/PocketPC.  It looks like a standard TTF, except that  */
997    /* it doesn't contain outlines.                                */
998    /*                                                             */
999
1000    FT_TRACE2(( "sfnt_load_face: %08p\n\n", face ));
1001
1002    /* do we have outlines in there? */
1003#ifdef FT_CONFIG_OPTION_INCREMENTAL
1004    has_outline = FT_BOOL( face->root.internal->incremental_interface != 0 ||
1005                           tt_face_lookup_table( face, TTAG_glyf )    != 0 ||
1006                           tt_face_lookup_table( face, TTAG_CFF )     != 0 );
1007#else
1008    has_outline = FT_BOOL( tt_face_lookup_table( face, TTAG_glyf ) != 0 ||
1009                           tt_face_lookup_table( face, TTAG_CFF )  != 0 );
1010#endif
1011
1012    is_apple_sbit = 0;
1013    is_apple_sbix = !face->goto_table( face, TTAG_sbix, stream, 0 );
1014
1015    /* Apple 'sbix' color bitmaps are rendered scaled and then the 'glyf'
1016     * outline rendered on top.  We don't support that yet, so just ignore
1017     * the 'glyf' outline and advertise it as a bitmap-only font. */
1018    if ( is_apple_sbix )
1019      has_outline = FALSE;
1020
1021    /* if this font doesn't contain outlines, we try to load */
1022    /* a `bhed' table                                        */
1023    if ( !has_outline && sfnt->load_bhed )
1024    {
1025      LOAD_( bhed );
1026      is_apple_sbit = FT_BOOL( !error );
1027    }
1028
1029    /* load the font header (`head' table) if this isn't an Apple */
1030    /* sbit font file                                             */
1031    if ( !is_apple_sbit || is_apple_sbix )
1032    {
1033      LOAD_( head );
1034      if ( error )
1035        goto Exit;
1036    }
1037
1038    if ( face->header.Units_Per_EM == 0 )
1039    {
1040      error = FT_THROW( Invalid_Table );
1041
1042      goto Exit;
1043    }
1044
1045    /* the following tables are often not present in embedded TrueType */
1046    /* fonts within PDF documents, so don't check for them.            */
1047    LOAD_( maxp );
1048    LOAD_( cmap );
1049
1050    /* the following tables are optional in PCL fonts -- */
1051    /* don't check for errors                            */
1052    LOAD_( name );
1053    LOAD_( post );
1054
1055#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
1056    psnames_error = error;
1057#endif
1058
1059    /* do not load the metrics headers and tables if this is an Apple */
1060    /* sbit font file                                                 */
1061    if ( !is_apple_sbit )
1062    {
1063      /* load the `hhea' and `hmtx' tables */
1064      LOADM_( hhea, 0 );
1065      if ( !error )
1066      {
1067        LOADM_( hmtx, 0 );
1068        if ( FT_ERR_EQ( error, Table_Missing ) )
1069        {
1070          error = FT_THROW( Hmtx_Table_Missing );
1071
1072#ifdef FT_CONFIG_OPTION_INCREMENTAL
1073          /* If this is an incrementally loaded font and there are */
1074          /* overriding metrics, tolerate a missing `hmtx' table.  */
1075          if ( face->root.internal->incremental_interface          &&
1076               face->root.internal->incremental_interface->funcs->
1077                 get_glyph_metrics                                 )
1078          {
1079            face->horizontal.number_Of_HMetrics = 0;
1080            error                               = FT_Err_Ok;
1081          }
1082#endif
1083        }
1084      }
1085      else if ( FT_ERR_EQ( error, Table_Missing ) )
1086      {
1087        /* No `hhea' table necessary for SFNT Mac fonts. */
1088        if ( face->format_tag == TTAG_true )
1089        {
1090          FT_TRACE2(( "This is an SFNT Mac font.\n" ));
1091
1092          has_outline = 0;
1093          error       = FT_Err_Ok;
1094        }
1095        else
1096        {
1097          error = FT_THROW( Horiz_Header_Missing );
1098
1099#ifdef FT_CONFIG_OPTION_INCREMENTAL
1100          /* If this is an incrementally loaded font and there are */
1101          /* overriding metrics, tolerate a missing `hhea' table.  */
1102          if ( face->root.internal->incremental_interface          &&
1103               face->root.internal->incremental_interface->funcs->
1104                 get_glyph_metrics                                 )
1105          {
1106            face->horizontal.number_Of_HMetrics = 0;
1107            error                               = FT_Err_Ok;
1108          }
1109#endif
1110
1111        }
1112      }
1113
1114      if ( error )
1115        goto Exit;
1116
1117      /* try to load the `vhea' and `vmtx' tables */
1118      LOADM_( hhea, 1 );
1119      if ( !error )
1120      {
1121        LOADM_( hmtx, 1 );
1122        if ( !error )
1123          face->vertical_info = 1;
1124      }
1125
1126      if ( error && FT_ERR_NEQ( error, Table_Missing ) )
1127        goto Exit;
1128
1129      LOAD_( os2 );
1130      if ( error )
1131      {
1132        /* we treat the table as missing if there are any errors */
1133        face->os2.version = 0xFFFFU;
1134      }
1135    }
1136
1137    /* the optional tables */
1138
1139    /* embedded bitmap support */
1140    if ( sfnt->load_eblc )
1141    {
1142      LOAD_( eblc );
1143      if ( error )
1144      {
1145        /* a font which contains neither bitmaps nor outlines is */
1146        /* still valid (although rather useless in most cases);  */
1147        /* however, you can find such stripped fonts in PDFs     */
1148        if ( FT_ERR_EQ( error, Table_Missing ) )
1149          error = FT_Err_Ok;
1150        else
1151          goto Exit;
1152      }
1153    }
1154
1155    LOAD_( pclt );
1156    if ( error )
1157    {
1158      if ( FT_ERR_NEQ( error, Table_Missing ) )
1159        goto Exit;
1160
1161      face->pclt.Version = 0;
1162    }
1163
1164    /* consider the kerning and gasp tables as optional */
1165    LOAD_( gasp );
1166    LOAD_( kern );
1167
1168    face->root.num_glyphs = face->max_profile.numGlyphs;
1169
1170    /* Bit 8 of the `fsSelection' field in the `OS/2' table denotes  */
1171    /* a WWS-only font face.  `WWS' stands for `weight', width', and */
1172    /* `slope', a term used by Microsoft's Windows Presentation      */
1173    /* Foundation (WPF).  This flag has been introduced in version   */
1174    /* 1.5 of the OpenType specification (May 2008).                 */
1175
1176    face->root.family_name = NULL;
1177    face->root.style_name  = NULL;
1178    if ( face->os2.version != 0xFFFFU && face->os2.fsSelection & 256 )
1179    {
1180      if ( !ignore_preferred_family )
1181        GET_NAME( PREFERRED_FAMILY, &face->root.family_name );
1182      if ( !face->root.family_name )
1183        GET_NAME( FONT_FAMILY, &face->root.family_name );
1184
1185      if ( !ignore_preferred_subfamily )
1186        GET_NAME( PREFERRED_SUBFAMILY, &face->root.style_name );
1187      if ( !face->root.style_name )
1188        GET_NAME( FONT_SUBFAMILY, &face->root.style_name );
1189    }
1190    else
1191    {
1192      GET_NAME( WWS_FAMILY, &face->root.family_name );
1193      if ( !face->root.family_name && !ignore_preferred_family )
1194        GET_NAME( PREFERRED_FAMILY, &face->root.family_name );
1195      if ( !face->root.family_name )
1196        GET_NAME( FONT_FAMILY, &face->root.family_name );
1197
1198      GET_NAME( WWS_SUBFAMILY, &face->root.style_name );
1199      if ( !face->root.style_name && !ignore_preferred_subfamily )
1200        GET_NAME( PREFERRED_SUBFAMILY, &face->root.style_name );
1201      if ( !face->root.style_name )
1202        GET_NAME( FONT_SUBFAMILY, &face->root.style_name );
1203    }
1204
1205    /* now set up root fields */
1206    {
1207      FT_Face  root  = &face->root;
1208      FT_Long  flags = root->face_flags;
1209
1210
1211      /*********************************************************************/
1212      /*                                                                   */
1213      /* Compute face flags.                                               */
1214      /*                                                                   */
1215      if ( face->sbit_table_type == TT_SBIT_TABLE_TYPE_CBLC ||
1216           face->sbit_table_type == TT_SBIT_TABLE_TYPE_SBIX )
1217        flags |= FT_FACE_FLAG_COLOR;      /* color glyphs */
1218
1219      if ( has_outline == TRUE )
1220        flags |= FT_FACE_FLAG_SCALABLE;   /* scalable outlines */
1221
1222      /* The sfnt driver only supports bitmap fonts natively, thus we */
1223      /* don't set FT_FACE_FLAG_HINTER.                               */
1224      flags |= FT_FACE_FLAG_SFNT       |  /* SFNT file format  */
1225               FT_FACE_FLAG_HORIZONTAL;   /* horizontal data   */
1226
1227#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
1228      if ( !psnames_error                             &&
1229           face->postscript.FormatType != 0x00030000L )
1230        flags |= FT_FACE_FLAG_GLYPH_NAMES;
1231#endif
1232
1233      /* fixed width font? */
1234      if ( face->postscript.isFixedPitch )
1235        flags |= FT_FACE_FLAG_FIXED_WIDTH;
1236
1237      /* vertical information? */
1238      if ( face->vertical_info )
1239        flags |= FT_FACE_FLAG_VERTICAL;
1240
1241      /* kerning available ? */
1242      if ( TT_FACE_HAS_KERNING( face ) )
1243        flags |= FT_FACE_FLAG_KERNING;
1244
1245#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
1246      /* Don't bother to load the tables unless somebody asks for them. */
1247      /* No need to do work which will (probably) not be used.          */
1248      if ( tt_face_lookup_table( face, TTAG_glyf ) != 0 &&
1249           tt_face_lookup_table( face, TTAG_fvar ) != 0 &&
1250           tt_face_lookup_table( face, TTAG_gvar ) != 0 )
1251        flags |= FT_FACE_FLAG_MULTIPLE_MASTERS;
1252#endif
1253
1254      root->face_flags = flags;
1255
1256      /*********************************************************************/
1257      /*                                                                   */
1258      /* Compute style flags.                                              */
1259      /*                                                                   */
1260
1261      flags = 0;
1262      if ( has_outline == TRUE && face->os2.version != 0xFFFFU )
1263      {
1264        /* We have an OS/2 table; use the `fsSelection' field.  Bit 9 */
1265        /* indicates an oblique font face.  This flag has been        */
1266        /* introduced in version 1.5 of the OpenType specification.   */
1267
1268        if ( face->os2.fsSelection & 512 )       /* bit 9 */
1269          flags |= FT_STYLE_FLAG_ITALIC;
1270        else if ( face->os2.fsSelection & 1 )    /* bit 0 */
1271          flags |= FT_STYLE_FLAG_ITALIC;
1272
1273        if ( face->os2.fsSelection & 32 )        /* bit 5 */
1274          flags |= FT_STYLE_FLAG_BOLD;
1275      }
1276      else
1277      {
1278        /* this is an old Mac font, use the header field */
1279
1280        if ( face->header.Mac_Style & 1 )
1281          flags |= FT_STYLE_FLAG_BOLD;
1282
1283        if ( face->header.Mac_Style & 2 )
1284          flags |= FT_STYLE_FLAG_ITALIC;
1285      }
1286
1287      root->style_flags = flags;
1288
1289      /*********************************************************************/
1290      /*                                                                   */
1291      /* Polish the charmaps.                                              */
1292      /*                                                                   */
1293      /*   Try to set the charmap encoding according to the platform &     */
1294      /*   encoding ID of each charmap.                                    */
1295      /*                                                                   */
1296
1297      tt_face_build_cmaps( face );  /* ignore errors */
1298
1299
1300      /* set the encoding fields */
1301      {
1302        FT_Int  m;
1303
1304
1305        for ( m = 0; m < root->num_charmaps; m++ )
1306        {
1307          FT_CharMap  charmap = root->charmaps[m];
1308
1309
1310          charmap->encoding = sfnt_find_encoding( charmap->platform_id,
1311                                                  charmap->encoding_id );
1312
1313#if 0
1314          if ( root->charmap     == NULL &&
1315               charmap->encoding == FT_ENCODING_UNICODE )
1316          {
1317            /* set 'root->charmap' to the first Unicode encoding we find */
1318            root->charmap = charmap;
1319          }
1320#endif
1321        }
1322      }
1323
1324#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
1325
1326      /*
1327       *  Now allocate the root array of FT_Bitmap_Size records and
1328       *  populate them.  Unfortunately, it isn't possible to indicate bit
1329       *  depths in the FT_Bitmap_Size record.  This is a design error.
1330       */
1331      {
1332        FT_UInt  i, count;
1333
1334
1335        count = face->sbit_num_strikes;
1336
1337        if ( count > 0 )
1338        {
1339          FT_Memory        memory   = face->root.stream->memory;
1340          FT_UShort        em_size  = face->header.Units_Per_EM;
1341          FT_Short         avgwidth = face->os2.xAvgCharWidth;
1342          FT_Size_Metrics  metrics;
1343
1344
1345          if ( em_size == 0 || face->os2.version == 0xFFFFU )
1346          {
1347            avgwidth = 1;
1348            em_size = 1;
1349          }
1350
1351          if ( FT_NEW_ARRAY( root->available_sizes, count ) )
1352            goto Exit;
1353
1354          for ( i = 0; i < count; i++ )
1355          {
1356            FT_Bitmap_Size*  bsize = root->available_sizes + i;
1357
1358
1359            error = sfnt->load_strike_metrics( face, i, &metrics );
1360            if ( error )
1361              goto Exit;
1362
1363            bsize->height = (FT_Short)( metrics.height >> 6 );
1364            bsize->width = (FT_Short)(
1365                ( avgwidth * metrics.x_ppem + em_size / 2 ) / em_size );
1366
1367            bsize->x_ppem = metrics.x_ppem << 6;
1368            bsize->y_ppem = metrics.y_ppem << 6;
1369
1370            /* assume 72dpi */
1371            bsize->size   = metrics.y_ppem << 6;
1372          }
1373
1374          root->face_flags     |= FT_FACE_FLAG_FIXED_SIZES;
1375          root->num_fixed_sizes = (FT_Int)count;
1376        }
1377      }
1378
1379#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
1380
1381      /* a font with no bitmaps and no outlines is scalable; */
1382      /* it has only empty glyphs then                       */
1383      if ( !FT_HAS_FIXED_SIZES( root ) && !FT_IS_SCALABLE( root ) )
1384        root->face_flags |= FT_FACE_FLAG_SCALABLE;
1385
1386
1387      /*********************************************************************/
1388      /*                                                                   */
1389      /*  Set up metrics.                                                  */
1390      /*                                                                   */
1391      if ( FT_IS_SCALABLE( root ) )
1392      {
1393        /* XXX What about if outline header is missing */
1394        /*     (e.g. sfnt wrapped bitmap)?             */
1395        root->bbox.xMin    = face->header.xMin;
1396        root->bbox.yMin    = face->header.yMin;
1397        root->bbox.xMax    = face->header.xMax;
1398        root->bbox.yMax    = face->header.yMax;
1399        root->units_per_EM = face->header.Units_Per_EM;
1400
1401
1402        /* XXX: Computing the ascender/descender/height is very different */
1403        /*      from what the specification tells you.  Apparently, we    */
1404        /*      must be careful because                                   */
1405        /*                                                                */
1406        /*      - not all fonts have an OS/2 table; in this case, we take */
1407        /*        the values in the horizontal header.  However, these    */
1408        /*        values very often are not reliable.                     */
1409        /*                                                                */
1410        /*      - otherwise, the correct typographic values are in the    */
1411        /*        sTypoAscender, sTypoDescender & sTypoLineGap fields.    */
1412        /*                                                                */
1413        /*        However, certain fonts have these fields set to 0.      */
1414        /*        Rather, they have usWinAscent & usWinDescent correctly  */
1415        /*        set (but with different values).                        */
1416        /*                                                                */
1417        /*      As an example, Arial Narrow is implemented through four   */
1418        /*      files ARIALN.TTF, ARIALNI.TTF, ARIALNB.TTF & ARIALNBI.TTF */
1419        /*                                                                */
1420        /*      Strangely, all fonts have the same values in their        */
1421        /*      sTypoXXX fields, except ARIALNB which sets them to 0.     */
1422        /*                                                                */
1423        /*      On the other hand, they all have different                */
1424        /*      usWinAscent/Descent values -- as a conclusion, the OS/2   */
1425        /*      table cannot be used to compute the text height reliably! */
1426        /*                                                                */
1427
1428        /* The ascender and descender are taken from the `hhea' table. */
1429        /* If zero, they are taken from the `OS/2' table.              */
1430
1431        root->ascender  = face->horizontal.Ascender;
1432        root->descender = face->horizontal.Descender;
1433
1434        root->height = (FT_Short)( root->ascender - root->descender +
1435                                   face->horizontal.Line_Gap );
1436
1437        if ( !( root->ascender || root->descender ) )
1438        {
1439          if ( face->os2.version != 0xFFFFU )
1440          {
1441            if ( face->os2.sTypoAscender || face->os2.sTypoDescender )
1442            {
1443              root->ascender  = face->os2.sTypoAscender;
1444              root->descender = face->os2.sTypoDescender;
1445
1446              root->height = (FT_Short)( root->ascender - root->descender +
1447                                         face->os2.sTypoLineGap );
1448            }
1449            else
1450            {
1451              root->ascender  =  (FT_Short)face->os2.usWinAscent;
1452              root->descender = -(FT_Short)face->os2.usWinDescent;
1453
1454              root->height = (FT_UShort)( root->ascender - root->descender );
1455            }
1456          }
1457        }
1458
1459        root->max_advance_width  = face->horizontal.advance_Width_Max;
1460        root->max_advance_height = (FT_Short)( face->vertical_info
1461                                     ? face->vertical.advance_Height_Max
1462                                     : root->height );
1463
1464        /* See http://www.microsoft.com/OpenType/OTSpec/post.htm -- */
1465        /* Adjust underline position from top edge to centre of     */
1466        /* stroke to convert TrueType meaning to FreeType meaning.  */
1467        root->underline_position  = face->postscript.underlinePosition -
1468                                    face->postscript.underlineThickness / 2;
1469        root->underline_thickness = face->postscript.underlineThickness;
1470      }
1471
1472    }
1473
1474  Exit:
1475    FT_TRACE2(( "sfnt_load_face: done\n" ));
1476
1477    return error;
1478  }
1479
1480
1481#undef LOAD_
1482#undef LOADM_
1483#undef GET_NAME
1484
1485
1486  FT_LOCAL_DEF( void )
1487  sfnt_done_face( TT_Face  face )
1488  {
1489    FT_Memory     memory;
1490    SFNT_Service  sfnt;
1491
1492
1493    if ( !face )
1494      return;
1495
1496    memory = face->root.memory;
1497    sfnt   = (SFNT_Service)face->sfnt;
1498
1499    if ( sfnt )
1500    {
1501      /* destroy the postscript names table if it is loaded */
1502      if ( sfnt->free_psnames )
1503        sfnt->free_psnames( face );
1504
1505      /* destroy the embedded bitmaps table if it is loaded */
1506      if ( sfnt->free_eblc )
1507        sfnt->free_eblc( face );
1508    }
1509
1510#ifdef TT_CONFIG_OPTION_BDF
1511    /* freeing the embedded BDF properties */
1512    tt_face_free_bdf_props( face );
1513#endif
1514
1515    /* freeing the kerning table */
1516    tt_face_done_kern( face );
1517
1518    /* freeing the collection table */
1519    FT_FREE( face->ttc_header.offsets );
1520    face->ttc_header.count = 0;
1521
1522    /* freeing table directory */
1523    FT_FREE( face->dir_tables );
1524    face->num_tables = 0;
1525
1526    {
1527      FT_Stream  stream = FT_FACE_STREAM( face );
1528
1529
1530      /* simply release the 'cmap' table frame */
1531      FT_FRAME_RELEASE( face->cmap_table );
1532      face->cmap_size = 0;
1533    }
1534
1535    /* freeing the horizontal metrics */
1536    {
1537      FT_Stream  stream = FT_FACE_STREAM( face );
1538
1539
1540      FT_FRAME_RELEASE( face->horz_metrics );
1541      FT_FRAME_RELEASE( face->vert_metrics );
1542      face->horz_metrics_size = 0;
1543      face->vert_metrics_size = 0;
1544    }
1545
1546    /* freeing the vertical ones, if any */
1547    if ( face->vertical_info )
1548    {
1549      FT_FREE( face->vertical.long_metrics  );
1550      FT_FREE( face->vertical.short_metrics );
1551      face->vertical_info = 0;
1552    }
1553
1554    /* freeing the gasp table */
1555    FT_FREE( face->gasp.gaspRanges );
1556    face->gasp.numRanges = 0;
1557
1558    /* freeing the name table */
1559    if ( sfnt )
1560      sfnt->free_name( face );
1561
1562    /* freeing family and style name */
1563    FT_FREE( face->root.family_name );
1564    FT_FREE( face->root.style_name );
1565
1566    /* freeing sbit size table */
1567    FT_FREE( face->root.available_sizes );
1568    face->root.num_fixed_sizes = 0;
1569
1570    FT_FREE( face->postscript_name );
1571
1572    face->sfnt = 0;
1573  }
1574
1575
1576/* END */
1577