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->Offset + table->CompLength > woff.length      ||
571           sfnt_offset + table->OrigLength > woff.totalSfntSize ||
572           table->CompLength > table->OrigLength                )
573      {
574        error = FT_THROW( Invalid_Table );
575        goto Exit;
576      }
577
578      table->OrigOffset = sfnt_offset;
579
580      /* The offsets must be multiples of 4. */
581      woff_offset += ( table->CompLength + 3 ) & ~3;
582      sfnt_offset += ( table->OrigLength + 3 ) & ~3;
583    }
584
585    /*
586     * Final checks!
587     *
588     * We don't decode and check the metadata block.
589     * We don't check table checksums either.
590     * But other than those, I think we implement all
591     * `MUST' checks from the spec.
592     */
593
594    if ( woff.metaOffset )
595    {
596      if ( woff.metaOffset != woff_offset                  ||
597           woff.metaOffset + woff.metaLength > woff.length )
598      {
599        error = FT_THROW( Invalid_Table );
600        goto Exit;
601      }
602
603      /* We have padding only ... */
604      woff_offset += woff.metaLength;
605    }
606
607    if ( woff.privOffset )
608    {
609      /* ... if it isn't the last block. */
610      woff_offset = ( woff_offset + 3 ) & ~3;
611
612      if ( woff.privOffset != woff_offset                  ||
613           woff.privOffset + woff.privLength > woff.length )
614      {
615        error = FT_THROW( Invalid_Table );
616        goto Exit;
617      }
618
619      /* No padding for the last block. */
620      woff_offset += woff.privLength;
621    }
622
623    if ( sfnt_offset != woff.totalSfntSize ||
624         woff_offset != woff.length        )
625    {
626      error = FT_THROW( Invalid_Table );
627      goto Exit;
628    }
629
630    /* Write the tables. */
631
632    for ( nn = 0; nn < woff.num_tables; nn++ )
633    {
634      WOFF_Table  table = tables + nn;
635
636
637      /* Write SFNT table entry. */
638      WRITE_ULONG( sfnt_header, table->Tag );
639      WRITE_ULONG( sfnt_header, table->CheckSum );
640      WRITE_ULONG( sfnt_header, table->OrigOffset );
641      WRITE_ULONG( sfnt_header, table->OrigLength );
642
643      /* Write table data. */
644      if ( FT_STREAM_SEEK( table->Offset )     ||
645           FT_FRAME_ENTER( table->CompLength ) )
646        goto Exit;
647
648      if ( table->CompLength == table->OrigLength )
649      {
650        /* Uncompressed data; just copy. */
651        ft_memcpy( sfnt + table->OrigOffset,
652                   stream->cursor,
653                   table->OrigLength );
654      }
655      else
656      {
657#ifdef FT_CONFIG_OPTION_USE_ZLIB
658
659        /* Uncompress with zlib. */
660        FT_ULong  output_len = table->OrigLength;
661
662
663        error = FT_Gzip_Uncompress( memory,
664                                    sfnt + table->OrigOffset, &output_len,
665                                    stream->cursor, table->CompLength );
666        if ( error )
667          goto Exit;
668        if ( output_len != table->OrigLength )
669        {
670          error = FT_THROW( Invalid_Table );
671          goto Exit;
672        }
673
674#else /* !FT_CONFIG_OPTION_USE_ZLIB */
675
676        error = FT_THROW( Unimplemented_Feature );
677        goto Exit;
678
679#endif /* !FT_CONFIG_OPTION_USE_ZLIB */
680      }
681
682      FT_FRAME_EXIT();
683
684      /* We don't check whether the padding bytes in the WOFF file are     */
685      /* actually '\0'.  For the output, however, we do set them properly. */
686      sfnt_offset = table->OrigOffset + table->OrigLength;
687      while ( sfnt_offset & 3 )
688      {
689        sfnt[sfnt_offset] = '\0';
690        sfnt_offset++;
691      }
692    }
693
694    /* Ok!  Finally ready.  Swap out stream and return. */
695    FT_Stream_OpenMemory( sfnt_stream, sfnt, woff.totalSfntSize );
696    sfnt_stream->memory = stream->memory;
697    sfnt_stream->close  = sfnt_stream_close;
698
699    FT_Stream_Free(
700      face->root.stream,
701      ( face->root.face_flags & FT_FACE_FLAG_EXTERNAL_STREAM ) != 0 );
702
703    face->root.stream = sfnt_stream;
704
705    face->root.face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM;
706
707  Exit:
708    FT_FREE( tables );
709    FT_FREE( indices );
710
711    if ( error )
712    {
713      FT_FREE( sfnt );
714      FT_Stream_Close( sfnt_stream );
715      FT_FREE( sfnt_stream );
716    }
717
718    return error;
719  }
720
721
722#undef WRITE_USHORT
723#undef WRITE_ULONG
724
725
726  /* Fill in face->ttc_header.  If the font is not a TTC, it is */
727  /* synthesized into a TTC with one offset table.              */
728  static FT_Error
729  sfnt_open_font( FT_Stream  stream,
730                  TT_Face    face )
731  {
732    FT_Memory  memory = stream->memory;
733    FT_Error   error;
734    FT_ULong   tag, offset;
735
736    static const FT_Frame_Field  ttc_header_fields[] =
737    {
738#undef  FT_STRUCTURE
739#define FT_STRUCTURE  TTC_HeaderRec
740
741      FT_FRAME_START( 8 ),
742        FT_FRAME_LONG( version ),
743        FT_FRAME_LONG( count   ),  /* this is ULong in the specs */
744      FT_FRAME_END
745    };
746
747
748    face->ttc_header.tag     = 0;
749    face->ttc_header.version = 0;
750    face->ttc_header.count   = 0;
751
752  retry:
753    offset = FT_STREAM_POS();
754
755    if ( FT_READ_ULONG( tag ) )
756      return error;
757
758    if ( tag == TTAG_wOFF )
759    {
760      FT_TRACE2(( "sfnt_open_font: file is a WOFF; synthesizing SFNT\n" ));
761
762      if ( FT_STREAM_SEEK( offset ) )
763        return error;
764
765      error = woff_open_font( stream, face );
766      if ( error )
767        return error;
768
769      /* Swap out stream and retry! */
770      stream = face->root.stream;
771      goto retry;
772    }
773
774    if ( tag != 0x00010000UL &&
775         tag != TTAG_ttcf    &&
776         tag != TTAG_OTTO    &&
777         tag != TTAG_true    &&
778         tag != TTAG_typ1    &&
779         tag != 0x00020000UL )
780    {
781      FT_TRACE2(( "  not a font using the SFNT container format\n" ));
782      return FT_THROW( Unknown_File_Format );
783    }
784
785    face->ttc_header.tag = TTAG_ttcf;
786
787    if ( tag == TTAG_ttcf )
788    {
789      FT_Int  n;
790
791
792      FT_TRACE3(( "sfnt_open_font: file is a collection\n" ));
793
794      if ( FT_STREAM_READ_FIELDS( ttc_header_fields, &face->ttc_header ) )
795        return error;
796
797      if ( face->ttc_header.count == 0 )
798        return FT_THROW( Invalid_Table );
799
800      /* a rough size estimate: let's conservatively assume that there   */
801      /* is just a single table info in each subfont header (12 + 16*1 = */
802      /* 28 bytes), thus we have (at least) `12 + 4*count' bytes for the */
803      /* size of the TTC header plus `28*count' bytes for all subfont    */
804      /* headers                                                         */
805      if ( (FT_ULong)face->ttc_header.count > stream->size / ( 28 + 4 ) )
806        return FT_THROW( Array_Too_Large );
807
808      /* now read the offsets of each font in the file */
809      if ( FT_NEW_ARRAY( face->ttc_header.offsets, face->ttc_header.count ) )
810        return error;
811
812      if ( FT_FRAME_ENTER( face->ttc_header.count * 4L ) )
813        return error;
814
815      for ( n = 0; n < face->ttc_header.count; n++ )
816        face->ttc_header.offsets[n] = FT_GET_ULONG();
817
818      FT_FRAME_EXIT();
819    }
820    else
821    {
822      FT_TRACE3(( "sfnt_open_font: synthesize TTC\n" ));
823
824      face->ttc_header.version = 1 << 16;
825      face->ttc_header.count   = 1;
826
827      if ( FT_NEW( face->ttc_header.offsets ) )
828        return error;
829
830      face->ttc_header.offsets[0] = offset;
831    }
832
833    return error;
834  }
835
836
837  FT_LOCAL_DEF( FT_Error )
838  sfnt_init_face( FT_Stream      stream,
839                  TT_Face        face,
840                  FT_Int         face_index,
841                  FT_Int         num_params,
842                  FT_Parameter*  params )
843  {
844    FT_Error        error;
845    FT_Library      library = face->root.driver->root.library;
846    SFNT_Service    sfnt;
847
848
849    /* for now, parameters are unused */
850    FT_UNUSED( num_params );
851    FT_UNUSED( params );
852
853
854    sfnt = (SFNT_Service)face->sfnt;
855    if ( !sfnt )
856    {
857      sfnt = (SFNT_Service)FT_Get_Module_Interface( library, "sfnt" );
858      if ( !sfnt )
859      {
860        FT_ERROR(( "sfnt_init_face: cannot access `sfnt' module\n" ));
861        return FT_THROW( Missing_Module );
862      }
863
864      face->sfnt       = sfnt;
865      face->goto_table = sfnt->goto_table;
866    }
867
868    FT_FACE_FIND_GLOBAL_SERVICE( face, face->psnames, POSTSCRIPT_CMAPS );
869
870    FT_TRACE2(( "SFNT driver\n" ));
871
872    error = sfnt_open_font( stream, face );
873    if ( error )
874      return error;
875
876    /* Stream may have changed in sfnt_open_font. */
877    stream = face->root.stream;
878
879    FT_TRACE2(( "sfnt_init_face: %08p, %ld\n", face, face_index ));
880
881    if ( face_index < 0 )
882      face_index = 0;
883
884    if ( face_index >= face->ttc_header.count )
885      return FT_THROW( Invalid_Argument );
886
887    if ( FT_STREAM_SEEK( face->ttc_header.offsets[face_index] ) )
888      return error;
889
890    /* check that we have a valid TrueType file */
891    error = sfnt->load_font_dir( face, stream );
892    if ( error )
893      return error;
894
895    face->root.num_faces  = face->ttc_header.count;
896    face->root.face_index = face_index;
897
898    return error;
899  }
900
901
902#define LOAD_( x )                                          \
903  do                                                        \
904  {                                                         \
905    FT_TRACE2(( "`" #x "' " ));                             \
906    FT_TRACE3(( "-->\n" ));                                 \
907                                                            \
908    error = sfnt->load_ ## x( face, stream );               \
909                                                            \
910    FT_TRACE2(( "%s\n", ( !error )                          \
911                        ? "loaded"                          \
912                        : FT_ERR_EQ( error, Table_Missing ) \
913                          ? "missing"                       \
914                          : "failed to load" ));            \
915    FT_TRACE3(( "\n" ));                                    \
916  } while ( 0 )
917
918#define LOADM_( x, vertical )                               \
919  do                                                        \
920  {                                                         \
921    FT_TRACE2(( "`%s" #x "' ",                              \
922                vertical ? "vertical " : "" ));             \
923    FT_TRACE3(( "-->\n" ));                                 \
924                                                            \
925    error = sfnt->load_ ## x( face, stream, vertical );     \
926                                                            \
927    FT_TRACE2(( "%s\n", ( !error )                          \
928                        ? "loaded"                          \
929                        : FT_ERR_EQ( error, Table_Missing ) \
930                          ? "missing"                       \
931                          : "failed to load" ));            \
932    FT_TRACE3(( "\n" ));                                    \
933  } while ( 0 )
934
935#define GET_NAME( id, field )                                   \
936  do                                                            \
937  {                                                             \
938    error = tt_face_get_name( face, TT_NAME_ID_ ## id, field ); \
939    if ( error )                                                \
940      goto Exit;                                                \
941  } while ( 0 )
942
943
944  FT_LOCAL_DEF( FT_Error )
945  sfnt_load_face( FT_Stream      stream,
946                  TT_Face        face,
947                  FT_Int         face_index,
948                  FT_Int         num_params,
949                  FT_Parameter*  params )
950  {
951    FT_Error      error;
952#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
953    FT_Error      psnames_error;
954#endif
955    FT_Bool       has_outline;
956    FT_Bool       is_apple_sbit;
957    FT_Bool       is_apple_sbix;
958    FT_Bool       ignore_preferred_family    = FALSE;
959    FT_Bool       ignore_preferred_subfamily = FALSE;
960
961    SFNT_Service  sfnt = (SFNT_Service)face->sfnt;
962
963    FT_UNUSED( face_index );
964
965
966    /* Check parameters */
967
968    {
969      FT_Int  i;
970
971
972      for ( i = 0; i < num_params; i++ )
973      {
974        if ( params[i].tag == FT_PARAM_TAG_IGNORE_PREFERRED_FAMILY )
975          ignore_preferred_family = TRUE;
976        else if ( params[i].tag == FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY )
977          ignore_preferred_subfamily = TRUE;
978      }
979    }
980
981    /* Load tables */
982
983    /* We now support two SFNT-based bitmapped font formats.  They */
984    /* are recognized easily as they do not include a `glyf'       */
985    /* table.                                                      */
986    /*                                                             */
987    /* The first format comes from Apple, and uses a table named   */
988    /* `bhed' instead of `head' to store the font header (using    */
989    /* the same format).  It also doesn't include horizontal and   */
990    /* vertical metrics tables (i.e. `hhea' and `vhea' tables are  */
991    /* missing).                                                   */
992    /*                                                             */
993    /* The other format comes from Microsoft, and is used with     */
994    /* WinCE/PocketPC.  It looks like a standard TTF, except that  */
995    /* it doesn't contain outlines.                                */
996    /*                                                             */
997
998    FT_TRACE2(( "sfnt_load_face: %08p\n\n", face ));
999
1000    /* do we have outlines in there? */
1001#ifdef FT_CONFIG_OPTION_INCREMENTAL
1002    has_outline = FT_BOOL( face->root.internal->incremental_interface != 0 ||
1003                           tt_face_lookup_table( face, TTAG_glyf )    != 0 ||
1004                           tt_face_lookup_table( face, TTAG_CFF )     != 0 );
1005#else
1006    has_outline = FT_BOOL( tt_face_lookup_table( face, TTAG_glyf ) != 0 ||
1007                           tt_face_lookup_table( face, TTAG_CFF )  != 0 );
1008#endif
1009
1010    is_apple_sbit = 0;
1011    is_apple_sbix = !face->goto_table( face, TTAG_sbix, stream, 0 );
1012
1013    /* Apple 'sbix' color bitmaps are rendered scaled and then the 'glyf'
1014     * outline rendered on top.  We don't support that yet, so just ignore
1015     * the 'glyf' outline and advertise it as a bitmap-only font. */
1016    if ( is_apple_sbix )
1017      has_outline = FALSE;
1018
1019
1020    /* if this font doesn't contain outlines, we try to load */
1021    /* a `bhed' table                                        */
1022    if ( !has_outline && sfnt->load_bhed )
1023    {
1024      LOAD_( bhed );
1025      is_apple_sbit = FT_BOOL( !error );
1026    }
1027
1028    /* load the font header (`head' table) if this isn't an Apple */
1029    /* sbit font file                                             */
1030    if ( !is_apple_sbit || is_apple_sbix )
1031    {
1032      LOAD_( head );
1033      if ( error )
1034        goto Exit;
1035    }
1036
1037    if ( face->header.Units_Per_EM == 0 )
1038    {
1039      error = FT_THROW( Invalid_Table );
1040
1041      goto Exit;
1042    }
1043
1044    /* the following tables are often not present in embedded TrueType */
1045    /* fonts within PDF documents, so don't check for them.            */
1046    LOAD_( maxp );
1047    LOAD_( cmap );
1048
1049    /* the following tables are optional in PCL fonts -- */
1050    /* don't check for errors                            */
1051    LOAD_( name );
1052    LOAD_( post );
1053
1054#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
1055    psnames_error = error;
1056#endif
1057
1058    /* do not load the metrics headers and tables if this is an Apple */
1059    /* sbit font file                                                 */
1060    if ( !is_apple_sbit )
1061    {
1062      /* load the `hhea' and `hmtx' tables */
1063      LOADM_( hhea, 0 );
1064      if ( !error )
1065      {
1066        LOADM_( hmtx, 0 );
1067        if ( FT_ERR_EQ( error, Table_Missing ) )
1068        {
1069          error = FT_THROW( Hmtx_Table_Missing );
1070
1071#ifdef FT_CONFIG_OPTION_INCREMENTAL
1072          /* If this is an incrementally loaded font and there are */
1073          /* overriding metrics, tolerate a missing `hmtx' table.  */
1074          if ( face->root.internal->incremental_interface          &&
1075               face->root.internal->incremental_interface->funcs->
1076                 get_glyph_metrics                                 )
1077          {
1078            face->horizontal.number_Of_HMetrics = 0;
1079            error                               = FT_Err_Ok;
1080          }
1081#endif
1082        }
1083      }
1084      else if ( FT_ERR_EQ( error, Table_Missing ) )
1085      {
1086        /* No `hhea' table necessary for SFNT Mac fonts. */
1087        if ( face->format_tag == TTAG_true )
1088        {
1089          FT_TRACE2(( "This is an SFNT Mac font.\n" ));
1090
1091          has_outline = 0;
1092          error       = FT_Err_Ok;
1093        }
1094        else
1095        {
1096          error = FT_THROW( Horiz_Header_Missing );
1097
1098#ifdef FT_CONFIG_OPTION_INCREMENTAL
1099          /* If this is an incrementally loaded font and there are */
1100          /* overriding metrics, tolerate a missing `hhea' table.  */
1101          if ( face->root.internal->incremental_interface          &&
1102               face->root.internal->incremental_interface->funcs->
1103                 get_glyph_metrics                                 )
1104          {
1105            face->horizontal.number_Of_HMetrics = 0;
1106            error                               = FT_Err_Ok;
1107          }
1108#endif
1109
1110        }
1111      }
1112
1113      if ( error )
1114        goto Exit;
1115
1116      /* try to load the `vhea' and `vmtx' tables */
1117      LOADM_( hhea, 1 );
1118      if ( !error )
1119      {
1120        LOADM_( hmtx, 1 );
1121        if ( !error )
1122          face->vertical_info = 1;
1123      }
1124
1125      if ( error && FT_ERR_NEQ( error, Table_Missing ) )
1126        goto Exit;
1127
1128      LOAD_( os2 );
1129      if ( error )
1130      {
1131        /* we treat the table as missing if there are any errors */
1132        face->os2.version = 0xFFFFU;
1133      }
1134    }
1135
1136    /* the optional tables */
1137
1138    /* embedded bitmap support */
1139    if ( sfnt->load_eblc )
1140    {
1141      LOAD_( eblc );
1142      if ( error )
1143      {
1144        /* a font which contains neither bitmaps nor outlines is */
1145        /* still valid (although rather useless in most cases);  */
1146        /* however, you can find such stripped fonts in PDFs     */
1147        if ( FT_ERR_EQ( error, Table_Missing ) )
1148          error = FT_Err_Ok;
1149        else
1150          goto Exit;
1151      }
1152    }
1153
1154    LOAD_( pclt );
1155    if ( error )
1156    {
1157      if ( FT_ERR_NEQ( error, Table_Missing ) )
1158        goto Exit;
1159
1160      face->pclt.Version = 0;
1161    }
1162
1163    /* consider the kerning and gasp tables as optional */
1164    LOAD_( gasp );
1165    LOAD_( kern );
1166
1167    face->root.num_glyphs = face->max_profile.numGlyphs;
1168
1169    /* Bit 8 of the `fsSelection' field in the `OS/2' table denotes  */
1170    /* a WWS-only font face.  `WWS' stands for `weight', width', and */
1171    /* `slope', a term used by Microsoft's Windows Presentation      */
1172    /* Foundation (WPF).  This flag has been introduced in version   */
1173    /* 1.5 of the OpenType specification (May 2008).                 */
1174
1175    face->root.family_name = NULL;
1176    face->root.style_name  = NULL;
1177    if ( face->os2.version != 0xFFFFU && face->os2.fsSelection & 256 )
1178    {
1179      if ( !ignore_preferred_family )
1180        GET_NAME( PREFERRED_FAMILY, &face->root.family_name );
1181      if ( !face->root.family_name )
1182        GET_NAME( FONT_FAMILY, &face->root.family_name );
1183
1184      if ( !ignore_preferred_subfamily )
1185        GET_NAME( PREFERRED_SUBFAMILY, &face->root.style_name );
1186      if ( !face->root.style_name )
1187        GET_NAME( FONT_SUBFAMILY, &face->root.style_name );
1188    }
1189    else
1190    {
1191      GET_NAME( WWS_FAMILY, &face->root.family_name );
1192      if ( !face->root.family_name && !ignore_preferred_family )
1193        GET_NAME( PREFERRED_FAMILY, &face->root.family_name );
1194      if ( !face->root.family_name )
1195        GET_NAME( FONT_FAMILY, &face->root.family_name );
1196
1197      GET_NAME( WWS_SUBFAMILY, &face->root.style_name );
1198      if ( !face->root.style_name && !ignore_preferred_subfamily )
1199        GET_NAME( PREFERRED_SUBFAMILY, &face->root.style_name );
1200      if ( !face->root.style_name )
1201        GET_NAME( FONT_SUBFAMILY, &face->root.style_name );
1202    }
1203
1204    /* now set up root fields */
1205    {
1206      FT_Face  root  = &face->root;
1207      FT_Long  flags = root->face_flags;
1208
1209
1210      /*********************************************************************/
1211      /*                                                                   */
1212      /* Compute face flags.                                               */
1213      /*                                                                   */
1214      if ( face->sbit_table_type == TT_SBIT_TABLE_TYPE_CBLC ||
1215           face->sbit_table_type == TT_SBIT_TABLE_TYPE_SBIX )
1216        flags |= FT_FACE_FLAG_COLOR;      /* color glyphs */
1217
1218      if ( has_outline == TRUE )
1219        flags |= FT_FACE_FLAG_SCALABLE;   /* scalable outlines */
1220
1221      /* The sfnt driver only supports bitmap fonts natively, thus we */
1222      /* don't set FT_FACE_FLAG_HINTER.                               */
1223      flags |= FT_FACE_FLAG_SFNT       |  /* SFNT file format  */
1224               FT_FACE_FLAG_HORIZONTAL;   /* horizontal data   */
1225
1226#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
1227      if ( !psnames_error                             &&
1228           face->postscript.FormatType != 0x00030000L )
1229        flags |= FT_FACE_FLAG_GLYPH_NAMES;
1230#endif
1231
1232      /* fixed width font? */
1233      if ( face->postscript.isFixedPitch )
1234        flags |= FT_FACE_FLAG_FIXED_WIDTH;
1235
1236      /* vertical information? */
1237      if ( face->vertical_info )
1238        flags |= FT_FACE_FLAG_VERTICAL;
1239
1240      /* kerning available ? */
1241      if ( TT_FACE_HAS_KERNING( face ) )
1242        flags |= FT_FACE_FLAG_KERNING;
1243
1244#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
1245      /* Don't bother to load the tables unless somebody asks for them. */
1246      /* No need to do work which will (probably) not be used.          */
1247      if ( tt_face_lookup_table( face, TTAG_glyf ) != 0 &&
1248           tt_face_lookup_table( face, TTAG_fvar ) != 0 &&
1249           tt_face_lookup_table( face, TTAG_gvar ) != 0 )
1250        flags |= FT_FACE_FLAG_MULTIPLE_MASTERS;
1251#endif
1252
1253      root->face_flags = flags;
1254
1255      /*********************************************************************/
1256      /*                                                                   */
1257      /* Compute style flags.                                              */
1258      /*                                                                   */
1259
1260      flags = 0;
1261      if ( has_outline == TRUE && face->os2.version != 0xFFFFU )
1262      {
1263        /* We have an OS/2 table; use the `fsSelection' field.  Bit 9 */
1264        /* indicates an oblique font face.  This flag has been        */
1265        /* introduced in version 1.5 of the OpenType specification.   */
1266
1267        if ( face->os2.fsSelection & 512 )       /* bit 9 */
1268          flags |= FT_STYLE_FLAG_ITALIC;
1269        else if ( face->os2.fsSelection & 1 )    /* bit 0 */
1270          flags |= FT_STYLE_FLAG_ITALIC;
1271
1272        if ( face->os2.fsSelection & 32 )        /* bit 5 */
1273          flags |= FT_STYLE_FLAG_BOLD;
1274      }
1275      else
1276      {
1277        /* this is an old Mac font, use the header field */
1278
1279        if ( face->header.Mac_Style & 1 )
1280          flags |= FT_STYLE_FLAG_BOLD;
1281
1282        if ( face->header.Mac_Style & 2 )
1283          flags |= FT_STYLE_FLAG_ITALIC;
1284      }
1285
1286      root->style_flags = flags;
1287
1288      /*********************************************************************/
1289      /*                                                                   */
1290      /* Polish the charmaps.                                              */
1291      /*                                                                   */
1292      /*   Try to set the charmap encoding according to the platform &     */
1293      /*   encoding ID of each charmap.                                    */
1294      /*                                                                   */
1295
1296      tt_face_build_cmaps( face );  /* ignore errors */
1297
1298
1299      /* set the encoding fields */
1300      {
1301        FT_Int  m;
1302
1303
1304        for ( m = 0; m < root->num_charmaps; m++ )
1305        {
1306          FT_CharMap  charmap = root->charmaps[m];
1307
1308
1309          charmap->encoding = sfnt_find_encoding( charmap->platform_id,
1310                                                  charmap->encoding_id );
1311
1312#if 0
1313          if ( root->charmap     == NULL &&
1314               charmap->encoding == FT_ENCODING_UNICODE )
1315          {
1316            /* set 'root->charmap' to the first Unicode encoding we find */
1317            root->charmap = charmap;
1318          }
1319#endif
1320        }
1321      }
1322
1323#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
1324
1325      /*
1326       *  Now allocate the root array of FT_Bitmap_Size records and
1327       *  populate them.  Unfortunately, it isn't possible to indicate bit
1328       *  depths in the FT_Bitmap_Size record.  This is a design error.
1329       */
1330      {
1331        FT_UInt  i, count;
1332
1333
1334        count = face->sbit_num_strikes;
1335
1336        if ( count > 0 )
1337        {
1338          FT_Memory        memory   = face->root.stream->memory;
1339          FT_UShort        em_size  = face->header.Units_Per_EM;
1340          FT_Short         avgwidth = face->os2.xAvgCharWidth;
1341          FT_Size_Metrics  metrics;
1342
1343
1344          if ( em_size == 0 || face->os2.version == 0xFFFFU )
1345          {
1346            avgwidth = 1;
1347            em_size = 1;
1348          }
1349
1350          if ( FT_NEW_ARRAY( root->available_sizes, count ) )
1351            goto Exit;
1352
1353          for ( i = 0; i < count; i++ )
1354          {
1355            FT_Bitmap_Size*  bsize = root->available_sizes + i;
1356
1357
1358            error = sfnt->load_strike_metrics( face, i, &metrics );
1359            if ( error )
1360              goto Exit;
1361
1362            bsize->height = (FT_Short)( metrics.height >> 6 );
1363            bsize->width = (FT_Short)(
1364                ( avgwidth * metrics.x_ppem + em_size / 2 ) / em_size );
1365
1366            bsize->x_ppem = metrics.x_ppem << 6;
1367            bsize->y_ppem = metrics.y_ppem << 6;
1368
1369            /* assume 72dpi */
1370            bsize->size   = metrics.y_ppem << 6;
1371          }
1372
1373          root->face_flags     |= FT_FACE_FLAG_FIXED_SIZES;
1374          root->num_fixed_sizes = (FT_Int)count;
1375        }
1376      }
1377
1378#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
1379
1380      /* a font with no bitmaps and no outlines is scalable; */
1381      /* it has only empty glyphs then                       */
1382      if ( !FT_HAS_FIXED_SIZES( root ) && !FT_IS_SCALABLE( root ) )
1383        root->face_flags |= FT_FACE_FLAG_SCALABLE;
1384
1385
1386      /*********************************************************************/
1387      /*                                                                   */
1388      /*  Set up metrics.                                                  */
1389      /*                                                                   */
1390      if ( FT_IS_SCALABLE( root ) )
1391      {
1392        /* XXX What about if outline header is missing */
1393        /*     (e.g. sfnt wrapped bitmap)?             */
1394        root->bbox.xMin    = face->header.xMin;
1395        root->bbox.yMin    = face->header.yMin;
1396        root->bbox.xMax    = face->header.xMax;
1397        root->bbox.yMax    = face->header.yMax;
1398        root->units_per_EM = face->header.Units_Per_EM;
1399
1400
1401        /* XXX: Computing the ascender/descender/height is very different */
1402        /*      from what the specification tells you.  Apparently, we    */
1403        /*      must be careful because                                   */
1404        /*                                                                */
1405        /*      - not all fonts have an OS/2 table; in this case, we take */
1406        /*        the values in the horizontal header.  However, these    */
1407        /*        values very often are not reliable.                     */
1408        /*                                                                */
1409        /*      - otherwise, the correct typographic values are in the    */
1410        /*        sTypoAscender, sTypoDescender & sTypoLineGap fields.    */
1411        /*                                                                */
1412        /*        However, certain fonts have these fields set to 0.      */
1413        /*        Rather, they have usWinAscent & usWinDescent correctly  */
1414        /*        set (but with different values).                        */
1415        /*                                                                */
1416        /*      As an example, Arial Narrow is implemented through four   */
1417        /*      files ARIALN.TTF, ARIALNI.TTF, ARIALNB.TTF & ARIALNBI.TTF */
1418        /*                                                                */
1419        /*      Strangely, all fonts have the same values in their        */
1420        /*      sTypoXXX fields, except ARIALNB which sets them to 0.     */
1421        /*                                                                */
1422        /*      On the other hand, they all have different                */
1423        /*      usWinAscent/Descent values -- as a conclusion, the OS/2   */
1424        /*      table cannot be used to compute the text height reliably! */
1425        /*                                                                */
1426
1427        /* The ascender and descender are taken from the `hhea' table. */
1428        /* If zero, they are taken from the `OS/2' table.              */
1429
1430        root->ascender  = face->horizontal.Ascender;
1431        root->descender = face->horizontal.Descender;
1432
1433        root->height = (FT_Short)( root->ascender - root->descender +
1434                                   face->horizontal.Line_Gap );
1435
1436        if ( !( root->ascender || root->descender ) )
1437        {
1438          if ( face->os2.version != 0xFFFFU )
1439          {
1440            if ( face->os2.sTypoAscender || face->os2.sTypoDescender )
1441            {
1442              root->ascender  = face->os2.sTypoAscender;
1443              root->descender = face->os2.sTypoDescender;
1444
1445              root->height = (FT_Short)( root->ascender - root->descender +
1446                                         face->os2.sTypoLineGap );
1447            }
1448            else
1449            {
1450              root->ascender  =  (FT_Short)face->os2.usWinAscent;
1451              root->descender = -(FT_Short)face->os2.usWinDescent;
1452
1453              root->height = (FT_UShort)( root->ascender - root->descender );
1454            }
1455          }
1456        }
1457
1458        root->max_advance_width  = face->horizontal.advance_Width_Max;
1459        root->max_advance_height = (FT_Short)( face->vertical_info
1460                                     ? face->vertical.advance_Height_Max
1461                                     : root->height );
1462
1463        /* See http://www.microsoft.com/OpenType/OTSpec/post.htm -- */
1464        /* Adjust underline position from top edge to centre of     */
1465        /* stroke to convert TrueType meaning to FreeType meaning.  */
1466        root->underline_position  = face->postscript.underlinePosition -
1467                                    face->postscript.underlineThickness / 2;
1468        root->underline_thickness = face->postscript.underlineThickness;
1469      }
1470
1471    }
1472
1473  Exit:
1474    FT_TRACE2(( "sfnt_load_face: done\n" ));
1475
1476    return error;
1477  }
1478
1479
1480#undef LOAD_
1481#undef LOADM_
1482#undef GET_NAME
1483
1484
1485  FT_LOCAL_DEF( void )
1486  sfnt_done_face( TT_Face  face )
1487  {
1488    FT_Memory     memory;
1489    SFNT_Service  sfnt;
1490
1491
1492    if ( !face )
1493      return;
1494
1495    memory = face->root.memory;
1496    sfnt   = (SFNT_Service)face->sfnt;
1497
1498    if ( sfnt )
1499    {
1500      /* destroy the postscript names table if it is loaded */
1501      if ( sfnt->free_psnames )
1502        sfnt->free_psnames( face );
1503
1504      /* destroy the embedded bitmaps table if it is loaded */
1505      if ( sfnt->free_eblc )
1506        sfnt->free_eblc( face );
1507    }
1508
1509#ifdef TT_CONFIG_OPTION_BDF
1510    /* freeing the embedded BDF properties */
1511    tt_face_free_bdf_props( face );
1512#endif
1513
1514    /* freeing the kerning table */
1515    tt_face_done_kern( face );
1516
1517    /* freeing the collection table */
1518    FT_FREE( face->ttc_header.offsets );
1519    face->ttc_header.count = 0;
1520
1521    /* freeing table directory */
1522    FT_FREE( face->dir_tables );
1523    face->num_tables = 0;
1524
1525    {
1526      FT_Stream  stream = FT_FACE_STREAM( face );
1527
1528
1529      /* simply release the 'cmap' table frame */
1530      FT_FRAME_RELEASE( face->cmap_table );
1531      face->cmap_size = 0;
1532    }
1533
1534    /* freeing the horizontal metrics */
1535    {
1536      FT_Stream  stream = FT_FACE_STREAM( face );
1537
1538
1539      FT_FRAME_RELEASE( face->horz_metrics );
1540      FT_FRAME_RELEASE( face->vert_metrics );
1541      face->horz_metrics_size = 0;
1542      face->vert_metrics_size = 0;
1543    }
1544
1545    /* freeing the vertical ones, if any */
1546    if ( face->vertical_info )
1547    {
1548      FT_FREE( face->vertical.long_metrics  );
1549      FT_FREE( face->vertical.short_metrics );
1550      face->vertical_info = 0;
1551    }
1552
1553    /* freeing the gasp table */
1554    FT_FREE( face->gasp.gaspRanges );
1555    face->gasp.numRanges = 0;
1556
1557    /* freeing the name table */
1558    if ( sfnt )
1559      sfnt->free_name( face );
1560
1561    /* freeing family and style name */
1562    FT_FREE( face->root.family_name );
1563    FT_FREE( face->root.style_name );
1564
1565    /* freeing sbit size table */
1566    FT_FREE( face->root.available_sizes );
1567    face->root.num_fixed_sizes = 0;
1568
1569    FT_FREE( face->postscript_name );
1570
1571    face->sfnt = 0;
1572  }
1573
1574
1575/* END */
1576