tor-browser

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

psmodule.c (16268B)


      1 /****************************************************************************
      2 *
      3 * psmodule.c
      4 *
      5 *   psnames module implementation (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/ftobjs.h>
     21 #include <freetype/internal/services/svpscmap.h>
     22 
     23 #include "psmodule.h"
     24 
     25  /*
     26   * The file `pstables.h' with its arrays and its function
     27   * `ft_get_adobe_glyph_index' is useful for other projects also (for
     28   * example, `pdfium' is using it).  However, if used as a C++ header,
     29   * including it in two different source files makes it necessary to use
     30   * `extern const' for the declaration of its arrays, otherwise the data
     31   * would be duplicated as mandated by the C++ standard.
     32   *
     33   * For this reason, we use `DEFINE_PS_TABLES' to guard the function
     34   * definitions, and `DEFINE_PS_TABLES_DATA' to provide both proper array
     35   * declarations and definitions.
     36   */
     37 #include "pstables.h"
     38 #define  DEFINE_PS_TABLES
     39 #define  DEFINE_PS_TABLES_DATA
     40 #include "pstables.h"
     41 
     42 #include "psnamerr.h"
     43 
     44 
     45 #ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES
     46 
     47 
     48 #ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST
     49 
     50 
     51 #define VARIANT_BIT         0x80000000UL
     52 #define BASE_GLYPH( code )  ( (FT_UInt32)( (code) & ~VARIANT_BIT ) )
     53 
     54 
     55  /* Return the Unicode value corresponding to a given glyph.  Note that */
     56  /* we do deal with glyph variants by detecting a non-initial dot in    */
     57  /* the name, as in `A.swash' or `e.final'; in this case, the           */
     58  /* VARIANT_BIT is set in the return value.                             */
     59  /*                                                                     */
     60  FT_CALLBACK_DEF( FT_UInt32 )
     61  ps_unicode_value( const char*  glyph_name )
     62  {
     63    /* If the name begins with `uni', then the glyph name may be a */
     64    /* hard-coded unicode character code.                          */
     65    if ( glyph_name[0] == 'u' &&
     66         glyph_name[1] == 'n' &&
     67         glyph_name[2] == 'i' )
     68    {
     69      /* determine whether the next four characters following are */
     70      /* hexadecimal.                                             */
     71 
     72      /* XXX: Add code to deal with ligatures, i.e. glyph names like */
     73      /*      `uniXXXXYYYYZZZZ'...                                   */
     74 
     75      FT_Int       count;
     76      FT_UInt32    value = 0;
     77      const char*  p     = glyph_name + 3;
     78 
     79 
     80      for ( count = 4; count > 0; count--, p++ )
     81      {
     82        char          c = *p;
     83        unsigned int  d;
     84 
     85 
     86        d = (unsigned char)c - '0';
     87        if ( d >= 10 )
     88        {
     89          d = (unsigned char)c - 'A';
     90          if ( d >= 6 )
     91            d = 16;
     92          else
     93            d += 10;
     94        }
     95 
     96        /* Exit if a non-uppercase hexadecimal character was found   */
     97        /* -- this also catches character codes below `0' since such */
     98        /* negative numbers cast to `unsigned int' are far too big.  */
     99        if ( d >= 16 )
    100          break;
    101 
    102        value = ( value << 4 ) + d;
    103      }
    104 
    105      /* there must be exactly four hex digits */
    106      if ( count == 0 )
    107      {
    108        if ( *p == '\0' )
    109          return value;
    110        if ( *p == '.' )
    111          return (FT_UInt32)( value | VARIANT_BIT );
    112      }
    113    }
    114 
    115    /* If the name begins with `u', followed by four to six uppercase */
    116    /* hexadecimal digits, it is a hard-coded unicode character code. */
    117    if ( glyph_name[0] == 'u' )
    118    {
    119      FT_Int       count;
    120      FT_UInt32    value = 0;
    121      const char*  p     = glyph_name + 1;
    122 
    123 
    124      for ( count = 6; count > 0; count--, p++ )
    125      {
    126        char          c = *p;
    127        unsigned int  d;
    128 
    129 
    130        d = (unsigned char)c - '0';
    131        if ( d >= 10 )
    132        {
    133          d = (unsigned char)c - 'A';
    134          if ( d >= 6 )
    135            d = 16;
    136          else
    137            d += 10;
    138        }
    139 
    140        if ( d >= 16 )
    141          break;
    142 
    143        value = ( value << 4 ) + d;
    144      }
    145 
    146      if ( count <= 2 )
    147      {
    148        if ( *p == '\0' )
    149          return value;
    150        if ( *p == '.' )
    151          return (FT_UInt32)( value | VARIANT_BIT );
    152      }
    153    }
    154 
    155    /* Look for a non-initial dot in the glyph name in order to */
    156    /* find variants like `A.swash', `e.final', etc.            */
    157    {
    158      FT_UInt32    value = 0;
    159      const char*  p     = glyph_name;
    160 
    161 
    162      for ( ; *p && *p != '.'; p++ )
    163        ;
    164 
    165      /* now look up the glyph in the Adobe Glyph List;      */
    166      /* `.notdef', `.null' and the empty name are short cut */
    167      if ( p > glyph_name )
    168      {
    169        value = (FT_UInt32)ft_get_adobe_glyph_index( glyph_name, p );
    170 
    171        if ( *p == '.' )
    172          value |= (FT_UInt32)VARIANT_BIT;
    173      }
    174 
    175      return value;
    176    }
    177  }
    178 
    179 
    180  /* ft_qsort callback to sort the unicode map */
    181  FT_COMPARE_DEF( int )
    182  compare_uni_maps( const void*  a,
    183                    const void*  b )
    184  {
    185    PS_UniMap*  map1 = (PS_UniMap*)a;
    186    PS_UniMap*  map2 = (PS_UniMap*)b;
    187    FT_UInt32   unicode1 = BASE_GLYPH( map1->unicode );
    188    FT_UInt32   unicode2 = BASE_GLYPH( map2->unicode );
    189 
    190 
    191    /* sort base glyphs before glyph variants */
    192    if ( unicode1 == unicode2 )
    193    {
    194      if ( map1->unicode > map2->unicode )
    195        return 1;
    196      else if ( map1->unicode < map2->unicode )
    197        return -1;
    198      else
    199        return 0;
    200    }
    201    else
    202    {
    203      if ( unicode1 > unicode2 )
    204        return 1;
    205      else if ( unicode1 < unicode2 )
    206        return -1;
    207      else
    208        return 0;
    209    }
    210  }
    211 
    212 
    213  /* support for extra glyphs not handled (well) in AGL; */
    214  /* we add extra mappings for them if necessary         */
    215 
    216 #define EXTRA_GLYPH_LIST_SIZE  10
    217 
    218  static const FT_UInt32  ft_extra_glyph_unicodes[EXTRA_GLYPH_LIST_SIZE] =
    219  {
    220    /* WGL 4 */
    221    0x0394,
    222    0x03A9,
    223    0x2215,
    224    0x00AD,
    225    0x02C9,
    226    0x03BC,
    227    0x2219,
    228    0x00A0,
    229    /* Romanian */
    230    0x021A,
    231    0x021B
    232  };
    233 
    234  static const char  ft_extra_glyph_names[] =
    235  {
    236    'D','e','l','t','a',0,
    237    'O','m','e','g','a',0,
    238    'f','r','a','c','t','i','o','n',0,
    239    'h','y','p','h','e','n',0,
    240    'm','a','c','r','o','n',0,
    241    'm','u',0,
    242    'p','e','r','i','o','d','c','e','n','t','e','r','e','d',0,
    243    's','p','a','c','e',0,
    244    'T','c','o','m','m','a','a','c','c','e','n','t',0,
    245    't','c','o','m','m','a','a','c','c','e','n','t',0
    246  };
    247 
    248  static const FT_Int
    249  ft_extra_glyph_name_offsets[EXTRA_GLYPH_LIST_SIZE] =
    250  {
    251     0,
    252     6,
    253    12,
    254    21,
    255    28,
    256    35,
    257    38,
    258    53,
    259    59,
    260    72
    261  };
    262 
    263 
    264  static void
    265  ps_check_extra_glyph_name( const char*  gname,
    266                             FT_UInt      glyph,
    267                             FT_UInt*     extra_glyphs,
    268                             FT_UInt     *states )
    269  {
    270    FT_UInt  n;
    271 
    272 
    273    for ( n = 0; n < EXTRA_GLYPH_LIST_SIZE; n++ )
    274    {
    275      if ( ft_strcmp( ft_extra_glyph_names +
    276                        ft_extra_glyph_name_offsets[n], gname ) == 0 )
    277      {
    278        if ( states[n] == 0 )
    279        {
    280          /* mark this extra glyph as a candidate for the cmap */
    281          states[n]     = 1;
    282          extra_glyphs[n] = glyph;
    283        }
    284 
    285        return;
    286      }
    287    }
    288  }
    289 
    290 
    291  static void
    292  ps_check_extra_glyph_unicode( FT_UInt32  uni_char,
    293                                FT_UInt   *states )
    294  {
    295    FT_UInt  n;
    296 
    297 
    298    for ( n = 0; n < EXTRA_GLYPH_LIST_SIZE; n++ )
    299    {
    300      if ( uni_char == ft_extra_glyph_unicodes[n] )
    301      {
    302        /* disable this extra glyph from being added to the cmap */
    303        states[n] = 2;
    304 
    305        return;
    306      }
    307    }
    308  }
    309 
    310 
    311  /* Build a table that maps Unicode values to glyph indices. */
    312  FT_CALLBACK_DEF( FT_Error )
    313  ps_unicodes_init( FT_Memory             memory,
    314                    PS_Unicodes           table,
    315                    FT_UInt               num_glyphs,
    316                    PS_GetGlyphNameFunc   get_glyph_name,
    317                    PS_FreeGlyphNameFunc  free_glyph_name,
    318                    FT_Pointer            glyph_data )
    319  {
    320    FT_Error  error;
    321 
    322    FT_UInt  extra_glyph_list_states[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
    323    FT_UInt  extra_glyphs[EXTRA_GLYPH_LIST_SIZE];
    324 
    325 
    326    /* we first allocate the table */
    327    table->num_maps = 0;
    328 
    329    if ( !FT_QNEW_ARRAY( table->maps, num_glyphs + EXTRA_GLYPH_LIST_SIZE ) )
    330    {
    331      FT_UInt     n;
    332      FT_UInt     count;
    333      PS_UniMap*  map;
    334      FT_UInt32   uni_char;
    335 
    336 
    337      map = table->maps;
    338 
    339      for ( n = 0; n < num_glyphs; n++ )
    340      {
    341        const char*  gname = get_glyph_name( glyph_data, n );
    342 
    343 
    344        if ( gname && *gname )
    345        {
    346          ps_check_extra_glyph_name( gname, n,
    347                                     extra_glyphs, extra_glyph_list_states );
    348          uni_char = ps_unicode_value( gname );
    349 
    350          if ( BASE_GLYPH( uni_char ) != 0 )
    351          {
    352            ps_check_extra_glyph_unicode( uni_char,
    353                                          extra_glyph_list_states );
    354            map->unicode     = uni_char;
    355            map->glyph_index = n;
    356            map++;
    357          }
    358 
    359          if ( free_glyph_name )
    360            free_glyph_name( glyph_data, gname );
    361        }
    362      }
    363 
    364      for ( n = 0; n < EXTRA_GLYPH_LIST_SIZE; n++ )
    365      {
    366        if ( extra_glyph_list_states[n] == 1 )
    367        {
    368          /* This glyph name has an additional representation. */
    369          /* Add it to the cmap.                               */
    370 
    371          map->unicode     = ft_extra_glyph_unicodes[n];
    372          map->glyph_index = extra_glyphs[n];
    373          map++;
    374        }
    375      }
    376 
    377      /* now compress the table a bit */
    378      count = (FT_UInt)( map - table->maps );
    379 
    380      if ( count == 0 )
    381      {
    382        /* No unicode chars here! */
    383        FT_FREE( table->maps );
    384        if ( !error )
    385          error = FT_THROW( No_Unicode_Glyph_Name );
    386      }
    387      else
    388      {
    389        /* Reallocate if the number of used entries is much smaller. */
    390        if ( count < num_glyphs / 2 )
    391        {
    392          FT_MEM_QRENEW_ARRAY( table->maps,
    393                               num_glyphs + EXTRA_GLYPH_LIST_SIZE,
    394                               count );
    395          error = FT_Err_Ok;
    396        }
    397 
    398        /* Sort the table in increasing order of unicode values, */
    399        /* taking care of glyph variants.                        */
    400        ft_qsort( table->maps, count, sizeof ( PS_UniMap ),
    401                  compare_uni_maps );
    402      }
    403 
    404      table->num_maps = count;
    405    }
    406 
    407    return error;
    408  }
    409 
    410 
    411  FT_CALLBACK_DEF( FT_UInt )
    412  ps_unicodes_char_index( PS_Unicodes  table,
    413                          FT_UInt32    unicode )
    414  {
    415    PS_UniMap  *result = NULL;
    416    PS_UniMap  *min = table->maps;
    417    PS_UniMap  *max = min + table->num_maps;
    418    PS_UniMap  *mid = min + ( ( max - min ) >> 1 );
    419 
    420 
    421    /* Perform a binary search on the table. */
    422    while ( min < max )
    423    {
    424      FT_UInt32  base_glyph;
    425 
    426 
    427      if ( mid->unicode == unicode )
    428      {
    429        result = mid;
    430        break;
    431      }
    432 
    433      base_glyph = BASE_GLYPH( mid->unicode );
    434 
    435      if ( base_glyph == unicode )
    436        result = mid; /* remember match but continue search for base glyph */
    437 
    438      if ( base_glyph < unicode )
    439        min = mid + 1;
    440      else
    441        max = mid;
    442 
    443      /* reasonable prediction in a continuous block */
    444      mid += unicode - base_glyph;
    445      if ( mid >= max || mid < min )
    446        mid = min + ( ( max - min ) >> 1 );
    447    }
    448 
    449    if ( result )
    450      return result->glyph_index;
    451    else
    452      return 0;
    453  }
    454 
    455 
    456  FT_CALLBACK_DEF( FT_UInt )
    457  ps_unicodes_char_next( PS_Unicodes  table,
    458                         FT_UInt32   *unicode )
    459  {
    460    FT_UInt    result    = 0;
    461    FT_UInt32  char_code = *unicode + 1;
    462 
    463 
    464    {
    465      FT_UInt     min = 0;
    466      FT_UInt     max = table->num_maps;
    467      FT_UInt     mid = min + ( ( max - min ) >> 1 );
    468      PS_UniMap*  map;
    469      FT_UInt32   base_glyph;
    470 
    471 
    472      while ( min < max )
    473      {
    474        map = table->maps + mid;
    475 
    476        if ( map->unicode == char_code )
    477        {
    478          result = map->glyph_index;
    479          goto Exit;
    480        }
    481 
    482        base_glyph = BASE_GLYPH( map->unicode );
    483 
    484        if ( base_glyph == char_code )
    485          result = map->glyph_index;
    486 
    487        if ( base_glyph < char_code )
    488          min = mid + 1;
    489        else
    490          max = mid;
    491 
    492        /* reasonable prediction in a continuous block */
    493        mid += char_code - base_glyph;
    494        if ( mid >= max || mid < min )
    495          mid = min + ( max - min ) / 2;
    496      }
    497 
    498      if ( result )
    499        goto Exit;               /* we have a variant glyph */
    500 
    501      /* we didn't find it; check whether we have a map just above it */
    502      char_code = 0;
    503 
    504      if ( min < table->num_maps )
    505      {
    506        map       = table->maps + min;
    507        result    = map->glyph_index;
    508        char_code = BASE_GLYPH( map->unicode );
    509      }
    510    }
    511 
    512  Exit:
    513    *unicode = char_code;
    514    return result;
    515  }
    516 
    517 
    518 #endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */
    519 
    520 
    521  FT_CALLBACK_DEF( const char* )
    522  ps_get_macintosh_name( FT_UInt  name_index )
    523  {
    524    if ( name_index >= FT_NUM_MAC_NAMES )
    525      name_index = 0;
    526 
    527    return ft_standard_glyph_names + ft_mac_names[name_index];
    528  }
    529 
    530 
    531  FT_CALLBACK_DEF( const char* )
    532  ps_get_standard_strings( FT_UInt  sid )
    533  {
    534    if ( sid >= FT_NUM_SID_NAMES )
    535      return 0;
    536 
    537    return ft_standard_glyph_names + ft_sid_names[sid];
    538  }
    539 
    540 
    541 #ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST
    542 
    543  FT_DEFINE_SERVICE_PSCMAPSREC(
    544    pscmaps_interface,
    545 
    546    ps_unicode_value,         /* PS_Unicode_ValueFunc      unicode_value         */
    547    ps_unicodes_init,         /* PS_Unicodes_InitFunc      unicodes_init         */
    548    ps_unicodes_char_index,   /* PS_Unicodes_CharIndexFunc unicodes_char_index   */
    549    ps_unicodes_char_next,    /* PS_Unicodes_CharNextFunc  unicodes_char_next    */
    550 
    551    ps_get_macintosh_name,    /* PS_Macintosh_NameFunc     macintosh_name        */
    552    ps_get_standard_strings,  /* PS_Adobe_Std_StringsFunc  adobe_std_strings     */
    553 
    554    t1_standard_encoding,                               /* adobe_std_encoding    */
    555    t1_expert_encoding                                  /* adobe_expert_encoding */
    556  )
    557 
    558 #else
    559 
    560  FT_DEFINE_SERVICE_PSCMAPSREC(
    561    pscmaps_interface,
    562 
    563    NULL,                     /* PS_Unicode_ValueFunc      unicode_value         */
    564    NULL,                     /* PS_Unicodes_InitFunc      unicodes_init         */
    565    NULL,                     /* PS_Unicodes_CharIndexFunc unicodes_char_index   */
    566    NULL,                     /* PS_Unicodes_CharNextFunc  unicodes_char_next    */
    567 
    568    ps_get_macintosh_name,    /* PS_Macintosh_NameFunc     macintosh_name        */
    569    ps_get_standard_strings,  /* PS_Adobe_Std_StringsFunc  adobe_std_strings     */
    570 
    571    t1_standard_encoding,                               /* adobe_std_encoding    */
    572    t1_expert_encoding                                  /* adobe_expert_encoding */
    573  )
    574 
    575 #endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */
    576 
    577 
    578  FT_DEFINE_SERVICEDESCREC1(
    579    pscmaps_services,
    580 
    581    FT_SERVICE_ID_POSTSCRIPT_CMAPS, &pscmaps_interface )
    582 
    583 
    584  static FT_Pointer
    585  psnames_get_service( FT_Module    module,
    586                       const char*  service_id )
    587  {
    588    FT_UNUSED( module );
    589 
    590    return ft_service_list_lookup( pscmaps_services, service_id );
    591  }
    592 
    593 #endif /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES */
    594 
    595 
    596 #ifndef FT_CONFIG_OPTION_POSTSCRIPT_NAMES
    597 #define PUT_PS_NAMES_SERVICE( a )  NULL
    598 #else
    599 #define PUT_PS_NAMES_SERVICE( a )  a
    600 #endif
    601 
    602  FT_DEFINE_MODULE(
    603    psnames_module_class,
    604 
    605    0,  /* this is not a font driver, nor a renderer */
    606    sizeof ( FT_ModuleRec ),
    607 
    608    "psnames",  /* driver name                         */
    609    0x10000L,   /* driver version                      */
    610    0x20000L,   /* driver requires FreeType 2 or above */
    611 
    612    PUT_PS_NAMES_SERVICE(
    613      (void*)&pscmaps_interface ),   /* module specific interface */
    614 
    615    NULL,                                        /* FT_Module_Constructor module_init   */
    616    NULL,                                        /* FT_Module_Destructor  module_done   */
    617    PUT_PS_NAMES_SERVICE( psnames_get_service )  /* FT_Module_Requester   get_interface */
    618  )
    619 
    620 
    621 /* END */