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