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 */