tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

sfdriver.c (37071B)


      1 /****************************************************************************
      2 *
      3 * sfdriver.c
      4 *
      5 *   High-level SFNT driver interface (body).
      6 *
      7 * Copyright (C) 1996-2025 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 <freetype/internal/ftdebug.h>
     20 #include <freetype/internal/sfnt.h>
     21 #include <freetype/internal/ftobjs.h>
     22 #include <freetype/ttnameid.h>
     23 
     24 #include "sfdriver.h"
     25 #include "ttload.h"
     26 #include "sfobjs.h"
     27 
     28 #include "sferrors.h"
     29 
     30 #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
     31 #include "ttsbit.h"
     32 #endif
     33 
     34 #ifdef TT_CONFIG_OPTION_COLOR_LAYERS
     35 #include "ttcolr.h"
     36 #include "ttcpal.h"
     37 #endif
     38 
     39 #ifdef FT_CONFIG_OPTION_SVG
     40 #include "ttsvg.h"
     41 #endif
     42 
     43 #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
     44 #include "ttpost.h"
     45 #endif
     46 
     47 #ifdef TT_CONFIG_OPTION_BDF
     48 #include "ttbdf.h"
     49 #include <freetype/internal/services/svbdf.h>
     50 #endif
     51 
     52 #ifdef TT_CONFIG_OPTION_GPOS_KERNING
     53 #include "ttgpos.h"
     54 #endif
     55 
     56 #include "ttcmap.h"
     57 #include "ttkern.h"
     58 #include "ttmtx.h"
     59 
     60 #include <freetype/internal/services/svgldict.h>
     61 #include <freetype/internal/services/svpostnm.h>
     62 #include <freetype/internal/services/svsfnt.h>
     63 #include <freetype/internal/services/svttcmap.h>
     64 
     65 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
     66 #include <freetype/ftmm.h>
     67 #include <freetype/internal/services/svmm.h>
     68 #endif
     69 
     70 
     71  /**************************************************************************
     72   *
     73   * The macro FT_COMPONENT is used in trace mode.  It is an implicit
     74   * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
     75   * messages during execution.
     76   */
     77 #undef  FT_COMPONENT
     78 #define FT_COMPONENT  sfdriver
     79 
     80 
     81  /*
     82   * SFNT TABLE SERVICE
     83   *
     84   */
     85 
     86  FT_CALLBACK_DEF( FT_Error )
     87  sfnt_load_table( FT_Face    face,    /* TT_Face */
     88                   FT_ULong   tag,
     89                   FT_Long    offset,
     90                   FT_Byte*   buffer,
     91                   FT_ULong*  length )
     92  {
     93    TT_Face  ttface = (TT_Face)face;
     94 
     95 
     96    return tt_face_load_any( ttface, tag, offset, buffer, length );
     97  }
     98 
     99 
    100  FT_CALLBACK_DEF( void* )
    101  get_sfnt_table( FT_Face      face,  /* TT_Face */
    102                  FT_Sfnt_Tag  tag )
    103  {
    104    TT_Face  ttface = (TT_Face)face;
    105 
    106    void*  table;
    107 
    108 
    109    switch ( tag )
    110    {
    111    case FT_SFNT_HEAD:
    112      table = &ttface->header;
    113      break;
    114 
    115    case FT_SFNT_HHEA:
    116      table = &ttface->horizontal;
    117      break;
    118 
    119    case FT_SFNT_VHEA:
    120      table = ttface->vertical_info ? &ttface->vertical : NULL;
    121      break;
    122 
    123    case FT_SFNT_OS2:
    124      table = ( ttface->os2.version == 0xFFFFU ) ? NULL : &ttface->os2;
    125      break;
    126 
    127    case FT_SFNT_POST:
    128      table = &ttface->postscript;
    129      break;
    130 
    131    case FT_SFNT_MAXP:
    132      table = &ttface->max_profile;
    133      break;
    134 
    135    case FT_SFNT_PCLT:
    136      table = ttface->pclt.Version ? &ttface->pclt : NULL;
    137      break;
    138 
    139    default:
    140      table = NULL;
    141    }
    142 
    143    return table;
    144  }
    145 
    146 
    147  FT_CALLBACK_DEF( FT_Error )
    148  sfnt_table_info( FT_Face    face,    /* TT_Face */
    149                   FT_UInt    idx,
    150                   FT_ULong  *tag,
    151                   FT_ULong  *offset,
    152                   FT_ULong  *length )
    153  {
    154    TT_Face  ttface = (TT_Face)face;
    155 
    156 
    157    if ( !offset || !length )
    158      return FT_THROW( Invalid_Argument );
    159 
    160    if ( !tag )
    161      *length = ttface->num_tables;
    162    else
    163    {
    164      if ( idx >= ttface->num_tables )
    165        return FT_THROW( Table_Missing );
    166 
    167      *tag    = ttface->dir_tables[idx].Tag;
    168      *offset = ttface->dir_tables[idx].Offset;
    169      *length = ttface->dir_tables[idx].Length;
    170    }
    171 
    172    return FT_Err_Ok;
    173  }
    174 
    175 
    176  FT_DEFINE_SERVICE_SFNT_TABLEREC(
    177    sfnt_service_sfnt_table,
    178 
    179    sfnt_load_table,  /* FT_SFNT_TableLoadFunc load_table */
    180    get_sfnt_table,   /* FT_SFNT_TableGetFunc  get_table  */
    181    sfnt_table_info   /* FT_SFNT_TableInfoFunc table_info */
    182  )
    183 
    184 
    185 #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
    186 
    187  /*
    188   * GLYPH DICT SERVICE
    189   *
    190   */
    191 
    192  FT_CALLBACK_DEF( FT_Error )
    193  sfnt_get_glyph_name( FT_Face     face,
    194                       FT_UInt     glyph_index,
    195                       FT_Pointer  buffer,
    196                       FT_UInt     buffer_max )
    197  {
    198    FT_String*  gname;
    199    FT_Error    error;
    200 
    201 
    202    error = tt_face_get_ps_name( (TT_Face)face, glyph_index, &gname );
    203    if ( !error )
    204      FT_STRCPYN( buffer, gname, buffer_max );
    205 
    206    return error;
    207  }
    208 
    209 
    210  FT_CALLBACK_DEF( FT_UInt )
    211  sfnt_get_name_index( FT_Face           face,
    212                       const FT_String*  glyph_name )
    213  {
    214    TT_Face  ttface = (TT_Face)face;
    215 
    216    FT_UInt  i, max_gid = FT_UINT_MAX;
    217 
    218 
    219    if ( face->num_glyphs < 0 )
    220      return 0;
    221    else if ( (FT_ULong)face->num_glyphs < FT_UINT_MAX )
    222      max_gid = (FT_UInt)face->num_glyphs;
    223    else
    224      FT_TRACE0(( "Ignore glyph names for invalid GID 0x%08x - 0x%08lx\n",
    225                  FT_UINT_MAX, face->num_glyphs ));
    226 
    227    for ( i = 0; i < max_gid; i++ )
    228    {
    229      FT_String*  gname;
    230      FT_Error    error = tt_face_get_ps_name( ttface, i, &gname );
    231 
    232 
    233      if ( error )
    234        continue;
    235 
    236      if ( !ft_strcmp( glyph_name, gname ) )
    237        return i;
    238    }
    239 
    240    return 0;
    241  }
    242 
    243 
    244  FT_DEFINE_SERVICE_GLYPHDICTREC(
    245    sfnt_service_glyph_dict,
    246 
    247    sfnt_get_glyph_name,  /* FT_GlyphDict_GetNameFunc   get_name   */
    248    sfnt_get_name_index   /* FT_GlyphDict_NameIndexFunc name_index */
    249  )
    250 
    251 #endif /* TT_CONFIG_OPTION_POSTSCRIPT_NAMES */
    252 
    253 
    254  /*
    255   * POSTSCRIPT NAME SERVICE
    256   *
    257   */
    258 
    259  /* an array representing allowed ASCII characters in a PS string */
    260  static const unsigned char sfnt_ps_map[16] =
    261  {
    262                /*             4        0        C        8 */
    263    0x00, 0x00, /* 0x00: 0 0 0 0  0 0 0 0  0 0 0 0  0 0 0 0 */
    264    0x00, 0x00, /* 0x10: 0 0 0 0  0 0 0 0  0 0 0 0  0 0 0 0 */
    265    0xDE, 0x7C, /* 0x20: 1 1 0 1  1 1 1 0  0 1 1 1  1 1 0 0 */
    266    0xFF, 0xAF, /* 0x30: 1 1 1 1  1 1 1 1  1 0 1 0  1 1 1 1 */
    267    0xFF, 0xFF, /* 0x40: 1 1 1 1  1 1 1 1  1 1 1 1  1 1 1 1 */
    268    0xFF, 0xD7, /* 0x50: 1 1 1 1  1 1 1 1  1 1 0 1  0 1 1 1 */
    269    0xFF, 0xFF, /* 0x60: 1 1 1 1  1 1 1 1  1 1 1 1  1 1 1 1 */
    270    0xFF, 0x57  /* 0x70: 1 1 1 1  1 1 1 1  0 1 0 1  0 1 1 1 */
    271  };
    272 
    273 
    274  static int
    275  sfnt_is_postscript( int  c )
    276  {
    277    unsigned int  cc;
    278 
    279 
    280    if ( c < 0 || c >= 0x80 )
    281      return 0;
    282 
    283    cc = (unsigned int)c;
    284 
    285    return sfnt_ps_map[cc >> 3] & ( 1 << ( cc & 0x07 ) );
    286  }
    287 
    288 
    289 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
    290 
    291  /* Only ASCII letters and digits are taken for a variation font */
    292  /* instance's PostScript name.                                  */
    293  /*                                                              */
    294  /* `ft_isalnum' is a macro, but we need a function here, thus   */
    295  /* this definition.                                             */
    296  static int
    297  sfnt_is_alphanumeric( int  c )
    298  {
    299    return ft_isalnum( c );
    300  }
    301 
    302 
    303  /* the implementation of MurmurHash3 is taken and adapted from          */
    304  /* https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp */
    305 
    306 #define ROTL32( x, r )  ( x << r ) | ( x >> ( 32 - r ) )
    307 
    308 
    309  static FT_UInt32
    310  fmix32( FT_UInt32  h )
    311  {
    312    h ^= h >> 16;
    313    h *= 0x85ebca6b;
    314    h ^= h >> 13;
    315    h *= 0xc2b2ae35;
    316    h ^= h >> 16;
    317 
    318    return h;
    319  }
    320 
    321 
    322  static void
    323  murmur_hash_3_128( const void*         key,
    324                     const unsigned int  len,
    325                     FT_UInt32           seed,
    326                     void*               out )
    327  {
    328    const FT_Byte*  data    = (const FT_Byte*)key;
    329    const int       nblocks = (int)len / 16;
    330 
    331    FT_UInt32  h1 = seed;
    332    FT_UInt32  h2 = seed;
    333    FT_UInt32  h3 = seed;
    334    FT_UInt32  h4 = seed;
    335 
    336    const FT_UInt32  c1 = 0x239b961b;
    337    const FT_UInt32  c2 = 0xab0e9789;
    338    const FT_UInt32  c3 = 0x38b34ae5;
    339    const FT_UInt32  c4 = 0xa1e38b93;
    340 
    341    const FT_UInt32*  blocks = (const FT_UInt32*)( data + nblocks * 16 );
    342 
    343    int  i;
    344 
    345 
    346    for( i = -nblocks; i; i++ )
    347    {
    348      FT_UInt32  k1 = blocks[i * 4 + 0];
    349      FT_UInt32  k2 = blocks[i * 4 + 1];
    350      FT_UInt32  k3 = blocks[i * 4 + 2];
    351      FT_UInt32  k4 = blocks[i * 4 + 3];
    352 
    353 
    354      k1 *= c1;
    355      k1  = ROTL32( k1, 15 );
    356      k1 *= c2;
    357      h1 ^= k1;
    358 
    359      h1  = ROTL32( h1, 19 );
    360      h1 += h2;
    361      h1  = h1 * 5 + 0x561ccd1b;
    362 
    363      k2 *= c2;
    364      k2  = ROTL32( k2, 16 );
    365      k2 *= c3;
    366      h2 ^= k2;
    367 
    368      h2  = ROTL32( h2, 17 );
    369      h2 += h3;
    370      h2  = h2 * 5 + 0x0bcaa747;
    371 
    372      k3 *= c3;
    373      k3  = ROTL32( k3, 17 );
    374      k3 *= c4;
    375      h3 ^= k3;
    376 
    377      h3  = ROTL32( h3, 15 );
    378      h3 += h4;
    379      h3  = h3 * 5 + 0x96cd1c35;
    380 
    381      k4 *= c4;
    382      k4  = ROTL32( k4, 18 );
    383      k4 *= c1;
    384      h4 ^= k4;
    385 
    386      h4  = ROTL32( h4, 13 );
    387      h4 += h1;
    388      h4  = h4 * 5 + 0x32ac3b17;
    389    }
    390 
    391    {
    392      const FT_Byte*  tail = (const FT_Byte*)( data + nblocks * 16 );
    393 
    394      FT_UInt32  k1 = 0;
    395      FT_UInt32  k2 = 0;
    396      FT_UInt32  k3 = 0;
    397      FT_UInt32  k4 = 0;
    398 
    399 
    400      switch ( len & 15 )
    401      {
    402      case 15:
    403        k4 ^= (FT_UInt32)tail[14] << 16;
    404        FALL_THROUGH;
    405      case 14:
    406        k4 ^= (FT_UInt32)tail[13] << 8;
    407        FALL_THROUGH;
    408      case 13:
    409        k4 ^= (FT_UInt32)tail[12];
    410        k4 *= c4;
    411        k4  = ROTL32( k4, 18 );
    412        k4 *= c1;
    413        h4 ^= k4;
    414        FALL_THROUGH;
    415 
    416      case 12:
    417        k3 ^= (FT_UInt32)tail[11] << 24;
    418        FALL_THROUGH;
    419      case 11:
    420        k3 ^= (FT_UInt32)tail[10] << 16;
    421        FALL_THROUGH;
    422      case 10:
    423        k3 ^= (FT_UInt32)tail[9] << 8;
    424        FALL_THROUGH;
    425      case 9:
    426        k3 ^= (FT_UInt32)tail[8];
    427        k3 *= c3;
    428        k3  = ROTL32( k3, 17 );
    429        k3 *= c4;
    430        h3 ^= k3;
    431        FALL_THROUGH;
    432 
    433      case 8:
    434        k2 ^= (FT_UInt32)tail[7] << 24;
    435        FALL_THROUGH;
    436      case 7:
    437        k2 ^= (FT_UInt32)tail[6] << 16;
    438        FALL_THROUGH;
    439      case 6:
    440        k2 ^= (FT_UInt32)tail[5] << 8;
    441        FALL_THROUGH;
    442      case 5:
    443        k2 ^= (FT_UInt32)tail[4];
    444        k2 *= c2;
    445        k2  = ROTL32( k2, 16 );
    446        k2 *= c3;
    447        h2 ^= k2;
    448        FALL_THROUGH;
    449 
    450      case 4:
    451        k1 ^= (FT_UInt32)tail[3] << 24;
    452        FALL_THROUGH;
    453      case 3:
    454        k1 ^= (FT_UInt32)tail[2] << 16;
    455        FALL_THROUGH;
    456      case 2:
    457        k1 ^= (FT_UInt32)tail[1] << 8;
    458        FALL_THROUGH;
    459      case 1:
    460        k1 ^= (FT_UInt32)tail[0];
    461        k1 *= c1;
    462        k1  = ROTL32( k1, 15 );
    463        k1 *= c2;
    464        h1 ^= k1;
    465      }
    466    }
    467 
    468    h1 ^= len;
    469    h2 ^= len;
    470    h3 ^= len;
    471    h4 ^= len;
    472 
    473    h1 += h2;
    474    h1 += h3;
    475    h1 += h4;
    476 
    477    h2 += h1;
    478    h3 += h1;
    479    h4 += h1;
    480 
    481    h1 = fmix32( h1 );
    482    h2 = fmix32( h2 );
    483    h3 = fmix32( h3 );
    484    h4 = fmix32( h4 );
    485 
    486    h1 += h2;
    487    h1 += h3;
    488    h1 += h4;
    489 
    490    h2 += h1;
    491    h3 += h1;
    492    h4 += h1;
    493 
    494    ((FT_UInt32*)out)[0] = h1;
    495    ((FT_UInt32*)out)[1] = h2;
    496    ((FT_UInt32*)out)[2] = h3;
    497    ((FT_UInt32*)out)[3] = h4;
    498  }
    499 
    500 
    501 #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
    502 
    503 
    504  typedef int (*char_type_func)( int  c );
    505 
    506 
    507  /* Handling of PID/EID 3/0 and 3/1 is the same. */
    508 #define IS_WIN( n )  ( (n)->platformID == 3                             && \
    509                       ( (n)->encodingID == 1 || (n)->encodingID == 0 ) )
    510 
    511 #define IS_APPLE( n )  ( (n)->platformID == 1 && \
    512                         (n)->encodingID == 0 )
    513 
    514  static char*
    515  get_win_string( FT_Memory       memory,
    516                  FT_Stream       stream,
    517                  TT_Name         entry,
    518                  char_type_func  char_type,
    519                  FT_Bool         report_invalid_characters )
    520  {
    521    FT_Error  error;
    522 
    523    char*       result = NULL;
    524    FT_String*  r;
    525    FT_Char*    p;
    526    FT_UInt     len;
    527 
    528 
    529    if ( FT_QALLOC( result, entry->stringLength / 2 + 1 ) )
    530      return NULL;
    531 
    532    if ( FT_STREAM_SEEK( entry->stringOffset ) ||
    533         FT_FRAME_ENTER( entry->stringLength ) )
    534      goto get_win_string_error;
    535 
    536    r = (FT_String*)result;
    537    p = (FT_Char*)stream->cursor;
    538 
    539    for ( len = entry->stringLength / 2; len > 0; len--, p += 2 )
    540    {
    541      if ( p[0] == 0 && char_type( p[1] ) )
    542        *r++ = p[1];
    543      else
    544      {
    545        if ( report_invalid_characters )
    546          FT_TRACE0(( "get_win_string:"
    547                      " Character 0x%X invalid in PS name string\n",
    548                      ((unsigned)p[0])*256 + (unsigned)p[1] ));
    549        continue;
    550      }
    551    }
    552    *r = '\0';
    553 
    554    FT_FRAME_EXIT();
    555 
    556    if ( r != result )
    557      return result;
    558 
    559  get_win_string_error:
    560    FT_FREE( result );
    561 
    562    entry->stringLength = 0;
    563    entry->stringOffset = 0;
    564    FT_FREE( entry->string );
    565 
    566    return NULL;
    567  }
    568 
    569 
    570  static char*
    571  get_apple_string( FT_Memory       memory,
    572                    FT_Stream       stream,
    573                    TT_Name         entry,
    574                    char_type_func  char_type,
    575                    FT_Bool         report_invalid_characters )
    576  {
    577    FT_Error  error;
    578 
    579    char*       result = NULL;
    580    FT_String*  r;
    581    FT_Char*    p;
    582    FT_UInt     len;
    583 
    584 
    585    if ( FT_QALLOC( result, entry->stringLength + 1 ) )
    586      return NULL;
    587 
    588    if ( FT_STREAM_SEEK( entry->stringOffset ) ||
    589         FT_FRAME_ENTER( entry->stringLength ) )
    590      goto get_apple_string_error;
    591 
    592    r = (FT_String*)result;
    593    p = (FT_Char*)stream->cursor;
    594 
    595    for ( len = entry->stringLength; len > 0; len--, p++ )
    596    {
    597      if ( char_type( *p ) )
    598        *r++ = *p;
    599      else
    600      {
    601        if ( report_invalid_characters )
    602          FT_TRACE0(( "get_apple_string:"
    603                      " Character `%c' (0x%X) invalid in PS name string\n",
    604                      *p, *p ));
    605        continue;
    606      }
    607    }
    608    *r = '\0';
    609 
    610    FT_FRAME_EXIT();
    611 
    612    if ( r != result )
    613      return result;
    614 
    615  get_apple_string_error:
    616    FT_FREE( result );
    617 
    618    entry->stringOffset = 0;
    619    entry->stringLength = 0;
    620    FT_FREE( entry->string );
    621 
    622    return NULL;
    623  }
    624 
    625 
    626  FT_CALLBACK_DEF( FT_Bool )
    627  sfnt_get_name_id( TT_Face    face,
    628                    FT_UShort  id,
    629                    FT_Int    *win,
    630                    FT_Int    *apple )
    631  {
    632    FT_Int  n;
    633 
    634 
    635    *win   = -1;
    636    *apple = -1;
    637 
    638    for ( n = 0; n < face->num_names; n++ )
    639    {
    640      TT_Name  name = face->name_table.names + n;
    641 
    642 
    643      if ( name->nameID == id && name->stringLength > 0 )
    644      {
    645        if ( IS_WIN( name ) && ( name->languageID == 0x409 || *win == -1 ) )
    646          *win = n;
    647 
    648        if ( IS_APPLE( name ) && ( name->languageID == 0 || *apple == -1 ) )
    649          *apple = n;
    650      }
    651    }
    652 
    653    return ( *win >= 0 ) || ( *apple >= 0 );
    654  }
    655 
    656 
    657 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
    658 
    659  /*
    660      The maximum length of an axis value descriptor.
    661 
    662      We need 65536 different values for the decimal fraction; this fits
    663      nicely into five decimal places.  Consequently, it consists of
    664 
    665        . the minus sign if the number is negative,
    666        . up to five characters for the digits before the decimal point,
    667        . the decimal point if there is a fractional part, and
    668        . up to five characters for the digits after the decimal point.
    669 
    670      We also need one byte for the leading `_' character and up to four
    671      bytes for the axis tag.
    672   */
    673 #define MAX_VALUE_DESCRIPTOR_LEN  ( 1 + 5 + 1 + 5 + 1 + 4 )
    674 
    675 
    676  /* the maximum length of PostScript font names */
    677 #define MAX_PS_NAME_LEN  127
    678 
    679 
    680  /*
    681   * Find the shortest decimal representation of a 16.16 fixed-point
    682   * number.  The function fills `buf' with the result, returning a pointer
    683   * to the position after the representation's last byte.
    684   */
    685 
    686  static char*
    687  fixed2float( FT_Int  fixed,
    688               char*   buf )
    689  {
    690    char*  p;
    691    char*  q;
    692    char   tmp[5];
    693 
    694    FT_Int  int_part;
    695    FT_Int  frac_part;
    696 
    697    FT_Int  i;
    698 
    699 
    700    p = buf;
    701 
    702    if ( fixed == 0 )
    703    {
    704      *p++ = '0';
    705      return p;
    706    }
    707 
    708    if ( fixed < 0 )
    709    {
    710      *p++ = '-';
    711      fixed = NEG_INT( fixed );
    712    }
    713 
    714    int_part  = ( fixed >> 16 ) & 0xFFFF;
    715    frac_part = fixed & 0xFFFF;
    716 
    717    /* get digits of integer part (in reverse order) */
    718    q = tmp;
    719    while ( int_part > 0 )
    720    {
    721      *q++      = '0' + int_part % 10;
    722      int_part /= 10;
    723    }
    724 
    725    /* copy digits in correct order to buffer */
    726    while ( q > tmp )
    727      *p++ = *--q;
    728 
    729    if ( !frac_part )
    730      return p;
    731 
    732    /* save position of point */
    733    q    = p;
    734    *p++ = '.';
    735 
    736    /* apply rounding */
    737    frac_part = frac_part * 10 + 5;
    738 
    739    /* get digits of fractional part */
    740    for ( i = 0; i < 5; i++ )
    741    {
    742      *p++ = '0' + (char)( frac_part / 0x10000L );
    743 
    744      frac_part %= 0x10000L;
    745      if ( !frac_part )
    746        break;
    747 
    748      frac_part *= 10;
    749    }
    750 
    751    /*
    752        If the remainder stored in `frac_part' (after the last FOR loop) is
    753        smaller than 34480*10, the resulting decimal value minus 0.00001 is
    754        an equivalent representation of `fixed'.
    755 
    756        The above FOR loop always finds the larger of the two values; I
    757        verified this by iterating over all possible fixed-point numbers.
    758 
    759        If the remainder is 17232*10, both values are equally good, and we
    760        take the next even number (following IEEE 754's `round to nearest,
    761        ties to even' rounding rule).
    762 
    763        If the remainder is smaller than 17232*10, the lower of the two
    764        numbers is nearer to the exact result (values 17232 and 34480 were
    765        also found by testing all possible fixed-point values).
    766 
    767        We use this to find a shorter decimal representation.  If not ending
    768        with digit zero, we take the representation with less error.
    769     */
    770    p--;
    771    if ( p - q == 5 )  /* five digits? */
    772    {
    773      /* take the representation that has zero as the last digit */
    774      if ( frac_part < 34480 * 10 &&
    775           *p == '1'              )
    776        *p = '0';
    777 
    778      /* otherwise use the one with less error */
    779      else if ( frac_part == 17232 * 10 &&
    780                *p & 1                  )
    781        *p -= 1;
    782 
    783      else if ( frac_part < 17232 * 10 &&
    784                *p != '0'              )
    785        *p -= 1;
    786    }
    787 
    788    /* remove trailing zeros */
    789    while ( *p == '0' )
    790      *p-- = '\0';
    791 
    792    return p + 1;
    793  }
    794 
    795 
    796  static const char  hexdigits[16] =
    797  {
    798    '0', '1', '2', '3', '4', '5', '6', '7',
    799    '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
    800  };
    801 
    802 
    803  static const char*
    804  sfnt_get_var_ps_name( TT_Face  face )
    805  {
    806    FT_Error   error;
    807    FT_Memory  memory = face->root.memory;
    808 
    809    FT_Service_MultiMasters  mm = (FT_Service_MultiMasters)face->mm;
    810 
    811    FT_UInt     num_coords;
    812    FT_Fixed*   coords;
    813    FT_MM_Var*  mm_var;
    814 
    815    FT_Int   found, win, apple;
    816    FT_UInt  i, j;
    817 
    818    char*  result = NULL;
    819    char*  p;
    820 
    821 
    822    if ( !face->var_postscript_prefix )
    823    {
    824      FT_UInt  len;
    825 
    826 
    827      /* check whether we have a Variations PostScript Name Prefix */
    828      found = sfnt_get_name_id( face,
    829                                TT_NAME_ID_VARIATIONS_PREFIX,
    830                                &win,
    831                                &apple );
    832      if ( !found )
    833      {
    834        /* otherwise use the typographic family name */
    835        found = sfnt_get_name_id( face,
    836                                  TT_NAME_ID_TYPOGRAPHIC_FAMILY,
    837                                  &win,
    838                                  &apple );
    839      }
    840 
    841      if ( !found )
    842      {
    843        /* according to the 'name' documentation in the OpenType   */
    844        /* specification the font family name is to be used if the */
    845        /* typographic family name is missing, so let's do that    */
    846        found = sfnt_get_name_id( face,
    847                                  TT_NAME_ID_FONT_FAMILY,
    848                                  &win,
    849                                  &apple );
    850      }
    851 
    852      if ( !found )
    853      {
    854        FT_TRACE0(( "sfnt_get_var_ps_name:"
    855                    " Can't construct PS name prefix for font instances\n" ));
    856        return NULL;
    857      }
    858 
    859      /* prefer Windows entries over Apple */
    860      if ( win != -1 )
    861        result = get_win_string( face->root.memory,
    862                                 face->name_table.stream,
    863                                 face->name_table.names + win,
    864                                 sfnt_is_alphanumeric,
    865                                 0 );
    866      if ( !result && apple != -1 )
    867        result = get_apple_string( face->root.memory,
    868                                   face->name_table.stream,
    869                                   face->name_table.names + apple,
    870                                   sfnt_is_alphanumeric,
    871                                   0 );
    872 
    873      if ( !result )
    874      {
    875        FT_TRACE0(( "sfnt_get_var_ps_name:"
    876                    " No valid PS name prefix for font instances found\n" ));
    877        /* XXX It probably makes sense to never let this fail */
    878        /*     since an arbitrary prefix should work, too.    */
    879        /*     On the other hand, it is very unlikely that    */
    880        /*     we ever reach this code at all.                */
    881        return NULL;
    882      }
    883 
    884      len = ft_strlen( result );
    885 
    886      /* sanitize if necessary; we reserve space for 36 bytes (a 128bit  */
    887      /* checksum as a hex number, preceded by `-' and followed by three */
    888      /* ASCII dots, to be used if the constructed PS name would be too  */
    889      /* long); this is also sufficient for a single instance            */
    890      if ( len > MAX_PS_NAME_LEN - ( 1 + 32 + 3 ) )
    891      {
    892        len         = MAX_PS_NAME_LEN - ( 1 + 32 + 3 );
    893        result[len] = '\0';
    894 
    895        FT_TRACE0(( "sfnt_get_var_ps_name:"
    896                    " Shortening variation PS name prefix\n" ));
    897        FT_TRACE0(( "                     "
    898                    " to %u characters\n", len ));
    899      }
    900 
    901      face->var_postscript_prefix     = result;
    902      face->var_postscript_prefix_len = len;
    903    }
    904 
    905    mm->get_var_blend( FT_FACE( face ),
    906                       &num_coords,
    907                       &coords,
    908                       NULL,
    909                       &mm_var );
    910 
    911    if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) &&
    912         !FT_IS_VARIATION( FT_FACE( face ) )     )
    913    {
    914      SFNT_Service  sfnt = (SFNT_Service)face->sfnt;
    915 
    916      FT_Long  instance = ( ( face->root.face_index & 0x7FFF0000L ) >> 16 ) - 1;
    917      FT_UInt  psid     = mm_var->namedstyle[instance].psid;
    918 
    919      char*  ps_name = NULL;
    920 
    921 
    922      /* try first to load the name string with index `postScriptNameID' */
    923      if ( psid == 6                      ||
    924           ( psid > 255 && psid < 32768 ) )
    925        (void)sfnt->get_name( face, (FT_UShort)psid, &ps_name );
    926 
    927      if ( ps_name )
    928      {
    929        result = ps_name;
    930        p      = result + ft_strlen( result ) + 1;
    931 
    932        goto check_length;
    933      }
    934      else
    935      {
    936        /* otherwise construct a name using `subfamilyNameID' */
    937        FT_UInt  strid = mm_var->namedstyle[instance].strid;
    938 
    939        char*  subfamily_name;
    940        char*  s;
    941 
    942 
    943        (void)sfnt->get_name( face, (FT_UShort)strid, &subfamily_name );
    944 
    945        if ( !subfamily_name )
    946        {
    947          FT_TRACE1(( "sfnt_get_var_ps_name:"
    948                      " can't construct named instance PS name;\n" ));
    949          FT_TRACE1(( "                     "
    950                      " trying to construct normal instance PS name\n" ));
    951          goto construct_instance_name;
    952        }
    953 
    954        /* after the prefix we have character `-' followed by the   */
    955        /* subfamily name (using only characters a-z, A-Z, and 0-9) */
    956        if ( FT_QALLOC( result, face->var_postscript_prefix_len +
    957                                1 + ft_strlen( subfamily_name ) + 1 ) )
    958          return NULL;
    959 
    960        ft_strcpy( result, face->var_postscript_prefix );
    961 
    962        p = result + face->var_postscript_prefix_len;
    963        *p++ = '-';
    964 
    965        s = subfamily_name;
    966        while ( *s )
    967        {
    968          if ( ft_isalnum( *s ) )
    969            *p++ = *s;
    970          s++;
    971        }
    972        *p++ = '\0';
    973 
    974        FT_FREE( subfamily_name );
    975      }
    976    }
    977    else
    978    {
    979      FT_Var_Axis*  axis;
    980 
    981 
    982    construct_instance_name:
    983      axis = mm_var->axis;
    984 
    985      if ( FT_QALLOC( result,
    986                      face->var_postscript_prefix_len +
    987                        num_coords * MAX_VALUE_DESCRIPTOR_LEN + 1 ) )
    988        return NULL;
    989 
    990      p = result;
    991 
    992      ft_strcpy( p, face->var_postscript_prefix );
    993      p += face->var_postscript_prefix_len;
    994 
    995      for ( i = 0; i < num_coords; i++, coords++, axis++ )
    996      {
    997        char  t;
    998 
    999 
   1000        /* omit axis value descriptor if it is identical */
   1001        /* to the default axis value                     */
   1002        if ( *coords == axis->def )
   1003          continue;
   1004 
   1005        *p++ = '_';
   1006        p    = fixed2float( *coords, p );
   1007 
   1008        t = (char)( axis->tag >> 24 );
   1009        if ( t != ' ' && ft_isalnum( t ) )
   1010          *p++ = t;
   1011        t = (char)( axis->tag >> 16 );
   1012        if ( t != ' ' && ft_isalnum( t ) )
   1013          *p++ = t;
   1014        t = (char)( axis->tag >> 8 );
   1015        if ( t != ' ' && ft_isalnum( t ) )
   1016          *p++ = t;
   1017        t = (char)axis->tag;
   1018        if ( t != ' ' && ft_isalnum( t ) )
   1019          *p++ = t;
   1020      }
   1021      *p++ = '\0';
   1022    }
   1023 
   1024  check_length:
   1025    if ( p - result > MAX_PS_NAME_LEN )
   1026    {
   1027      /* the PS name is too long; replace the part after the prefix with */
   1028      /* a checksum; we use MurmurHash 3 with a hash length of 128 bit   */
   1029 
   1030      FT_UInt32  seed = 123456789;
   1031 
   1032      FT_UInt32   hash[4];
   1033      FT_UInt32*  h;
   1034 
   1035 
   1036      murmur_hash_3_128( result, p - result, seed, hash );
   1037 
   1038      p = result + face->var_postscript_prefix_len;
   1039      *p++ = '-';
   1040 
   1041      /* we convert the hash value to hex digits from back to front */
   1042      p += 32 + 3;
   1043      h  = hash + 3;
   1044 
   1045      *p-- = '\0';
   1046      *p-- = '.';
   1047      *p-- = '.';
   1048      *p-- = '.';
   1049 
   1050      for ( i = 0; i < 4; i++, h-- )
   1051      {
   1052        FT_UInt32  v = *h;
   1053 
   1054 
   1055        for ( j = 0; j < 8; j++ )
   1056        {
   1057          *p--   = hexdigits[v & 0xF];
   1058          v    >>= 4;
   1059        }
   1060      }
   1061    }
   1062 
   1063    return result;
   1064  }
   1065 
   1066 #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
   1067 
   1068 
   1069  FT_CALLBACK_DEF( const char* )
   1070  sfnt_get_ps_name( FT_Face  face )    /* TT_Face */
   1071  {
   1072    TT_Face  ttface = (TT_Face)face;
   1073 
   1074    FT_Int       found, win, apple;
   1075    const char*  result = NULL;
   1076 
   1077 
   1078    if ( ttface->postscript_name )
   1079      return ttface->postscript_name;
   1080 
   1081 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
   1082    if ( ttface->blend                    &&
   1083         ( FT_IS_NAMED_INSTANCE( face ) ||
   1084           FT_IS_VARIATION( face )      ) )
   1085    {
   1086      ttface->postscript_name = sfnt_get_var_ps_name( ttface );
   1087      return ttface->postscript_name;
   1088    }
   1089 #endif
   1090 
   1091    /* scan the name table to see whether we have a Postscript name here, */
   1092    /* either in Macintosh or Windows platform encodings                  */
   1093    found = sfnt_get_name_id( ttface, TT_NAME_ID_PS_NAME, &win, &apple );
   1094    if ( !found )
   1095      return NULL;
   1096 
   1097    /* prefer Windows entries over Apple */
   1098    if ( win != -1 )
   1099      result = get_win_string( FT_FACE_MEMORY( face ),
   1100                               ttface->name_table.stream,
   1101                               ttface->name_table.names + win,
   1102                               sfnt_is_postscript,
   1103                               1 );
   1104    if ( !result && apple != -1 )
   1105      result = get_apple_string( FT_FACE_MEMORY( face ),
   1106                                 ttface->name_table.stream,
   1107                                 ttface->name_table.names + apple,
   1108                                 sfnt_is_postscript,
   1109                                 1 );
   1110 
   1111    ttface->postscript_name = result;
   1112 
   1113    return result;
   1114  }
   1115 
   1116 
   1117  FT_DEFINE_SERVICE_PSFONTNAMEREC(
   1118    sfnt_service_ps_name,
   1119 
   1120    sfnt_get_ps_name  /* FT_PsName_GetFunc get_ps_font_name */
   1121  )
   1122 
   1123 
   1124  /*
   1125   * TT CMAP INFO
   1126   */
   1127  FT_DEFINE_SERVICE_TTCMAPSREC(
   1128    tt_service_get_cmap_info,
   1129 
   1130    tt_get_cmap_info  /* TT_CMap_Info_GetFunc get_cmap_info */
   1131  )
   1132 
   1133 
   1134 #ifdef TT_CONFIG_OPTION_BDF
   1135 
   1136  static FT_Error
   1137  sfnt_get_charset_id( FT_Face       face,
   1138                       const char*  *acharset_encoding,
   1139                       const char*  *acharset_registry )
   1140  {
   1141    BDF_PropertyRec  encoding, registry;
   1142    FT_Error         error;
   1143 
   1144 
   1145    /* XXX: I don't know whether this is correct, since
   1146     *      tt_face_find_bdf_prop only returns something correct if we have
   1147     *      previously selected a size that is listed in the BDF table.
   1148     *      Should we change the BDF table format to include single offsets
   1149     *      for `CHARSET_REGISTRY' and `CHARSET_ENCODING'?
   1150     */
   1151    error = tt_face_find_bdf_prop( face, "CHARSET_REGISTRY", &registry );
   1152    if ( !error )
   1153    {
   1154      error = tt_face_find_bdf_prop( face, "CHARSET_ENCODING", &encoding );
   1155      if ( !error )
   1156      {
   1157        if ( registry.type == BDF_PROPERTY_TYPE_ATOM &&
   1158             encoding.type == BDF_PROPERTY_TYPE_ATOM )
   1159        {
   1160          *acharset_encoding = encoding.u.atom;
   1161          *acharset_registry = registry.u.atom;
   1162        }
   1163        else
   1164          error = FT_THROW( Invalid_Argument );
   1165      }
   1166    }
   1167 
   1168    return error;
   1169  }
   1170 
   1171 
   1172  FT_DEFINE_SERVICE_BDFRec(
   1173    sfnt_service_bdf,
   1174 
   1175    sfnt_get_charset_id,   /* FT_BDF_GetCharsetIdFunc get_charset_id */
   1176    tt_face_find_bdf_prop  /* FT_BDF_GetPropertyFunc  get_property   */
   1177  )
   1178 
   1179 
   1180 #endif /* TT_CONFIG_OPTION_BDF */
   1181 
   1182 
   1183  /*
   1184   * SERVICE LIST
   1185   */
   1186 
   1187 #if defined TT_CONFIG_OPTION_POSTSCRIPT_NAMES && defined TT_CONFIG_OPTION_BDF
   1188  FT_DEFINE_SERVICEDESCREC5(
   1189    sfnt_services,
   1190 
   1191    FT_SERVICE_ID_SFNT_TABLE,           &sfnt_service_sfnt_table,
   1192    FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &sfnt_service_ps_name,
   1193    FT_SERVICE_ID_GLYPH_DICT,           &sfnt_service_glyph_dict,
   1194    FT_SERVICE_ID_BDF,                  &sfnt_service_bdf,
   1195    FT_SERVICE_ID_TT_CMAP,              &tt_service_get_cmap_info )
   1196 #elif defined TT_CONFIG_OPTION_POSTSCRIPT_NAMES
   1197  FT_DEFINE_SERVICEDESCREC4(
   1198    sfnt_services,
   1199 
   1200    FT_SERVICE_ID_SFNT_TABLE,           &sfnt_service_sfnt_table,
   1201    FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &sfnt_service_ps_name,
   1202    FT_SERVICE_ID_GLYPH_DICT,           &sfnt_service_glyph_dict,
   1203    FT_SERVICE_ID_TT_CMAP,              &tt_service_get_cmap_info )
   1204 #elif defined TT_CONFIG_OPTION_BDF
   1205  FT_DEFINE_SERVICEDESCREC4(
   1206    sfnt_services,
   1207 
   1208    FT_SERVICE_ID_SFNT_TABLE,           &sfnt_service_sfnt_table,
   1209    FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &sfnt_service_ps_name,
   1210    FT_SERVICE_ID_BDF,                  &sfnt_service_bdf,
   1211    FT_SERVICE_ID_TT_CMAP,              &tt_service_get_cmap_info )
   1212 #else
   1213  FT_DEFINE_SERVICEDESCREC3(
   1214    sfnt_services,
   1215 
   1216    FT_SERVICE_ID_SFNT_TABLE,           &sfnt_service_sfnt_table,
   1217    FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &sfnt_service_ps_name,
   1218    FT_SERVICE_ID_TT_CMAP,              &tt_service_get_cmap_info )
   1219 #endif
   1220 
   1221 
   1222  FT_CALLBACK_DEF( FT_Module_Interface )
   1223  sfnt_get_interface( FT_Module    module,
   1224                      const char*  module_interface )
   1225  {
   1226    FT_UNUSED( module );
   1227 
   1228    return ft_service_list_lookup( sfnt_services, module_interface );
   1229  }
   1230 
   1231 
   1232 #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
   1233 #define PUT_EMBEDDED_BITMAPS( a )  a
   1234 #else
   1235 #define PUT_EMBEDDED_BITMAPS( a )  NULL
   1236 #endif
   1237 
   1238 #ifdef TT_CONFIG_OPTION_COLOR_LAYERS
   1239 #define PUT_COLOR_LAYERS( a )  a
   1240 #else
   1241 #define PUT_COLOR_LAYERS( a )  NULL
   1242 #endif
   1243 
   1244 #ifdef FT_CONFIG_OPTION_SVG
   1245 #define PUT_SVG_SUPPORT( a )  a
   1246 #else
   1247 #define PUT_SVG_SUPPORT( a )  NULL
   1248 #endif
   1249 
   1250 #define PUT_COLOR_LAYERS_V1( a )  PUT_COLOR_LAYERS( a )
   1251 
   1252 #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
   1253 #define PUT_PS_NAMES( a )  a
   1254 #else
   1255 #define PUT_PS_NAMES( a )  NULL
   1256 #endif
   1257 
   1258 #ifdef TT_CONFIG_OPTION_GPOS_KERNING
   1259 #define PUT_GPOS_KERNING( a )  a
   1260 #else
   1261 #define PUT_GPOS_KERNING( a )  NULL
   1262 #endif
   1263 
   1264  FT_DEFINE_SFNT_INTERFACE(
   1265    sfnt_interface,
   1266 
   1267    tt_face_goto_table,     /* TT_Loader_GotoTableFunc goto_table      */
   1268 
   1269    sfnt_init_face,         /* TT_Init_Face_Func       init_face       */
   1270    sfnt_load_face,         /* TT_Load_Face_Func       load_face       */
   1271    sfnt_done_face,         /* TT_Done_Face_Func       done_face       */
   1272    sfnt_get_interface,     /* FT_Module_Requester     get_interface   */
   1273 
   1274    tt_face_load_any,       /* TT_Load_Any_Func        load_any        */
   1275 
   1276    tt_face_load_head,      /* TT_Load_Table_Func      load_head       */
   1277    tt_face_load_hhea,      /* TT_Load_Metrics_Func    load_hhea       */
   1278    tt_face_load_cmap,      /* TT_Load_Table_Func      load_cmap       */
   1279    tt_face_load_maxp,      /* TT_Load_Table_Func      load_maxp       */
   1280    tt_face_load_os2,       /* TT_Load_Table_Func      load_os2        */
   1281    tt_face_load_post,      /* TT_Load_Table_Func      load_post       */
   1282 
   1283    tt_face_load_name,      /* TT_Load_Table_Func      load_name       */
   1284    tt_face_free_name,      /* TT_Free_Table_Func      free_name       */
   1285 
   1286    tt_face_load_kern,      /* TT_Load_Table_Func      load_kern       */
   1287    PUT_GPOS_KERNING( tt_face_load_gpos ),
   1288                            /* TT_Load_Table_Func      load_gpos       */
   1289    tt_face_load_gasp,      /* TT_Load_Table_Func      load_gasp       */
   1290    tt_face_load_pclt,      /* TT_Load_Table_Func      load_init       */
   1291 
   1292    /* see `ttload.h' */
   1293    PUT_EMBEDDED_BITMAPS( tt_face_load_bhed ),
   1294                            /* TT_Load_Table_Func      load_bhed       */
   1295    PUT_EMBEDDED_BITMAPS( tt_face_load_sbit_image ),
   1296                            /* TT_Load_SBit_Image_Func load_sbit_image */
   1297 
   1298    /* see `ttpost.h' */
   1299    PUT_PS_NAMES( tt_face_get_ps_name   ),
   1300                            /* TT_Get_PS_Name_Func     get_psname      */
   1301    PUT_PS_NAMES( tt_face_free_ps_names ),
   1302                            /* TT_Free_Table_Func      free_psnames    */
   1303 
   1304    /* since version 2.1.8 */
   1305    tt_face_get_kerning,    /* TT_Face_GetKerningFunc  get_kerning     */
   1306 
   1307    PUT_GPOS_KERNING( tt_face_get_gpos_kerning ),
   1308                           /* TT_Face_GetKerningFunc  get_gpos_kerning */
   1309 
   1310    /* since version 2.2 */
   1311    tt_face_load_font_dir,  /* TT_Load_Table_Func      load_font_dir   */
   1312    tt_face_load_hmtx,      /* TT_Load_Metrics_Func    load_hmtx       */
   1313 
   1314    /* see `ttsbit.h' and `sfnt.h' */
   1315    PUT_EMBEDDED_BITMAPS( tt_face_load_sbit ),
   1316                            /* TT_Load_Table_Func      load_eblc       */
   1317    PUT_EMBEDDED_BITMAPS( tt_face_free_sbit ),
   1318                            /* TT_Free_Table_Func      free_eblc       */
   1319 
   1320    PUT_EMBEDDED_BITMAPS( tt_face_set_sbit_strike     ),
   1321                  /* TT_Set_SBit_Strike_Func      set_sbit_strike      */
   1322    PUT_EMBEDDED_BITMAPS( tt_face_load_strike_metrics ),
   1323                  /* TT_Load_Strike_Metrics_Func  load_strike_metrics  */
   1324 
   1325    PUT_COLOR_LAYERS( tt_face_load_cpal ),
   1326                            /* TT_Load_Table_Func      load_cpal       */
   1327    PUT_COLOR_LAYERS( tt_face_load_colr ),
   1328                            /* TT_Load_Table_Func      load_colr       */
   1329    PUT_COLOR_LAYERS( tt_face_free_cpal ),
   1330                            /* TT_Free_Table_Func      free_cpal       */
   1331    PUT_COLOR_LAYERS( tt_face_free_colr ),
   1332                            /* TT_Free_Table_Func      free_colr       */
   1333    PUT_COLOR_LAYERS( tt_face_palette_set ),
   1334                            /* TT_Set_Palette_Func     set_palette     */
   1335    PUT_COLOR_LAYERS( tt_face_get_colr_layer ),
   1336                            /* TT_Get_Colr_Layer_Func  get_colr_layer  */
   1337 
   1338    PUT_COLOR_LAYERS_V1( tt_face_get_colr_glyph_paint ),
   1339              /* TT_Get_Color_Glyph_Paint_Func    get_colr_glyph_paint */
   1340    PUT_COLOR_LAYERS_V1( tt_face_get_color_glyph_clipbox ),
   1341              /* TT_Get_Color_Glyph_ClipBox_Func  get_clipbox          */
   1342    PUT_COLOR_LAYERS_V1( tt_face_get_paint_layers ),
   1343              /* TT_Get_Paint_Layers_Func         get_paint_layers     */
   1344    PUT_COLOR_LAYERS_V1( tt_face_get_colorline_stops ),
   1345              /* TT_Get_Paint                     get_paint            */
   1346    PUT_COLOR_LAYERS_V1( tt_face_get_paint ),
   1347              /* TT_Get_Colorline_Stops_Func      get_colorline_stops  */
   1348 
   1349    PUT_COLOR_LAYERS( tt_face_colr_blend_layer ),
   1350                            /* TT_Blend_Colr_Func      colr_blend      */
   1351 
   1352    tt_face_get_metrics,    /* TT_Get_Metrics_Func     get_metrics     */
   1353 
   1354    tt_face_get_name,       /* TT_Get_Name_Func        get_name        */
   1355    sfnt_get_name_id,       /* TT_Get_Name_ID_Func     get_name_id     */
   1356 
   1357    PUT_SVG_SUPPORT( tt_face_load_svg ),
   1358                            /* TT_Load_Table_Func      load_svg        */
   1359    PUT_SVG_SUPPORT( tt_face_free_svg ),
   1360                            /* TT_Free_Table_Func      free_svg        */
   1361    PUT_SVG_SUPPORT( tt_face_load_svg_doc )
   1362                            /* TT_Load_Svg_Doc_Func    load_svg_doc    */
   1363  )
   1364 
   1365 
   1366  FT_DEFINE_MODULE(
   1367    sfnt_module_class,
   1368 
   1369    0,  /* not a font driver or renderer */
   1370    sizeof ( FT_ModuleRec ),
   1371 
   1372    "sfnt",     /* driver name                            */
   1373    0x10000L,   /* driver version 1.0                     */
   1374    0x20000L,   /* driver requires FreeType 2.0 or higher */
   1375 
   1376    (const void*)&sfnt_interface,  /* module specific interface */
   1377 
   1378    NULL,               /* FT_Module_Constructor module_init   */
   1379    NULL,               /* FT_Module_Destructor  module_done   */
   1380    sfnt_get_interface  /* FT_Module_Requester   get_interface */
   1381  )
   1382 
   1383 
   1384 /* END */