1/***************************************************************************/
2/*                                                                         */
3/*  sfdriver.c                                                             */
4/*                                                                         */
5/*    High-level SFNT driver interface (body).                             */
6/*                                                                         */
7/*  Copyright 1996-2007, 2009-2013 by                                      */
8/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
9/*                                                                         */
10/*  This file is part of the FreeType project, and may only be used,       */
11/*  modified, and distributed under the terms of the FreeType project      */
12/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
13/*  this file you indicate that you have read the license and              */
14/*  understand and accept it fully.                                        */
15/*                                                                         */
16/***************************************************************************/
17
18
19#include "../../include/ft2build.h"
20#include "../../include/freetype/internal/ftdebug.h"
21#include "../../include/freetype/internal/sfnt.h"
22#include "../../include/freetype/internal/ftobjs.h"
23
24#include "sfdriver.h"
25#include "ttload.h"
26#include "sfobjs.h"
27#include "sfntpic.h"
28
29#include "sferrors.h"
30
31#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
32#include "ttsbit.h"
33#endif
34
35#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
36#include "ttpost.h"
37#endif
38
39#ifdef TT_CONFIG_OPTION_BDF
40#include "ttbdf.h"
41#include "../../include/freetype/internal/services/svbdf.h"
42#endif
43
44#include "ttcmap.h"
45#include "ttkern.h"
46#include "ttmtx.h"
47
48#include "../../include/freetype/internal/services/svgldict.h"
49#include "../../include/freetype/internal/services/svpostnm.h"
50#include "../../include/freetype/internal/services/svsfnt.h"
51#include "../../include/freetype/internal/services/svttcmap.h"
52
53
54  /*************************************************************************/
55  /*                                                                       */
56  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
57  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
58  /* messages during execution.                                            */
59  /*                                                                       */
60#undef  FT_COMPONENT
61#define FT_COMPONENT  trace_sfdriver
62
63
64  /*
65   *  SFNT TABLE SERVICE
66   *
67   */
68
69  static void*
70  get_sfnt_table( TT_Face      face,
71                  FT_Sfnt_Tag  tag )
72  {
73    void*  table;
74
75
76    switch ( tag )
77    {
78    case ft_sfnt_head:
79      table = &face->header;
80      break;
81
82    case ft_sfnt_hhea:
83      table = &face->horizontal;
84      break;
85
86    case ft_sfnt_vhea:
87      table = face->vertical_info ? &face->vertical : 0;
88      break;
89
90    case ft_sfnt_os2:
91      table = face->os2.version == 0xFFFFU ? 0 : &face->os2;
92      break;
93
94    case ft_sfnt_post:
95      table = &face->postscript;
96      break;
97
98    case ft_sfnt_maxp:
99      table = &face->max_profile;
100      break;
101
102    case ft_sfnt_pclt:
103      table = face->pclt.Version ? &face->pclt : 0;
104      break;
105
106    default:
107      table = 0;
108    }
109
110    return table;
111  }
112
113
114  static FT_Error
115  sfnt_table_info( TT_Face    face,
116                   FT_UInt    idx,
117                   FT_ULong  *tag,
118                   FT_ULong  *offset,
119                   FT_ULong  *length )
120  {
121    if ( !offset || !length )
122      return FT_THROW( Invalid_Argument );
123
124    if ( !tag )
125      *length = face->num_tables;
126    else
127    {
128      if ( idx >= face->num_tables )
129        return FT_THROW( Table_Missing );
130
131      *tag    = face->dir_tables[idx].Tag;
132      *offset = face->dir_tables[idx].Offset;
133      *length = face->dir_tables[idx].Length;
134    }
135
136    return FT_Err_Ok;
137  }
138
139
140  FT_DEFINE_SERVICE_SFNT_TABLEREC(
141    sfnt_service_sfnt_table,
142    (FT_SFNT_TableLoadFunc)tt_face_load_any,
143    (FT_SFNT_TableGetFunc) get_sfnt_table,
144    (FT_SFNT_TableInfoFunc)sfnt_table_info )
145
146
147#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
148
149  /*
150   *  GLYPH DICT SERVICE
151   *
152   */
153
154  static FT_Error
155  sfnt_get_glyph_name( TT_Face     face,
156                       FT_UInt     glyph_index,
157                       FT_Pointer  buffer,
158                       FT_UInt     buffer_max )
159  {
160    FT_String*  gname;
161    FT_Error    error;
162
163
164    error = tt_face_get_ps_name( face, glyph_index, &gname );
165    if ( !error )
166      FT_STRCPYN( buffer, gname, buffer_max );
167
168    return error;
169  }
170
171
172  static FT_UInt
173  sfnt_get_name_index( TT_Face     face,
174                       FT_String*  glyph_name )
175  {
176    FT_Face  root = &face->root;
177
178    FT_UInt  i, max_gid = FT_UINT_MAX;
179
180
181    if ( root->num_glyphs < 0 )
182      return 0;
183    else if ( (FT_ULong)root->num_glyphs < FT_UINT_MAX )
184      max_gid = (FT_UInt)root->num_glyphs;
185    else
186      FT_TRACE0(( "Ignore glyph names for invalid GID 0x%08x - 0x%08x\n",
187                  FT_UINT_MAX, root->num_glyphs ));
188
189    for ( i = 0; i < max_gid; i++ )
190    {
191      FT_String*  gname;
192      FT_Error    error = tt_face_get_ps_name( face, i, &gname );
193
194
195      if ( error )
196        continue;
197
198      if ( !ft_strcmp( glyph_name, gname ) )
199        return i;
200    }
201
202    return 0;
203  }
204
205
206  FT_DEFINE_SERVICE_GLYPHDICTREC(
207    sfnt_service_glyph_dict,
208    (FT_GlyphDict_GetNameFunc)  sfnt_get_glyph_name,
209    (FT_GlyphDict_NameIndexFunc)sfnt_get_name_index )
210
211
212#endif /* TT_CONFIG_OPTION_POSTSCRIPT_NAMES */
213
214
215  /*
216   *  POSTSCRIPT NAME SERVICE
217   *
218   */
219
220  static const char*
221  sfnt_get_ps_name( TT_Face  face )
222  {
223    FT_Int       n, found_win, found_apple;
224    const char*  result = NULL;
225
226
227    /* shouldn't happen, but just in case to avoid memory leaks */
228    if ( face->postscript_name )
229      return face->postscript_name;
230
231    /* scan the name table to see whether we have a Postscript name here, */
232    /* either in Macintosh or Windows platform encodings                  */
233    found_win   = -1;
234    found_apple = -1;
235
236    for ( n = 0; n < face->num_names; n++ )
237    {
238      TT_NameEntryRec*  name = face->name_table.names + n;
239
240
241      if ( name->nameID == 6 && name->stringLength > 0 )
242      {
243        if ( name->platformID == 3     &&
244             name->encodingID == 1     &&
245             name->languageID == 0x409 )
246          found_win = n;
247
248        if ( name->platformID == 1 &&
249             name->encodingID == 0 &&
250             name->languageID == 0 )
251          found_apple = n;
252      }
253    }
254
255    if ( found_win != -1 )
256    {
257      FT_Memory         memory = face->root.memory;
258      TT_NameEntryRec*  name   = face->name_table.names + found_win;
259      FT_UInt           len    = name->stringLength / 2;
260      FT_Error          error  = FT_Err_Ok;
261
262      FT_UNUSED( error );
263
264
265      if ( !FT_ALLOC( result, name->stringLength + 1 ) )
266      {
267        FT_Stream   stream = face->name_table.stream;
268        FT_String*  r      = (FT_String*)result;
269        FT_Byte*    p      = (FT_Byte*)name->string;
270
271
272        if ( FT_STREAM_SEEK( name->stringOffset ) ||
273             FT_FRAME_ENTER( name->stringLength ) )
274        {
275          FT_FREE( result );
276          name->stringLength = 0;
277          name->stringOffset = 0;
278          FT_FREE( name->string );
279
280          goto Exit;
281        }
282
283        p = (FT_Byte*)stream->cursor;
284
285        for ( ; len > 0; len--, p += 2 )
286        {
287          if ( p[0] == 0 && p[1] >= 32 && p[1] < 128 )
288            *r++ = p[1];
289        }
290        *r = '\0';
291
292        FT_FRAME_EXIT();
293      }
294      goto Exit;
295    }
296
297    if ( found_apple != -1 )
298    {
299      FT_Memory         memory = face->root.memory;
300      TT_NameEntryRec*  name   = face->name_table.names + found_apple;
301      FT_UInt           len    = name->stringLength;
302      FT_Error          error  = FT_Err_Ok;
303
304      FT_UNUSED( error );
305
306
307      if ( !FT_ALLOC( result, len + 1 ) )
308      {
309        FT_Stream  stream = face->name_table.stream;
310
311
312        if ( FT_STREAM_SEEK( name->stringOffset ) ||
313             FT_STREAM_READ( result, len )        )
314        {
315          name->stringOffset = 0;
316          name->stringLength = 0;
317          FT_FREE( name->string );
318          FT_FREE( result );
319          goto Exit;
320        }
321        ((char*)result)[len] = '\0';
322      }
323    }
324
325  Exit:
326    face->postscript_name = result;
327    return result;
328  }
329
330
331  FT_DEFINE_SERVICE_PSFONTNAMEREC(
332    sfnt_service_ps_name,
333    (FT_PsName_GetFunc)sfnt_get_ps_name )
334
335
336  /*
337   *  TT CMAP INFO
338   */
339  FT_DEFINE_SERVICE_TTCMAPSREC(
340    tt_service_get_cmap_info,
341    (TT_CMap_Info_GetFunc)tt_get_cmap_info )
342
343
344#ifdef TT_CONFIG_OPTION_BDF
345
346  static FT_Error
347  sfnt_get_charset_id( TT_Face       face,
348                       const char*  *acharset_encoding,
349                       const char*  *acharset_registry )
350  {
351    BDF_PropertyRec  encoding, registry;
352    FT_Error         error;
353
354
355    /* XXX: I don't know whether this is correct, since
356     *      tt_face_find_bdf_prop only returns something correct if we have
357     *      previously selected a size that is listed in the BDF table.
358     *      Should we change the BDF table format to include single offsets
359     *      for `CHARSET_REGISTRY' and `CHARSET_ENCODING'?
360     */
361    error = tt_face_find_bdf_prop( face, "CHARSET_REGISTRY", &registry );
362    if ( !error )
363    {
364      error = tt_face_find_bdf_prop( face, "CHARSET_ENCODING", &encoding );
365      if ( !error )
366      {
367        if ( registry.type == BDF_PROPERTY_TYPE_ATOM &&
368             encoding.type == BDF_PROPERTY_TYPE_ATOM )
369        {
370          *acharset_encoding = encoding.u.atom;
371          *acharset_registry = registry.u.atom;
372        }
373        else
374          error = FT_THROW( Invalid_Argument );
375      }
376    }
377
378    return error;
379  }
380
381
382  FT_DEFINE_SERVICE_BDFRec(
383    sfnt_service_bdf,
384    (FT_BDF_GetCharsetIdFunc)sfnt_get_charset_id,
385    (FT_BDF_GetPropertyFunc) tt_face_find_bdf_prop )
386
387
388#endif /* TT_CONFIG_OPTION_BDF */
389
390
391  /*
392   *  SERVICE LIST
393   */
394
395#if defined TT_CONFIG_OPTION_POSTSCRIPT_NAMES && defined TT_CONFIG_OPTION_BDF
396  FT_DEFINE_SERVICEDESCREC5(
397    sfnt_services,
398    FT_SERVICE_ID_SFNT_TABLE,           &SFNT_SERVICE_SFNT_TABLE_GET,
399    FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &SFNT_SERVICE_PS_NAME_GET,
400    FT_SERVICE_ID_GLYPH_DICT,           &SFNT_SERVICE_GLYPH_DICT_GET,
401    FT_SERVICE_ID_BDF,                  &SFNT_SERVICE_BDF_GET,
402    FT_SERVICE_ID_TT_CMAP,              &TT_SERVICE_CMAP_INFO_GET )
403#elif defined TT_CONFIG_OPTION_POSTSCRIPT_NAMES
404  FT_DEFINE_SERVICEDESCREC4(
405    sfnt_services,
406    FT_SERVICE_ID_SFNT_TABLE,           &SFNT_SERVICE_SFNT_TABLE_GET,
407    FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &SFNT_SERVICE_PS_NAME_GET,
408    FT_SERVICE_ID_GLYPH_DICT,           &SFNT_SERVICE_GLYPH_DICT_GET,
409    FT_SERVICE_ID_TT_CMAP,              &TT_SERVICE_CMAP_INFO_GET )
410#elif defined TT_CONFIG_OPTION_BDF
411  FT_DEFINE_SERVICEDESCREC4(
412    sfnt_services,
413    FT_SERVICE_ID_SFNT_TABLE,           &SFNT_SERVICE_SFNT_TABLE_GET,
414    FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &SFNT_SERVICE_PS_NAME_GET,
415    FT_SERVICE_ID_BDF,                  &SFNT_SERVICE_BDF_GET,
416    FT_SERVICE_ID_TT_CMAP,              &TT_SERVICE_CMAP_INFO_GET )
417#else
418  FT_DEFINE_SERVICEDESCREC3(
419    sfnt_services,
420    FT_SERVICE_ID_SFNT_TABLE,           &SFNT_SERVICE_SFNT_TABLE_GET,
421    FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &SFNT_SERVICE_PS_NAME_GET,
422    FT_SERVICE_ID_TT_CMAP,              &TT_SERVICE_CMAP_INFO_GET )
423#endif
424
425
426  FT_CALLBACK_DEF( FT_Module_Interface )
427  sfnt_get_interface( FT_Module    module,
428                      const char*  module_interface )
429  {
430    /* SFNT_SERVICES_GET derefers `library' in PIC mode */
431#ifdef FT_CONFIG_OPTION_PIC
432    FT_Library  library;
433
434
435    if ( !module )
436      return NULL;
437    library = module->library;
438    if ( !library )
439      return NULL;
440#else
441    FT_UNUSED( module );
442#endif
443
444    return ft_service_list_lookup( SFNT_SERVICES_GET, module_interface );
445  }
446
447
448#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
449#define PUT_EMBEDDED_BITMAPS( a )  a
450#else
451#define PUT_EMBEDDED_BITMAPS( a )  NULL
452#endif
453
454#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
455#define PUT_PS_NAMES( a )  a
456#else
457#define PUT_PS_NAMES( a )  NULL
458#endif
459
460  FT_DEFINE_SFNT_INTERFACE(
461    sfnt_interface,
462    tt_face_goto_table,
463
464    sfnt_init_face,
465    sfnt_load_face,
466    sfnt_done_face,
467    sfnt_get_interface,
468
469    tt_face_load_any,
470
471    tt_face_load_head,
472    tt_face_load_hhea,
473    tt_face_load_cmap,
474    tt_face_load_maxp,
475    tt_face_load_os2,
476    tt_face_load_post,
477
478    tt_face_load_name,
479    tt_face_free_name,
480
481    tt_face_load_kern,
482    tt_face_load_gasp,
483    tt_face_load_pclt,
484
485    /* see `ttload.h' */
486    PUT_EMBEDDED_BITMAPS( tt_face_load_bhed ),
487
488    PUT_EMBEDDED_BITMAPS( tt_face_load_sbit_image ),
489
490    /* see `ttpost.h' */
491    PUT_PS_NAMES( tt_face_get_ps_name   ),
492    PUT_PS_NAMES( tt_face_free_ps_names ),
493
494    /* since version 2.1.8 */
495    tt_face_get_kerning,
496
497    /* since version 2.2 */
498    tt_face_load_font_dir,
499    tt_face_load_hmtx,
500
501    /* see `ttsbit.h' and `sfnt.h' */
502    PUT_EMBEDDED_BITMAPS( tt_face_load_eblc ),
503    PUT_EMBEDDED_BITMAPS( tt_face_free_eblc ),
504
505    PUT_EMBEDDED_BITMAPS( tt_face_set_sbit_strike     ),
506    PUT_EMBEDDED_BITMAPS( tt_face_load_strike_metrics ),
507
508    tt_face_get_metrics
509  )
510
511
512  FT_DEFINE_MODULE(
513    sfnt_module_class,
514
515    0,  /* not a font driver or renderer */
516    sizeof ( FT_ModuleRec ),
517
518    "sfnt",     /* driver name                            */
519    0x10000L,   /* driver version 1.0                     */
520    0x20000L,   /* driver requires FreeType 2.0 or higher */
521
522    (const void*)&SFNT_INTERFACE_GET,  /* module specific interface */
523
524    (FT_Module_Constructor)0,
525    (FT_Module_Destructor) 0,
526    (FT_Module_Requester)  sfnt_get_interface )
527
528
529/* END */
530