Home | History | Annotate | Download | only in sfnt
      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