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