1 /***************************************************************************/ 2 /* */ 3 /* ttcmap.c */ 4 /* */ 5 /* TrueType character mapping table (cmap) support (body). */ 6 /* */ 7 /* Copyright 1996-2001, 2002 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 "ttload.h" 22 #include "ttcmap.h" 23 24 #include "sferrors.h" 25 26 27 /*************************************************************************/ 28 /* */ 29 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 30 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 31 /* messages during execution. */ 32 /* */ 33 #undef FT_COMPONENT 34 #define FT_COMPONENT trace_ttcmap 35 36 37 FT_CALLBACK_DEF( FT_UInt ) 38 code_to_index0( TT_CMapTable charmap, 39 FT_ULong char_code ); 40 41 FT_CALLBACK_DEF( FT_ULong ) 42 code_to_next0( TT_CMapTable charmap, 43 FT_ULong char_code ); 44 45 FT_CALLBACK_DEF( FT_UInt ) 46 code_to_index2( TT_CMapTable charmap, 47 FT_ULong char_code ); 48 49 FT_CALLBACK_DEF( FT_ULong ) 50 code_to_next2( TT_CMapTable charmap, 51 FT_ULong char_code ); 52 53 FT_CALLBACK_DEF( FT_UInt ) 54 code_to_index4( TT_CMapTable charmap, 55 FT_ULong char_code ); 56 57 FT_CALLBACK_DEF( FT_ULong ) 58 code_to_next4( TT_CMapTable charmap, 59 FT_ULong char_code ); 60 61 FT_CALLBACK_DEF( FT_UInt ) 62 code_to_index6( TT_CMapTable charmap, 63 FT_ULong char_code ); 64 65 FT_CALLBACK_DEF( FT_ULong ) 66 code_to_next6( TT_CMapTable charmap, 67 FT_ULong char_code ); 68 69 FT_CALLBACK_DEF( FT_UInt ) 70 code_to_index8_12( TT_CMapTable charmap, 71 FT_ULong char_code ); 72 73 FT_CALLBACK_DEF( FT_ULong ) 74 code_to_next8_12( TT_CMapTable charmap, 75 FT_ULong char_code ); 76 77 FT_CALLBACK_DEF( FT_UInt ) 78 code_to_index10( TT_CMapTable charmap, 79 FT_ULong char_code ); 80 81 FT_CALLBACK_DEF( FT_ULong ) 82 code_to_next10( TT_CMapTable charmap, 83 FT_ULong char_code ); 84 85 86 /*************************************************************************/ 87 /* */ 88 /* <Function> */ 89 /* tt_face_load_charmap */ 90 /* */ 91 /* <Description> */ 92 /* Loads a given TrueType character map into memory. */ 93 /* */ 94 /* <Input> */ 95 /* face :: A handle to the parent face object. */ 96 /* */ 97 /* stream :: A handle to the current stream object. */ 98 /* */ 99 /* <InOut> */ 100 /* table :: A pointer to a cmap object. */ 101 /* */ 102 /* <Return> */ 103 /* FreeType error code. 0 means success. */ 104 /* */ 105 /* <Note> */ 106 /* The function assumes that the stream is already in use (i.e., */ 107 /* opened). In case of error, all partially allocated tables are */ 108 /* released. */ 109 /* */ 110 FT_LOCAL_DEF( FT_Error ) tt_face_load_charmap(TT_Face face,TT_CMapTable cmap,FT_Stream stream)111 tt_face_load_charmap( TT_Face face, 112 TT_CMapTable cmap, 113 FT_Stream stream ) 114 { 115 FT_Error error; 116 FT_Memory memory; 117 FT_UShort num_SH, num_Seg, i; 118 FT_ULong j, n; 119 120 FT_UShort u, l; 121 122 TT_CMap0 cmap0; 123 TT_CMap2 cmap2; 124 TT_CMap4 cmap4; 125 TT_CMap6 cmap6; 126 TT_CMap8_12 cmap8_12; 127 TT_CMap10 cmap10; 128 129 TT_CMap2SubHeader cmap2sub; 130 TT_CMap4Segment segments; 131 TT_CMapGroup groups; 132 133 134 if ( cmap->loaded ) 135 return SFNT_Err_Ok; 136 137 memory = stream->memory; 138 139 if ( FT_STREAM_SEEK( cmap->offset ) ) 140 return error; 141 142 switch ( cmap->format ) 143 { 144 case 0: 145 cmap0 = &cmap->c.cmap0; 146 147 if ( FT_READ_USHORT( cmap0->language ) || 148 FT_ALLOC( cmap0->glyphIdArray, 256L ) || 149 FT_STREAM_READ( cmap0->glyphIdArray, 256L ) ) 150 goto Fail; 151 152 cmap->get_index = code_to_index0; 153 cmap->get_next_char = code_to_next0; 154 break; 155 156 case 2: 157 num_SH = 0; 158 cmap2 = &cmap->c.cmap2; 159 160 /* allocate subheader keys */ 161 162 if ( FT_NEW_ARRAY( cmap2->subHeaderKeys, 256 ) || 163 FT_FRAME_ENTER( 2L + 512L ) ) 164 goto Fail; 165 166 cmap2->language = FT_GET_USHORT(); 167 168 for ( i = 0; i < 256; i++ ) 169 { 170 u = (FT_UShort)( FT_GET_USHORT() / 8 ); 171 cmap2->subHeaderKeys[i] = u; 172 173 if ( num_SH < u ) 174 num_SH = u; 175 } 176 177 FT_FRAME_EXIT(); 178 179 /* load subheaders */ 180 181 cmap2->numGlyphId = l = (FT_UShort)( 182 ( ( cmap->length - 2L * ( 256 + 3 ) - num_SH * 8L ) & 0xFFFFU ) / 2 ); 183 184 if ( FT_NEW_ARRAY( cmap2->subHeaders, num_SH + 1 ) || 185 FT_FRAME_ENTER( ( num_SH + 1 ) * 8L ) ) 186 { 187 FT_FREE( cmap2->subHeaderKeys ); 188 goto Fail; 189 } 190 191 cmap2sub = cmap2->subHeaders; 192 193 for ( i = 0; i <= num_SH; i++ ) 194 { 195 cmap2sub->firstCode = FT_GET_USHORT(); 196 cmap2sub->entryCount = FT_GET_USHORT(); 197 cmap2sub->idDelta = FT_GET_SHORT(); 198 /* we apply the location offset immediately */ 199 cmap2sub->idRangeOffset = (FT_UShort)( 200 FT_GET_USHORT() - ( num_SH - i ) * 8 - 2 ); 201 202 cmap2sub++; 203 } 204 205 FT_FRAME_EXIT(); 206 207 /* load glyph IDs */ 208 209 if ( FT_NEW_ARRAY( cmap2->glyphIdArray, l ) || 210 FT_FRAME_ENTER( l * 2L ) ) 211 { 212 FT_FREE( cmap2->subHeaders ); 213 FT_FREE( cmap2->subHeaderKeys ); 214 goto Fail; 215 } 216 217 for ( i = 0; i < l; i++ ) 218 cmap2->glyphIdArray[i] = FT_GET_USHORT(); 219 220 FT_FRAME_EXIT(); 221 222 cmap->get_index = code_to_index2; 223 cmap->get_next_char = code_to_next2; 224 break; 225 226 case 4: 227 cmap4 = &cmap->c.cmap4; 228 229 /* load header */ 230 231 if ( FT_FRAME_ENTER( 10L ) ) 232 goto Fail; 233 234 cmap4->language = FT_GET_USHORT(); 235 cmap4->segCountX2 = FT_GET_USHORT(); 236 cmap4->searchRange = FT_GET_USHORT(); 237 cmap4->entrySelector = FT_GET_USHORT(); 238 cmap4->rangeShift = FT_GET_USHORT(); 239 240 num_Seg = (FT_UShort)( cmap4->segCountX2 / 2 ); 241 242 FT_FRAME_EXIT(); 243 244 /* load segments */ 245 246 if ( FT_NEW_ARRAY( cmap4->segments, num_Seg ) || 247 FT_FRAME_ENTER( ( num_Seg * 4 + 1 ) * 2L ) ) 248 goto Fail; 249 250 segments = cmap4->segments; 251 252 for ( i = 0; i < num_Seg; i++ ) 253 segments[i].endCount = FT_GET_USHORT(); 254 255 (void)FT_GET_USHORT(); 256 257 for ( i = 0; i < num_Seg; i++ ) 258 segments[i].startCount = FT_GET_USHORT(); 259 260 for ( i = 0; i < num_Seg; i++ ) 261 segments[i].idDelta = FT_GET_SHORT(); 262 263 for ( i = 0; i < num_Seg; i++ ) 264 segments[i].idRangeOffset = FT_GET_USHORT(); 265 266 FT_FRAME_EXIT(); 267 268 cmap4->numGlyphId = l = (FT_UShort)( 269 ( ( cmap->length - ( 16L + 8L * num_Seg ) ) & 0xFFFFU ) / 2 ); 270 271 /* load IDs */ 272 273 if ( FT_NEW_ARRAY( cmap4->glyphIdArray, l ) || 274 FT_FRAME_ENTER( l * 2L ) ) 275 { 276 FT_FREE( cmap4->segments ); 277 goto Fail; 278 } 279 280 for ( i = 0; i < l; i++ ) 281 cmap4->glyphIdArray[i] = FT_GET_USHORT(); 282 283 FT_FRAME_EXIT(); 284 285 cmap4->last_segment = cmap4->segments; 286 287 cmap->get_index = code_to_index4; 288 cmap->get_next_char = code_to_next4; 289 break; 290 291 case 6: 292 cmap6 = &cmap->c.cmap6; 293 294 if ( FT_FRAME_ENTER( 6L ) ) 295 goto Fail; 296 297 cmap6->language = FT_GET_USHORT(); 298 cmap6->firstCode = FT_GET_USHORT(); 299 cmap6->entryCount = FT_GET_USHORT(); 300 301 FT_FRAME_EXIT(); 302 303 l = cmap6->entryCount; 304 305 if ( FT_NEW_ARRAY( cmap6->glyphIdArray, l ) || 306 FT_FRAME_ENTER( l * 2L ) ) 307 goto Fail; 308 309 for ( i = 0; i < l; i++ ) 310 cmap6->glyphIdArray[i] = FT_GET_USHORT(); 311 312 FT_FRAME_EXIT(); 313 cmap->get_index = code_to_index6; 314 cmap->get_next_char = code_to_next6; 315 break; 316 317 case 8: 318 case 12: 319 cmap8_12 = &cmap->c.cmap8_12; 320 321 if ( FT_FRAME_ENTER( 8L ) ) 322 goto Fail; 323 324 cmap->length = FT_GET_ULONG(); 325 cmap8_12->language = FT_GET_ULONG(); 326 327 FT_FRAME_EXIT(); 328 329 if ( cmap->format == 8 ) 330 if ( FT_STREAM_SKIP( 8192L ) ) 331 goto Fail; 332 333 if ( FT_READ_ULONG( cmap8_12->nGroups ) ) 334 goto Fail; 335 336 n = cmap8_12->nGroups; 337 338 if ( FT_NEW_ARRAY( cmap8_12->groups, n ) || 339 FT_FRAME_ENTER( n * 3 * 4L ) ) 340 goto Fail; 341 342 groups = cmap8_12->groups; 343 344 for ( j = 0; j < n; j++ ) 345 { 346 groups[j].startCharCode = FT_GET_ULONG(); 347 groups[j].endCharCode = FT_GET_ULONG(); 348 groups[j].startGlyphID = FT_GET_ULONG(); 349 } 350 351 FT_FRAME_EXIT(); 352 353 cmap8_12->last_group = cmap8_12->groups; 354 355 cmap->get_index = code_to_index8_12; 356 cmap->get_next_char = code_to_next8_12; 357 break; 358 359 case 10: 360 cmap10 = &cmap->c.cmap10; 361 362 if ( FT_FRAME_ENTER( 16L ) ) 363 goto Fail; 364 365 cmap->length = FT_GET_ULONG(); 366 cmap10->language = FT_GET_ULONG(); 367 cmap10->startCharCode = FT_GET_ULONG(); 368 cmap10->numChars = FT_GET_ULONG(); 369 370 FT_FRAME_EXIT(); 371 372 n = cmap10->numChars; 373 374 if ( FT_NEW_ARRAY( cmap10->glyphs, n ) || 375 FT_FRAME_ENTER( n * 2L ) ) 376 goto Fail; 377 378 for ( j = 0; j < n; j++ ) 379 cmap10->glyphs[j] = FT_GET_USHORT(); 380 381 FT_FRAME_EXIT(); 382 cmap->get_index = code_to_index10; 383 cmap->get_next_char = code_to_next10; 384 break; 385 386 default: /* corrupt character mapping table */ 387 return SFNT_Err_Invalid_CharMap_Format; 388 389 } 390 391 return SFNT_Err_Ok; 392 393 Fail: 394 tt_face_free_charmap( face, cmap ); 395 return error; 396 } 397 398 399 /*************************************************************************/ 400 /* */ 401 /* <Function> */ 402 /* tt_face_free_charmap */ 403 /* */ 404 /* <Description> */ 405 /* Destroys a character mapping table. */ 406 /* */ 407 /* <Input> */ 408 /* face :: A handle to the parent face object. */ 409 /* */ 410 /* cmap :: A handle to a cmap object. */ 411 /* */ 412 /* <Return> */ 413 /* FreeType error code. 0 means success. */ 414 /* */ 415 FT_LOCAL_DEF( FT_Error ) tt_face_free_charmap(TT_Face face,TT_CMapTable cmap)416 tt_face_free_charmap( TT_Face face, 417 TT_CMapTable cmap ) 418 { 419 FT_Memory memory; 420 421 422 if ( !cmap ) 423 return SFNT_Err_Ok; 424 425 memory = face->root.driver->root.memory; 426 427 switch ( cmap->format ) 428 { 429 case 0: 430 FT_FREE( cmap->c.cmap0.glyphIdArray ); 431 break; 432 433 case 2: 434 FT_FREE( cmap->c.cmap2.subHeaderKeys ); 435 FT_FREE( cmap->c.cmap2.subHeaders ); 436 FT_FREE( cmap->c.cmap2.glyphIdArray ); 437 break; 438 439 case 4: 440 FT_FREE( cmap->c.cmap4.segments ); 441 FT_FREE( cmap->c.cmap4.glyphIdArray ); 442 cmap->c.cmap4.segCountX2 = 0; 443 break; 444 445 case 6: 446 FT_FREE( cmap->c.cmap6.glyphIdArray ); 447 cmap->c.cmap6.entryCount = 0; 448 break; 449 450 case 8: 451 case 12: 452 FT_FREE( cmap->c.cmap8_12.groups ); 453 cmap->c.cmap8_12.nGroups = 0; 454 break; 455 456 case 10: 457 FT_FREE( cmap->c.cmap10.glyphs ); 458 cmap->c.cmap10.numChars = 0; 459 break; 460 461 default: 462 /* invalid table format, do nothing */ 463 ; 464 } 465 466 cmap->loaded = FALSE; 467 return SFNT_Err_Ok; 468 } 469 470 471 /*************************************************************************/ 472 /* */ 473 /* <Function> */ 474 /* code_to_index0 */ 475 /* */ 476 /* <Description> */ 477 /* Converts the character code into a glyph index. Uses format 0. */ 478 /* `charCode' must be in the range 0x00-0xFF (otherwise 0 is */ 479 /* returned). */ 480 /* */ 481 /* <Input> */ 482 /* charCode :: The wanted character code. */ 483 /* */ 484 /* cmap0 :: A pointer to a cmap table in format 0. */ 485 /* */ 486 /* <Return> */ 487 /* Glyph index into the glyphs array. 0 if the glyph does not exist. */ 488 /* */ 489 FT_CALLBACK_DEF( FT_UInt ) code_to_index0(TT_CMapTable cmap,FT_ULong charCode)490 code_to_index0( TT_CMapTable cmap, 491 FT_ULong charCode ) 492 { 493 TT_CMap0 cmap0 = &cmap->c.cmap0; 494 495 496 return ( charCode <= 0xFF ? cmap0->glyphIdArray[charCode] : 0 ); 497 } 498 499 500 /*************************************************************************/ 501 /* */ 502 /* <Function> */ 503 /* code_to_next0 */ 504 /* */ 505 /* <Description> */ 506 /* Finds the next encoded character after the given one. Uses */ 507 /* format 0. `charCode' must be in the range 0x00-0xFF (otherwise 0 */ 508 /* is returned). */ 509 /* */ 510 /* <Input> */ 511 /* charCode :: The wanted character code. */ 512 /* */ 513 /* cmap0 :: A pointer to a cmap table in format 0. */ 514 /* */ 515 /* <Return> */ 516 /* Next char code. 0 if no higher one is encoded. */ 517 /* */ 518 FT_CALLBACK_DEF( FT_ULong ) code_to_next0(TT_CMapTable cmap,FT_ULong charCode)519 code_to_next0( TT_CMapTable cmap, 520 FT_ULong charCode ) 521 { 522 TT_CMap0 cmap0 = &cmap->c.cmap0; 523 524 525 while ( ++charCode <= 0xFF ) 526 if ( cmap0->glyphIdArray[charCode] ) 527 return ( charCode ); 528 return ( 0 ); 529 } 530 531 532 /*************************************************************************/ 533 /* */ 534 /* <Function> */ 535 /* code_to_index2 */ 536 /* */ 537 /* <Description> */ 538 /* Converts the character code into a glyph index. Uses format 2. */ 539 /* */ 540 /* <Input> */ 541 /* charCode :: The wanted character code. */ 542 /* */ 543 /* cmap2 :: A pointer to a cmap table in format 2. */ 544 /* */ 545 /* <Return> */ 546 /* Glyph index into the glyphs array. 0 if the glyph does not exist. */ 547 /* */ 548 FT_CALLBACK_DEF( FT_UInt ) code_to_index2(TT_CMapTable cmap,FT_ULong charCode)549 code_to_index2( TT_CMapTable cmap, 550 FT_ULong charCode ) 551 { 552 FT_UInt result, index1, offset; 553 FT_UInt char_lo; 554 FT_ULong char_hi; 555 TT_CMap2SubHeader sh2; 556 TT_CMap2 cmap2; 557 558 559 cmap2 = &cmap->c.cmap2; 560 result = 0; 561 char_lo = (FT_UInt)( charCode & 0xFF ); 562 char_hi = charCode >> 8; 563 564 if ( char_hi == 0 ) 565 { 566 /* an 8-bit character code -- we use the subHeader 0 in this case */ 567 /* to test whether the character code is in the charmap */ 568 index1 = cmap2->subHeaderKeys[char_lo]; 569 if ( index1 != 0 ) 570 return 0; 571 } 572 else 573 { 574 /* a 16-bit character code */ 575 index1 = cmap2->subHeaderKeys[char_hi & 0xFF]; 576 if ( index1 == 0 ) 577 return 0; 578 } 579 580 sh2 = cmap2->subHeaders + index1; 581 char_lo -= sh2->firstCode; 582 583 if ( char_lo < (FT_UInt)sh2->entryCount ) 584 { 585 offset = sh2->idRangeOffset / 2 + char_lo; 586 if ( offset < (FT_UInt)cmap2->numGlyphId ) 587 { 588 result = cmap2->glyphIdArray[offset]; 589 if ( result ) 590 result = ( result + sh2->idDelta ) & 0xFFFFU; 591 } 592 } 593 594 return result; 595 } 596 597 598 /*************************************************************************/ 599 /* */ 600 /* <Function> */ 601 /* code_to_next2 */ 602 /* */ 603 /* <Description> */ 604 /* Find the next encoded character. Uses format 2. */ 605 /* */ 606 /* <Input> */ 607 /* charCode :: The wanted character code. */ 608 /* */ 609 /* cmap2 :: A pointer to a cmap table in format 2. */ 610 /* */ 611 /* <Return> */ 612 /* Next encoded character. 0 if none exists. */ 613 /* */ 614 FT_CALLBACK_DEF( FT_ULong ) code_to_next2(TT_CMapTable cmap,FT_ULong charCode)615 code_to_next2( TT_CMapTable cmap, 616 FT_ULong charCode ) 617 { 618 FT_UInt index1, offset; 619 FT_UInt char_lo; 620 FT_ULong char_hi; 621 TT_CMap2SubHeader sh2; 622 TT_CMap2 cmap2; 623 624 625 cmap2 = &cmap->c.cmap2; 626 charCode++; 627 628 /* 629 * This is relatively simplistic -- look for a subHeader containing 630 * glyphs and then walk to the first glyph in that subHeader. 631 */ 632 while ( charCode < 0x10000L ) 633 { 634 char_lo = (FT_UInt)( charCode & 0xFF ); 635 char_hi = charCode >> 8; 636 637 if ( char_hi == 0 ) 638 { 639 /* an 8-bit character code -- we use the subHeader 0 in this case */ 640 /* to test whether the character code is in the charmap */ 641 index1 = cmap2->subHeaderKeys[char_lo]; 642 if ( index1 != 0 ) 643 { 644 charCode++; 645 continue; 646 } 647 } 648 else 649 { 650 /* a 16-bit character code */ 651 index1 = cmap2->subHeaderKeys[char_hi & 0xFF]; 652 if ( index1 == 0 ) 653 { 654 charCode = ( char_hi + 1 ) << 8; 655 continue; 656 } 657 } 658 659 sh2 = cmap2->subHeaders + index1; 660 char_lo -= sh2->firstCode; 661 662 if ( char_lo > (FT_UInt)sh2->entryCount ) 663 { 664 charCode = ( char_hi + 1 ) << 8; 665 continue; 666 } 667 668 offset = sh2->idRangeOffset / 2 + char_lo; 669 if ( offset >= (FT_UInt)cmap2->numGlyphId || 670 cmap2->glyphIdArray[offset] == 0 ) 671 { 672 charCode++; 673 continue; 674 } 675 676 return charCode; 677 } 678 return 0; 679 } 680 681 682 /*************************************************************************/ 683 /* */ 684 /* <Function> */ 685 /* code_to_index4 */ 686 /* */ 687 /* <Description> */ 688 /* Converts the character code into a glyph index. Uses format 4. */ 689 /* */ 690 /* <Input> */ 691 /* charCode :: The wanted character code. */ 692 /* */ 693 /* cmap4 :: A pointer to a cmap table in format 4. */ 694 /* */ 695 /* <Return> */ 696 /* Glyph index into the glyphs array. 0 if the glyph does not exist. */ 697 /* */ 698 FT_CALLBACK_DEF( FT_UInt ) code_to_index4(TT_CMapTable cmap,FT_ULong charCode)699 code_to_index4( TT_CMapTable cmap, 700 FT_ULong charCode ) 701 { 702 FT_UInt result, index1, segCount; 703 TT_CMap4 cmap4; 704 TT_CMap4SegmentRec *seg4, *limit; 705 706 707 cmap4 = &cmap->c.cmap4; 708 result = 0; 709 segCount = cmap4->segCountX2 / 2; 710 limit = cmap4->segments + segCount; 711 712 /* first, check against the last used segment */ 713 714 seg4 = cmap4->last_segment; 715 716 /* the following is equivalent to performing two tests, as in */ 717 /* */ 718 /* if ( charCode >= seg4->startCount && charCode <= seg4->endCount ) */ 719 /* */ 720 /* This is a bit strange, but it is faster, and the idea behind the */ 721 /* cache is to significantly speed up charcode to glyph index */ 722 /* conversion. */ 723 724 if ( (FT_ULong)( charCode - seg4->startCount ) < 725 (FT_ULong)( seg4->endCount - seg4->startCount ) ) 726 goto Found1; 727 728 for ( seg4 = cmap4->segments; seg4 < limit; seg4++ ) 729 { 730 /* the ranges are sorted in increasing order. If we are out of */ 731 /* the range here, the char code isn't in the charmap, so exit. */ 732 733 if ( charCode > (FT_UInt)seg4->endCount ) 734 continue; 735 736 if ( charCode >= (FT_UInt)seg4->startCount ) 737 goto Found; 738 } 739 return 0; 740 741 Found: 742 cmap4->last_segment = seg4; 743 744 Found1: 745 /* if the idRangeOffset is 0, we can compute the glyph index */ 746 /* directly */ 747 748 if ( seg4->idRangeOffset == 0 ) 749 result = (FT_UInt)( charCode + seg4->idDelta ) & 0xFFFFU; 750 else 751 { 752 /* otherwise, we must use the glyphIdArray to do it */ 753 index1 = (FT_UInt)( seg4->idRangeOffset / 2 754 + ( charCode - seg4->startCount ) 755 + ( seg4 - cmap4->segments ) 756 - segCount ); 757 758 if ( index1 < (FT_UInt)cmap4->numGlyphId && 759 cmap4->glyphIdArray[index1] != 0 ) 760 result = ( cmap4->glyphIdArray[index1] + seg4->idDelta ) & 0xFFFFU; 761 } 762 763 return result; 764 } 765 766 767 /*************************************************************************/ 768 /* */ 769 /* <Function> */ 770 /* code_to_next4 */ 771 /* */ 772 /* <Description> */ 773 /* Find the next encoded character. Uses format 4. */ 774 /* */ 775 /* <Input> */ 776 /* charCode :: The wanted character code. */ 777 /* */ 778 /* cmap :: A pointer to a cmap table in format 4. */ 779 /* */ 780 /* <Return> */ 781 /* Next encoded character. 0 if none exists. */ 782 /* */ 783 FT_CALLBACK_DEF( FT_ULong ) code_to_next4(TT_CMapTable cmap,FT_ULong charCode)784 code_to_next4( TT_CMapTable cmap, 785 FT_ULong charCode ) 786 { 787 FT_UInt index1, segCount; 788 TT_CMap4 cmap4; 789 TT_CMap4SegmentRec *seg4, *limit; 790 791 792 cmap4 = &cmap->c.cmap4; 793 segCount = cmap4->segCountX2 / 2; 794 limit = cmap4->segments + segCount; 795 796 charCode++; 797 798 for ( seg4 = cmap4->segments; seg4 < limit; seg4++ ) 799 { 800 /* The ranges are sorted in increasing order. If we are out of */ 801 /* the range here, the char code isn't in the charmap, so exit. */ 802 803 if ( charCode <= (FT_UInt)seg4->endCount ) 804 goto Found; 805 } 806 return 0; 807 808 Found: 809 if ( charCode < (FT_ULong) seg4->startCount ) 810 charCode = seg4->startCount; 811 812 /* if the idRangeOffset is 0, all chars in the map exist */ 813 814 if ( seg4->idRangeOffset == 0 ) 815 return ( charCode ); 816 817 while ( charCode <= (FT_UInt) seg4->endCount ) 818 { 819 /* otherwise, we must use the glyphIdArray to do it */ 820 index1 = (FT_UInt)( seg4->idRangeOffset / 2 821 + ( charCode - seg4->startCount ) 822 + ( seg4 - cmap4->segments ) 823 - segCount ); 824 825 if ( index1 < (FT_UInt)cmap4->numGlyphId && 826 cmap4->glyphIdArray[index1] != 0 ) 827 return ( charCode ); 828 charCode++; 829 } 830 831 return 0; 832 } 833 834 835 /*************************************************************************/ 836 /* */ 837 /* <Function> */ 838 /* code_to_index6 */ 839 /* */ 840 /* <Description> */ 841 /* Converts the character code into a glyph index. Uses format 6. */ 842 /* */ 843 /* <Input> */ 844 /* charCode :: The wanted character code. */ 845 /* */ 846 /* cmap6 :: A pointer to a cmap table in format 6. */ 847 /* */ 848 /* <Return> */ 849 /* Glyph index into the glyphs array. 0 if the glyph does not exist. */ 850 /* */ 851 FT_CALLBACK_DEF( FT_UInt ) code_to_index6(TT_CMapTable cmap,FT_ULong charCode)852 code_to_index6( TT_CMapTable cmap, 853 FT_ULong charCode ) 854 { 855 TT_CMap6 cmap6; 856 FT_UInt result = 0; 857 858 859 cmap6 = &cmap->c.cmap6; 860 charCode -= cmap6->firstCode; 861 862 if ( charCode < (FT_UInt)cmap6->entryCount ) 863 result = cmap6->glyphIdArray[charCode]; 864 865 return result; 866 } 867 868 869 /*************************************************************************/ 870 /* */ 871 /* <Function> */ 872 /* code_to_next6 */ 873 /* */ 874 /* <Description> */ 875 /* Find the next encoded character. Uses format 6. */ 876 /* */ 877 /* <Input> */ 878 /* charCode :: The wanted character code. */ 879 /* */ 880 /* cmap :: A pointer to a cmap table in format 6. */ 881 /* */ 882 /* <Return> */ 883 /* Next encoded character. 0 if none exists. */ 884 /* */ 885 FT_CALLBACK_DEF( FT_ULong ) code_to_next6(TT_CMapTable cmap,FT_ULong charCode)886 code_to_next6( TT_CMapTable cmap, 887 FT_ULong charCode ) 888 { 889 TT_CMap6 cmap6; 890 891 892 charCode++; 893 894 cmap6 = &cmap->c.cmap6; 895 896 if ( charCode < (FT_ULong) cmap6->firstCode ) 897 charCode = cmap6->firstCode; 898 899 charCode -= cmap6->firstCode; 900 901 while ( charCode < (FT_UInt)cmap6->entryCount ) 902 { 903 if ( cmap6->glyphIdArray[charCode] != 0 ) 904 return charCode + cmap6->firstCode; 905 charCode++; 906 } 907 908 return 0; 909 } 910 911 912 /*************************************************************************/ 913 /* */ 914 /* <Function> */ 915 /* code_to_index8_12 */ 916 /* */ 917 /* <Description> */ 918 /* Converts the (possibly 32bit) character code into a glyph index. */ 919 /* Uses format 8 or 12. */ 920 /* */ 921 /* <Input> */ 922 /* charCode :: The wanted character code. */ 923 /* */ 924 /* cmap8_12 :: A pointer to a cmap table in format 8 or 12. */ 925 /* */ 926 /* <Return> */ 927 /* Glyph index into the glyphs array. 0 if the glyph does not exist. */ 928 /* */ 929 FT_CALLBACK_DEF( FT_UInt ) code_to_index8_12(TT_CMapTable cmap,FT_ULong charCode)930 code_to_index8_12( TT_CMapTable cmap, 931 FT_ULong charCode ) 932 { 933 TT_CMap8_12 cmap8_12; 934 TT_CMapGroupRec *group, *limit; 935 936 937 cmap8_12 = &cmap->c.cmap8_12; 938 limit = cmap8_12->groups + cmap8_12->nGroups; 939 940 /* first, check against the last used group */ 941 942 group = cmap8_12->last_group; 943 944 /* the following is equivalent to performing two tests, as in */ 945 /* */ 946 /* if ( charCode >= group->startCharCode && */ 947 /* charCode <= group->endCharCode ) */ 948 /* */ 949 /* This is a bit strange, but it is faster, and the idea behind the */ 950 /* cache is to significantly speed up charcode to glyph index */ 951 /* conversion. */ 952 953 if ( (FT_ULong)( charCode - group->startCharCode ) < 954 (FT_ULong)( group->endCharCode - group->startCharCode ) ) 955 goto Found1; 956 957 for ( group = cmap8_12->groups; group < limit; group++ ) 958 { 959 /* the ranges are sorted in increasing order. If we are out of */ 960 /* the range here, the char code isn't in the charmap, so exit. */ 961 962 if ( charCode > group->endCharCode ) 963 continue; 964 965 if ( charCode >= group->startCharCode ) 966 goto Found; 967 } 968 return 0; 969 970 Found: 971 cmap8_12->last_group = group; 972 973 Found1: 974 return (FT_UInt)( group->startGlyphID + 975 ( charCode - group->startCharCode ) ); 976 } 977 978 979 /*************************************************************************/ 980 /* */ 981 /* <Function> */ 982 /* code_to_next8_12 */ 983 /* */ 984 /* <Description> */ 985 /* Find the next encoded character. Uses format 8 or 12. */ 986 /* */ 987 /* <Input> */ 988 /* charCode :: The wanted character code. */ 989 /* */ 990 /* cmap :: A pointer to a cmap table in format 8 or 12. */ 991 /* */ 992 /* <Return> */ 993 /* Next encoded character. 0 if none exists. */ 994 /* */ 995 FT_CALLBACK_DEF( FT_ULong ) code_to_next8_12(TT_CMapTable cmap,FT_ULong charCode)996 code_to_next8_12( TT_CMapTable cmap, 997 FT_ULong charCode ) 998 { 999 TT_CMap8_12 cmap8_12; 1000 TT_CMapGroupRec *group, *limit; 1001 1002 1003 charCode++; 1004 cmap8_12 = &cmap->c.cmap8_12; 1005 limit = cmap8_12->groups + cmap8_12->nGroups; 1006 1007 for ( group = cmap8_12->groups; group < limit; group++ ) 1008 { 1009 /* the ranges are sorted in increasing order. If we are out of */ 1010 /* the range here, the char code isn't in the charmap, so exit. */ 1011 1012 if ( charCode <= group->endCharCode ) 1013 goto Found; 1014 } 1015 return 0; 1016 1017 Found: 1018 if ( charCode < group->startCharCode ) 1019 charCode = group->startCharCode; 1020 1021 return charCode; 1022 } 1023 1024 1025 /*************************************************************************/ 1026 /* */ 1027 /* <Function> */ 1028 /* code_to_index10 */ 1029 /* */ 1030 /* <Description> */ 1031 /* Converts the (possibly 32bit) character code into a glyph index. */ 1032 /* Uses format 10. */ 1033 /* */ 1034 /* <Input> */ 1035 /* charCode :: The wanted character code. */ 1036 /* */ 1037 /* cmap10 :: A pointer to a cmap table in format 10. */ 1038 /* */ 1039 /* <Return> */ 1040 /* Glyph index into the glyphs array. 0 if the glyph does not exist. */ 1041 /* */ 1042 FT_CALLBACK_DEF( FT_UInt ) code_to_index10(TT_CMapTable cmap,FT_ULong charCode)1043 code_to_index10( TT_CMapTable cmap, 1044 FT_ULong charCode ) 1045 { 1046 TT_CMap10 cmap10; 1047 FT_UInt result = 0; 1048 1049 1050 cmap10 = &cmap->c.cmap10; 1051 charCode -= cmap10->startCharCode; 1052 1053 /* the overflow trick for comparison works here also since the number */ 1054 /* of glyphs (even if numChars is specified as ULong in the specs) in */ 1055 /* an OpenType font is limited to 64k */ 1056 1057 if ( charCode < cmap10->numChars ) 1058 result = cmap10->glyphs[charCode]; 1059 1060 return result; 1061 } 1062 1063 1064 /*************************************************************************/ 1065 /* */ 1066 /* <Function> */ 1067 /* code_to_next10 */ 1068 /* */ 1069 /* <Description> */ 1070 /* Find the next encoded character. Uses format 10. */ 1071 /* */ 1072 /* <Input> */ 1073 /* charCode :: The wanted character code. */ 1074 /* */ 1075 /* cmap :: A pointer to a cmap table in format 10. */ 1076 /* */ 1077 /* <Return> */ 1078 /* Next encoded character. 0 if none exists. */ 1079 /* */ 1080 FT_CALLBACK_DEF( FT_ULong ) code_to_next10(TT_CMapTable cmap,FT_ULong charCode)1081 code_to_next10( TT_CMapTable cmap, 1082 FT_ULong charCode ) 1083 { 1084 TT_CMap10 cmap10; 1085 1086 1087 charCode++; 1088 cmap10 = &cmap->c.cmap10; 1089 1090 if ( charCode < cmap10->startCharCode ) 1091 charCode = cmap10->startCharCode; 1092 1093 charCode -= cmap10->startCharCode; 1094 1095 /* the overflow trick for comparison works here also since the number */ 1096 /* of glyphs (even if numChars is specified as ULong in the specs) in */ 1097 /* an OpenType font is limited to 64k */ 1098 1099 while ( charCode < cmap10->numChars ) 1100 { 1101 if ( cmap10->glyphs[charCode] ) 1102 return ( charCode + cmap10->startCharCode ); 1103 charCode++; 1104 } 1105 1106 return 0; 1107 } 1108 1109 1110 /* END */ 1111