1 /****************************************************************************
   2  *
   3  * psmodule.c
   4  *
   5  *   psnames module implementation (body).
   6  *
   7  * Copyright (C) 1996-2019 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 */