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_UNUSED( module );
    426 
    427     return ft_service_list_lookup( FT_SFNT_SERVICES_GET, module_interface );
    428   }
    429 
    430 
    431 #ifdef FT_CONFIG_OPTION_OLD_INTERNALS
    432 
    433   FT_CALLBACK_DEF( FT_Error )
    434   tt_face_load_sfnt_header_stub( TT_Face      face,
    435                                  FT_Stream    stream,
    436                                  FT_Long      face_index,
    437                                  SFNT_Header  header )
    438   {
    439     FT_UNUSED( face );
    440     FT_UNUSED( stream );
    441     FT_UNUSED( face_index );
    442     FT_UNUSED( header );
    443 
    444     return SFNT_Err_Unimplemented_Feature;
    445   }
    446 
    447 
    448   FT_CALLBACK_DEF( FT_Error )
    449   tt_face_load_directory_stub( TT_Face      face,
    450                                FT_Stream    stream,
    451                                SFNT_Header  header )
    452   {
    453     FT_UNUSED( face );
    454     FT_UNUSED( stream );
    455     FT_UNUSED( header );
    456 
    457     return SFNT_Err_Unimplemented_Feature;
    458   }
    459 
    460 
    461   FT_CALLBACK_DEF( FT_Error )
    462   tt_face_load_hdmx_stub( TT_Face    face,
    463                           FT_Stream  stream )
    464   {
    465     FT_UNUSED( face );
    466     FT_UNUSED( stream );
    467 
    468     return SFNT_Err_Unimplemented_Feature;
    469   }
    470 
    471 
    472   FT_CALLBACK_DEF( void )
    473   tt_face_free_hdmx_stub( TT_Face  face )
    474   {
    475     FT_UNUSED( face );
    476   }
    477 
    478 
    479   FT_CALLBACK_DEF( FT_Error )
    480   tt_face_set_sbit_strike_stub( TT_Face    face,
    481                                 FT_UInt    x_ppem,
    482                                 FT_UInt    y_ppem,
    483                                 FT_ULong*  astrike_index )
    484   {
    485     /*
    486      * We simply forge a FT_Size_Request and call the real function
    487      * that does all the work.
    488      *
    489      * This stub might be called by libXfont in the X.Org Xserver,
    490      * compiled against version 2.1.8 or newer.
    491      */
    492 
    493     FT_Size_RequestRec  req;
    494 
    495 
    496     req.type           = FT_SIZE_REQUEST_TYPE_NOMINAL;
    497     req.width          = (FT_F26Dot6)x_ppem;
    498     req.height         = (FT_F26Dot6)y_ppem;
    499     req.horiResolution = 0;
    500     req.vertResolution = 0;
    501 
    502     *astrike_index = 0x7FFFFFFFUL;
    503 
    504     return tt_face_set_sbit_strike( face, &req, astrike_index );
    505   }
    506 
    507 
    508   FT_CALLBACK_DEF( FT_Error )
    509   tt_face_load_sbit_stub( TT_Face    face,
    510                           FT_Stream  stream )
    511   {
    512     FT_UNUSED( face );
    513     FT_UNUSED( stream );
    514 
    515     /*
    516      *  This function was originally implemented to load the sbit table.
    517      *  However, it has been replaced by `tt_face_load_eblc', and this stub
    518      *  is only there for some rogue clients which would want to call it
    519      *  directly (which doesn't make much sense).
    520      */
    521     return SFNT_Err_Unimplemented_Feature;
    522   }
    523 
    524 
    525   FT_CALLBACK_DEF( void )
    526   tt_face_free_sbit_stub( TT_Face  face )
    527   {
    528     /* nothing to do in this stub */
    529     FT_UNUSED( face );
    530   }
    531 
    532 
    533   FT_CALLBACK_DEF( FT_Error )
    534   tt_face_load_charmap_stub( TT_Face    face,
    535                              void*      cmap,
    536                              FT_Stream  input )
    537   {
    538     FT_UNUSED( face );
    539     FT_UNUSED( cmap );
    540     FT_UNUSED( input );
    541 
    542     return SFNT_Err_Unimplemented_Feature;
    543   }
    544 
    545 
    546   FT_CALLBACK_DEF( FT_Error )
    547   tt_face_free_charmap_stub( TT_Face  face,
    548                              void*    cmap )
    549   {
    550     FT_UNUSED( face );
    551     FT_UNUSED( cmap );
    552 
    553     return SFNT_Err_Ok;
    554   }
    555 
    556 #endif /* FT_CONFIG_OPTION_OLD_INTERNALS */
    557 
    558 #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
    559 #define PUT_EMBEDDED_BITMAPS(a) a
    560 #else
    561 #define PUT_EMBEDDED_BITMAPS(a) 0
    562 #endif
    563 #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
    564 #define PUT_PS_NAMES(a) a
    565 #else
    566 #define PUT_PS_NAMES(a) 0
    567 #endif
    568 
    569   FT_DEFINE_SFNT_INTERFACE(sfnt_interface,
    570     tt_face_goto_table,
    571 
    572     sfnt_init_face,
    573     sfnt_load_face,
    574     sfnt_done_face,
    575     sfnt_get_interface,
    576 
    577     tt_face_load_any,
    578 
    579     tt_face_load_sfnt_header_stub, /* FT_CONFIG_OPTION_OLD_INTERNALS */
    580     tt_face_load_directory_stub, /* FT_CONFIG_OPTION_OLD_INTERNALS */
    581 
    582     tt_face_load_head,
    583     tt_face_load_hhea,
    584     tt_face_load_cmap,
    585     tt_face_load_maxp,
    586     tt_face_load_os2,
    587     tt_face_load_post,
    588 
    589     tt_face_load_name,
    590     tt_face_free_name,
    591 
    592     tt_face_load_hdmx_stub, /* FT_CONFIG_OPTION_OLD_INTERNALS */
    593     tt_face_free_hdmx_stub, /* FT_CONFIG_OPTION_OLD_INTERNALS */
    594 
    595     tt_face_load_kern,
    596     tt_face_load_gasp,
    597     tt_face_load_pclt,
    598 
    599     /* see `ttload.h' */
    600     PUT_EMBEDDED_BITMAPS(tt_face_load_bhed),
    601 
    602     tt_face_set_sbit_strike_stub, /* FT_CONFIG_OPTION_OLD_INTERNALS */
    603     tt_face_load_sbit_stub, /* FT_CONFIG_OPTION_OLD_INTERNALS */
    604 
    605     tt_find_sbit_image, /* FT_CONFIG_OPTION_OLD_INTERNALS */
    606     tt_load_sbit_metrics, /* FT_CONFIG_OPTION_OLD_INTERNALS */
    607 
    608     PUT_EMBEDDED_BITMAPS(tt_face_load_sbit_image),
    609 
    610     tt_face_free_sbit_stub, /* FT_CONFIG_OPTION_OLD_INTERNALS */
    611 
    612     /* see `ttpost.h' */
    613     PUT_PS_NAMES(tt_face_get_ps_name),
    614     PUT_PS_NAMES(tt_face_free_ps_names),
    615 
    616     tt_face_load_charmap_stub, /* FT_CONFIG_OPTION_OLD_INTERNALS */
    617     tt_face_free_charmap_stub, /* FT_CONFIG_OPTION_OLD_INTERNALS */
    618 
    619     /* since version 2.1.8 */
    620 
    621     tt_face_get_kerning,
    622 
    623     /* since version 2.2 */
    624 
    625     tt_face_load_font_dir,
    626     tt_face_load_hmtx,
    627 
    628     /* see `ttsbit.h' and `sfnt.h' */
    629     PUT_EMBEDDED_BITMAPS(tt_face_load_eblc),
    630     PUT_EMBEDDED_BITMAPS(tt_face_free_eblc),
    631 
    632     PUT_EMBEDDED_BITMAPS(tt_face_set_sbit_strike),
    633     PUT_EMBEDDED_BITMAPS(tt_face_load_strike_metrics),
    634 
    635     tt_face_get_metrics
    636   )
    637 
    638 
    639   FT_DEFINE_MODULE(sfnt_module_class,
    640 
    641     0,  /* not a font driver or renderer */
    642     sizeof( FT_ModuleRec ),
    643 
    644     "sfnt",     /* driver name                            */
    645     0x10000L,   /* driver version 1.0                     */
    646     0x20000L,   /* driver requires FreeType 2.0 or higher */
    647 
    648     (const void*)&FT_SFNT_INTERFACE_GET,  /* module specific interface */
    649 
    650     (FT_Module_Constructor)0,
    651     (FT_Module_Destructor) 0,
    652     (FT_Module_Requester)  sfnt_get_interface
    653   )
    654 
    655 
    656 /* END */
    657