1/***************************************************************************/
2/*                                                                         */
3/*  sfdriver.c                                                             */
4/*                                                                         */
5/*    High-level SFNT driver interface (body).                             */
6/*                                                                         */
7/*  Copyright 1996-2007, 2009-2011 by                                      */
8/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
9/*                                                                         */
10/*  This file is part of the FreeType project, and may only be used,       */
11/*  modified, and distributed under the terms of the FreeType project      */
12/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
13/*  this file you indicate that you have read the license and              */
14/*  understand and accept it fully.                                        */
15/*                                                                         */
16/***************************************************************************/
17
18
19#include <ft2build.h>
20#include FT_INTERNAL_DEBUG_H
21#include FT_INTERNAL_SFNT_H
22#include FT_INTERNAL_OBJECTS_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 FT_SERVICE_BDF_H
42#endif
43
44#include "ttcmap.h"
45#include "ttkern.h"
46#include "ttmtx.h"
47
48#include FT_SERVICE_GLYPH_DICT_H
49#include FT_SERVICE_POSTSCRIPT_NAME_H
50#include FT_SERVICE_SFNT_H
51#include FT_SERVICE_TT_CMAP_H
52
53  /*************************************************************************/
54  /*                                                                       */
55  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
56  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
57  /* messages during execution.                                            */
58  /*                                                                       */
59#undef  FT_COMPONENT
60#define FT_COMPONENT  trace_sfdriver
61
62
63 /*
64  *  SFNT TABLE SERVICE
65  *
66  */
67
68  static void*
69  get_sfnt_table( TT_Face      face,
70                  FT_Sfnt_Tag  tag )
71  {
72    void*  table;
73
74
75    switch ( tag )
76    {
77    case ft_sfnt_head:
78      table = &face->header;
79      break;
80
81    case ft_sfnt_hhea:
82      table = &face->horizontal;
83      break;
84
85    case ft_sfnt_vhea:
86      table = face->vertical_info ? &face->vertical : 0;
87      break;
88
89    case ft_sfnt_os2:
90      table = face->os2.version == 0xFFFFU ? 0 : &face->os2;
91      break;
92
93    case ft_sfnt_post:
94      table = &face->postscript;
95      break;
96
97    case ft_sfnt_maxp:
98      table = &face->max_profile;
99      break;
100
101    case ft_sfnt_pclt:
102      table = face->pclt.Version ? &face->pclt : 0;
103      break;
104
105    default:
106      table = 0;
107    }
108
109    return table;
110  }
111
112
113  static FT_Error
114  sfnt_table_info( TT_Face    face,
115                   FT_UInt    idx,
116                   FT_ULong  *tag,
117                   FT_ULong  *offset,
118                   FT_ULong  *length )
119  {
120    if ( !offset || !length )
121      return SFNT_Err_Invalid_Argument;
122
123    if ( !tag )
124      *length = face->num_tables;
125    else
126    {
127      if ( idx >= face->num_tables )
128        return SFNT_Err_Table_Missing;
129
130      *tag    = face->dir_tables[idx].Tag;
131      *offset = face->dir_tables[idx].Offset;
132      *length = face->dir_tables[idx].Length;
133    }
134
135    return SFNT_Err_Ok;
136  }
137
138
139  FT_DEFINE_SERVICE_SFNT_TABLEREC(sfnt_service_sfnt_table,
140    (FT_SFNT_TableLoadFunc)tt_face_load_any,
141    (FT_SFNT_TableGetFunc) get_sfnt_table,
142    (FT_SFNT_TableInfoFunc)sfnt_table_info
143  )
144
145
146#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
147
148 /*
149  *  GLYPH DICT SERVICE
150  *
151  */
152
153  static FT_Error
154  sfnt_get_glyph_name( TT_Face     face,
155                       FT_UInt     glyph_index,
156                       FT_Pointer  buffer,
157                       FT_UInt     buffer_max )
158  {
159    FT_String*  gname;
160    FT_Error    error;
161
162
163    error = tt_face_get_ps_name( face, glyph_index, &gname );
164    if ( !error )
165      FT_STRCPYN( buffer, gname, buffer_max );
166
167    return error;
168  }
169
170
171  static FT_UInt
172  sfnt_get_name_index( TT_Face     face,
173                       FT_String*  glyph_name )
174  {
175    FT_Face   root = &face->root;
176    FT_UInt   i, max_gid = FT_UINT_MAX;
177
178
179    if ( root->num_glyphs < 0 )
180      return 0;
181    else if ( ( FT_ULong ) root->num_glyphs < FT_UINT_MAX )
182      max_gid = ( FT_UInt ) root->num_glyphs;
183    else
184      FT_TRACE0(( "Ignore glyph names for invalid GID 0x%08x - 0x%08x\n",
185         FT_UINT_MAX, root->num_glyphs ));
186
187    for ( i = 0; i < max_gid; i++ )
188    {
189      FT_String*  gname;
190      FT_Error    error = tt_face_get_ps_name( face, i, &gname );
191
192
193      if ( error )
194        continue;
195
196      if ( !ft_strcmp( glyph_name, gname ) )
197        return i;
198    }
199
200    return 0;
201  }
202
203
204  FT_DEFINE_SERVICE_GLYPHDICTREC(sfnt_service_glyph_dict,
205    (FT_GlyphDict_GetNameFunc)  sfnt_get_glyph_name,
206    (FT_GlyphDict_NameIndexFunc)sfnt_get_name_index
207  )
208
209#endif /* TT_CONFIG_OPTION_POSTSCRIPT_NAMES */
210
211
212 /*
213  *  POSTSCRIPT NAME SERVICE
214  *
215  */
216
217  static const char*
218  sfnt_get_ps_name( TT_Face  face )
219  {
220    FT_Int       n, found_win, found_apple;
221    const char*  result = NULL;
222
223
224    /* shouldn't happen, but just in case to avoid memory leaks */
225    if ( face->postscript_name )
226      return face->postscript_name;
227
228    /* scan the name table to see whether we have a Postscript name here, */
229    /* either in Macintosh or Windows platform encodings                  */
230    found_win   = -1;
231    found_apple = -1;
232
233    for ( n = 0; n < face->num_names; n++ )
234    {
235      TT_NameEntryRec*  name = face->name_table.names + n;
236
237
238      if ( name->nameID == 6 && name->stringLength > 0 )
239      {
240        if ( name->platformID == 3     &&
241             name->encodingID == 1     &&
242             name->languageID == 0x409 )
243          found_win = n;
244
245        if ( name->platformID == 1 &&
246             name->encodingID == 0 &&
247             name->languageID == 0 )
248          found_apple = n;
249      }
250    }
251
252    if ( found_win != -1 )
253    {
254      FT_Memory         memory = face->root.memory;
255      TT_NameEntryRec*  name   = face->name_table.names + found_win;
256      FT_UInt           len    = name->stringLength / 2;
257      FT_Error          error  = SFNT_Err_Ok;
258
259      FT_UNUSED( error );
260
261
262      if ( !FT_ALLOC( result, name->stringLength + 1 ) )
263      {
264        FT_Stream   stream = face->name_table.stream;
265        FT_String*  r      = (FT_String*)result;
266        FT_Byte*    p      = (FT_Byte*)name->string;
267
268
269        if ( FT_STREAM_SEEK( name->stringOffset ) ||
270             FT_FRAME_ENTER( name->stringLength ) )
271        {
272          FT_FREE( result );
273          name->stringLength = 0;
274          name->stringOffset = 0;
275          FT_FREE( name->string );
276
277          goto Exit;
278        }
279
280        p = (FT_Byte*)stream->cursor;
281
282        for ( ; len > 0; len--, p += 2 )
283        {
284          if ( p[0] == 0 && p[1] >= 32 && p[1] < 128 )
285            *r++ = p[1];
286        }
287        *r = '\0';
288
289        FT_FRAME_EXIT();
290      }
291      goto Exit;
292    }
293
294    if ( found_apple != -1 )
295    {
296      FT_Memory         memory = face->root.memory;
297      TT_NameEntryRec*  name   = face->name_table.names + found_apple;
298      FT_UInt           len    = name->stringLength;
299      FT_Error          error  = SFNT_Err_Ok;
300
301      FT_UNUSED( error );
302
303
304      if ( !FT_ALLOC( result, len + 1 ) )
305      {
306        FT_Stream  stream = face->name_table.stream;
307
308
309        if ( FT_STREAM_SEEK( name->stringOffset ) ||
310             FT_STREAM_READ( result, len )        )
311        {
312          name->stringOffset = 0;
313          name->stringLength = 0;
314          FT_FREE( name->string );
315          FT_FREE( result );
316          goto Exit;
317        }
318        ((char*)result)[len] = '\0';
319      }
320    }
321
322  Exit:
323    face->postscript_name = result;
324    return result;
325  }
326
327  FT_DEFINE_SERVICE_PSFONTNAMEREC(sfnt_service_ps_name,
328    (FT_PsName_GetFunc)sfnt_get_ps_name
329  )
330
331
332  /*
333   *  TT CMAP INFO
334   */
335  FT_DEFINE_SERVICE_TTCMAPSREC(tt_service_get_cmap_info,
336    (TT_CMap_Info_GetFunc)tt_get_cmap_info
337  )
338
339
340#ifdef TT_CONFIG_OPTION_BDF
341
342  static FT_Error
343  sfnt_get_charset_id( TT_Face       face,
344                       const char*  *acharset_encoding,
345                       const char*  *acharset_registry )
346  {
347    BDF_PropertyRec  encoding, registry;
348    FT_Error         error;
349
350
351    /* XXX: I don't know whether this is correct, since
352     *      tt_face_find_bdf_prop only returns something correct if we have
353     *      previously selected a size that is listed in the BDF table.
354     *      Should we change the BDF table format to include single offsets
355     *      for `CHARSET_REGISTRY' and `CHARSET_ENCODING'?
356     */
357    error = tt_face_find_bdf_prop( face, "CHARSET_REGISTRY", &registry );
358    if ( !error )
359    {
360      error = tt_face_find_bdf_prop( face, "CHARSET_ENCODING", &encoding );
361      if ( !error )
362      {
363        if ( registry.type == BDF_PROPERTY_TYPE_ATOM &&
364             encoding.type == BDF_PROPERTY_TYPE_ATOM )
365        {
366          *acharset_encoding = encoding.u.atom;
367          *acharset_registry = registry.u.atom;
368        }
369        else
370          error = SFNT_Err_Invalid_Argument;
371      }
372    }
373
374    return error;
375  }
376
377
378  FT_DEFINE_SERVICE_BDFRec(sfnt_service_bdf,
379    (FT_BDF_GetCharsetIdFunc) sfnt_get_charset_id,
380    (FT_BDF_GetPropertyFunc)  tt_face_find_bdf_prop
381  )
382
383#endif /* TT_CONFIG_OPTION_BDF */
384
385
386  /*
387   *  SERVICE LIST
388   */
389
390#if defined TT_CONFIG_OPTION_POSTSCRIPT_NAMES && defined TT_CONFIG_OPTION_BDF
391  FT_DEFINE_SERVICEDESCREC5(sfnt_services,
392    FT_SERVICE_ID_SFNT_TABLE,           &FT_SFNT_SERVICE_SFNT_TABLE_GET,
393    FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &FT_SFNT_SERVICE_PS_NAME_GET,
394    FT_SERVICE_ID_GLYPH_DICT,           &FT_SFNT_SERVICE_GLYPH_DICT_GET,
395    FT_SERVICE_ID_BDF,                  &FT_SFNT_SERVICE_BDF_GET,
396    FT_SERVICE_ID_TT_CMAP,              &FT_TT_SERVICE_GET_CMAP_INFO_GET
397  )
398#elif defined TT_CONFIG_OPTION_POSTSCRIPT_NAMES
399  FT_DEFINE_SERVICEDESCREC4(sfnt_services,
400    FT_SERVICE_ID_SFNT_TABLE,           &FT_SFNT_SERVICE_SFNT_TABLE_GET,
401    FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &FT_SFNT_SERVICE_PS_NAME_GET,
402    FT_SERVICE_ID_GLYPH_DICT,           &FT_SFNT_SERVICE_GLYPH_DICT_GET,
403    FT_SERVICE_ID_TT_CMAP,              &FT_TT_SERVICE_GET_CMAP_INFO_GET
404  )
405#elif defined TT_CONFIG_OPTION_BDF
406  FT_DEFINE_SERVICEDESCREC4(sfnt_services,
407    FT_SERVICE_ID_SFNT_TABLE,           &FT_SFNT_SERVICE_SFNT_TABLE_GET,
408    FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &FT_SFNT_SERVICE_PS_NAME_GET,
409    FT_SERVICE_ID_BDF,                  &FT_SFNT_SERVICE_BDF_GET,
410    FT_SERVICE_ID_TT_CMAP,              &FT_TT_SERVICE_GET_CMAP_INFO_GET
411  )
412#else
413  FT_DEFINE_SERVICEDESCREC3(sfnt_services,
414    FT_SERVICE_ID_SFNT_TABLE,           &FT_SFNT_SERVICE_SFNT_TABLE_GET,
415    FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &FT_SFNT_SERVICE_PS_NAME_GET,
416    FT_SERVICE_ID_TT_CMAP,              &FT_TT_SERVICE_GET_CMAP_INFO_GET
417  )
418#endif
419
420
421  FT_CALLBACK_DEF( FT_Module_Interface )
422  sfnt_get_interface( FT_Module    module,
423                      const char*  module_interface )
424  {
425    /* FT_SFNT_SERVICES_GET derefers `library' in PIC mode */
426#ifdef FT_CONFIG_OPTION_PIC
427    FT_Library  library;
428
429
430    if ( !module )
431      return NULL;
432    library = module->library;
433    if ( !library )
434      return NULL;
435#else
436    FT_UNUSED( module );
437#endif
438    return ft_service_list_lookup( FT_SFNT_SERVICES_GET, module_interface );
439  }
440
441
442#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
443
444  FT_CALLBACK_DEF( FT_Error )
445  tt_face_load_sfnt_header_stub( TT_Face      face,
446                                 FT_Stream    stream,
447                                 FT_Long      face_index,
448                                 SFNT_Header  header )
449  {
450    FT_UNUSED( face );
451    FT_UNUSED( stream );
452    FT_UNUSED( face_index );
453    FT_UNUSED( header );
454
455    return SFNT_Err_Unimplemented_Feature;
456  }
457
458
459  FT_CALLBACK_DEF( FT_Error )
460  tt_face_load_directory_stub( TT_Face      face,
461                               FT_Stream    stream,
462                               SFNT_Header  header )
463  {
464    FT_UNUSED( face );
465    FT_UNUSED( stream );
466    FT_UNUSED( header );
467
468    return SFNT_Err_Unimplemented_Feature;
469  }
470
471
472  FT_CALLBACK_DEF( FT_Error )
473  tt_face_load_hdmx_stub( TT_Face    face,
474                          FT_Stream  stream )
475  {
476    FT_UNUSED( face );
477    FT_UNUSED( stream );
478
479    return SFNT_Err_Unimplemented_Feature;
480  }
481
482
483  FT_CALLBACK_DEF( void )
484  tt_face_free_hdmx_stub( TT_Face  face )
485  {
486    FT_UNUSED( face );
487  }
488
489
490  FT_CALLBACK_DEF( FT_Error )
491  tt_face_set_sbit_strike_stub( TT_Face    face,
492                                FT_UInt    x_ppem,
493                                FT_UInt    y_ppem,
494                                FT_ULong*  astrike_index )
495  {
496    /*
497     * We simply forge a FT_Size_Request and call the real function
498     * that does all the work.
499     *
500     * This stub might be called by libXfont in the X.Org Xserver,
501     * compiled against version 2.1.8 or newer.
502     */
503
504    FT_Size_RequestRec  req;
505
506
507    req.type           = FT_SIZE_REQUEST_TYPE_NOMINAL;
508    req.width          = (FT_F26Dot6)x_ppem;
509    req.height         = (FT_F26Dot6)y_ppem;
510    req.horiResolution = 0;
511    req.vertResolution = 0;
512
513    *astrike_index = 0x7FFFFFFFUL;
514
515    return tt_face_set_sbit_strike( face, &req, astrike_index );
516  }
517
518
519  FT_CALLBACK_DEF( FT_Error )
520  tt_face_load_sbit_stub( TT_Face    face,
521                          FT_Stream  stream )
522  {
523    FT_UNUSED( face );
524    FT_UNUSED( stream );
525
526    /*
527     *  This function was originally implemented to load the sbit table.
528     *  However, it has been replaced by `tt_face_load_eblc', and this stub
529     *  is only there for some rogue clients which would want to call it
530     *  directly (which doesn't make much sense).
531     */
532    return SFNT_Err_Unimplemented_Feature;
533  }
534
535
536  FT_CALLBACK_DEF( void )
537  tt_face_free_sbit_stub( TT_Face  face )
538  {
539    /* nothing to do in this stub */
540    FT_UNUSED( face );
541  }
542
543
544  FT_CALLBACK_DEF( FT_Error )
545  tt_face_load_charmap_stub( TT_Face    face,
546                             void*      cmap,
547                             FT_Stream  input )
548  {
549    FT_UNUSED( face );
550    FT_UNUSED( cmap );
551    FT_UNUSED( input );
552
553    return SFNT_Err_Unimplemented_Feature;
554  }
555
556
557  FT_CALLBACK_DEF( FT_Error )
558  tt_face_free_charmap_stub( TT_Face  face,
559                             void*    cmap )
560  {
561    FT_UNUSED( face );
562    FT_UNUSED( cmap );
563
564    return SFNT_Err_Ok;
565  }
566
567#endif /* FT_CONFIG_OPTION_OLD_INTERNALS */
568
569#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
570#define PUT_EMBEDDED_BITMAPS(a) a
571#else
572#define PUT_EMBEDDED_BITMAPS(a) 0
573#endif
574#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
575#define PUT_PS_NAMES(a) a
576#else
577#define PUT_PS_NAMES(a) 0
578#endif
579
580  FT_DEFINE_SFNT_INTERFACE(sfnt_interface,
581    tt_face_goto_table,
582
583    sfnt_init_face,
584    sfnt_load_face,
585    sfnt_done_face,
586    sfnt_get_interface,
587
588    tt_face_load_any,
589
590    tt_face_load_sfnt_header_stub, /* FT_CONFIG_OPTION_OLD_INTERNALS */
591    tt_face_load_directory_stub, /* FT_CONFIG_OPTION_OLD_INTERNALS */
592
593    tt_face_load_head,
594    tt_face_load_hhea,
595    tt_face_load_cmap,
596    tt_face_load_maxp,
597    tt_face_load_os2,
598    tt_face_load_post,
599
600    tt_face_load_name,
601    tt_face_free_name,
602
603    tt_face_load_hdmx_stub, /* FT_CONFIG_OPTION_OLD_INTERNALS */
604    tt_face_free_hdmx_stub, /* FT_CONFIG_OPTION_OLD_INTERNALS */
605
606    tt_face_load_kern,
607    tt_face_load_gasp,
608    tt_face_load_pclt,
609
610    /* see `ttload.h' */
611    PUT_EMBEDDED_BITMAPS(tt_face_load_bhed),
612
613    tt_face_set_sbit_strike_stub, /* FT_CONFIG_OPTION_OLD_INTERNALS */
614    tt_face_load_sbit_stub, /* FT_CONFIG_OPTION_OLD_INTERNALS */
615
616    tt_find_sbit_image, /* FT_CONFIG_OPTION_OLD_INTERNALS */
617    tt_load_sbit_metrics, /* FT_CONFIG_OPTION_OLD_INTERNALS */
618
619    PUT_EMBEDDED_BITMAPS(tt_face_load_sbit_image),
620
621    tt_face_free_sbit_stub, /* FT_CONFIG_OPTION_OLD_INTERNALS */
622
623    /* see `ttpost.h' */
624    PUT_PS_NAMES(tt_face_get_ps_name),
625    PUT_PS_NAMES(tt_face_free_ps_names),
626
627    tt_face_load_charmap_stub, /* FT_CONFIG_OPTION_OLD_INTERNALS */
628    tt_face_free_charmap_stub, /* FT_CONFIG_OPTION_OLD_INTERNALS */
629
630    /* since version 2.1.8 */
631
632    tt_face_get_kerning,
633
634    /* since version 2.2 */
635
636    tt_face_load_font_dir,
637    tt_face_load_hmtx,
638
639    /* see `ttsbit.h' and `sfnt.h' */
640    PUT_EMBEDDED_BITMAPS(tt_face_load_eblc),
641    PUT_EMBEDDED_BITMAPS(tt_face_free_eblc),
642
643    PUT_EMBEDDED_BITMAPS(tt_face_set_sbit_strike),
644    PUT_EMBEDDED_BITMAPS(tt_face_load_strike_metrics),
645
646    tt_face_get_metrics
647  )
648
649
650  FT_DEFINE_MODULE(sfnt_module_class,
651
652    0,  /* not a font driver or renderer */
653    sizeof ( FT_ModuleRec ),
654
655    "sfnt",     /* driver name                            */
656    0x10000L,   /* driver version 1.0                     */
657    0x20000L,   /* driver requires FreeType 2.0 or higher */
658
659    (const void*)&FT_SFNT_INTERFACE_GET,  /* module specific interface */
660
661    (FT_Module_Constructor)0,
662    (FT_Module_Destructor) 0,
663    (FT_Module_Requester)  sfnt_get_interface
664  )
665
666
667/* END */
668