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