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