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