1 /***************************************************************************/
2 /*                                                                         */
3 /*  sfdriver.c                                                             */
4 /*                                                                         */
5 /*    High-level SFNT driver interface (body).                             */
6 /*                                                                         */
7 /*  Copyright 1996-2016 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   /*                                                                       */
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*
get_sfnt_table(TT_Face face,FT_Sfnt_Tag tag)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 : NULL;
88       break;
89 
90     case FT_SFNT_OS2:
91       table = face->os2.version == 0xFFFFU ? NULL : &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 : NULL;
104       break;
105 
106     default:
107       table = NULL;
108     }
109 
110     return table;
111   }
112 
113 
114   static FT_Error
sfnt_table_info(TT_Face face,FT_UInt idx,FT_ULong * tag,FT_ULong * offset,FT_ULong * length)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,     /* load_table */
143     (FT_SFNT_TableGetFunc) get_sfnt_table,       /* get_table  */
144     (FT_SFNT_TableInfoFunc)sfnt_table_info )     /* table_info */
145 
146 
147 #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
148 
149   /*
150    *  GLYPH DICT SERVICE
151    *
152    */
153 
154   static FT_Error
sfnt_get_glyph_name(TT_Face face,FT_UInt glyph_index,FT_Pointer buffer,FT_UInt buffer_max)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
sfnt_get_name_index(TT_Face face,FT_String * glyph_name)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,    /* get_name   */
209     (FT_GlyphDict_NameIndexFunc)sfnt_get_name_index )   /* 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*
sfnt_get_ps_name(TT_Face face)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_Char*    p;
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_Char*)stream->cursor;
284 
285         for ( ; len > 0; len--, p += 2 )
286         {
287           if ( p[0] == 0 && p[1] >= 32 )
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 )     /* get_ps_font_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 )  /* get_cmap_info */
342 
343 
344 #ifdef TT_CONFIG_OPTION_BDF
345 
346   static FT_Error
sfnt_get_charset_id(TT_Face face,const char ** acharset_encoding,const char ** acharset_registry)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,     /* get_charset_id */
385     (FT_BDF_GetPropertyFunc) tt_face_find_bdf_prop )  /* get_property   */
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 
FT_CALLBACK_DEF(FT_Module_Interface)426   FT_CALLBACK_DEF( FT_Module_Interface )
427   sfnt_get_interface( FT_Module    module,
428                       const char*  module_interface )
429   {
430     /* SFNT_SERVICES_GET dereferences `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_sbit ),
503     PUT_EMBEDDED_BITMAPS( tt_face_free_sbit ),
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     tt_face_get_name
511   )
512 
513 
514   FT_DEFINE_MODULE(
515     sfnt_module_class,
516 
517     0,  /* not a font driver or renderer */
518     sizeof ( FT_ModuleRec ),
519 
520     "sfnt",     /* driver name                            */
521     0x10000L,   /* driver version 1.0                     */
522     0x20000L,   /* driver requires FreeType 2.0 or higher */
523 
524     (const void*)&SFNT_INTERFACE_GET,  /* module specific interface */
525 
526     (FT_Module_Constructor)0,
527     (FT_Module_Destructor) 0,
528     (FT_Module_Requester)  sfnt_get_interface )
529 
530 
531 /* END */
532