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