1 /* 2 * Copyright (C) 1998-2004 David Turner and Werner Lemberg 3 * Copyright (C) 2006 Behdad Esfahbod 4 * Copyright (C) 2007 Red Hat, Inc. 5 * 6 * This is part of HarfBuzz, an OpenType Layout engine library. 7 * 8 * Permission is hereby granted, without written agreement and without 9 * license or royalty fees, to use, copy, modify, and distribute this 10 * software and its documentation for any purpose, provided that the 11 * above copyright notice and the following two paragraphs appear in 12 * all copies of this software. 13 * 14 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 15 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 16 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 17 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 18 * DAMAGE. 19 * 20 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 21 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 22 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 23 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 24 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 25 * 26 * Red Hat Author(s): Behdad Esfahbod 27 */ 28 29 #include "harfbuzz-impl.h" 30 #include "harfbuzz-gsub-private.h" 31 #include "harfbuzz-open-private.h" 32 #include "harfbuzz-gdef-private.h" 33 34 static HB_Error GSUB_Do_Glyph_Lookup( HB_GSUBHeader* gsub, 35 HB_UShort lookup_index, 36 HB_Buffer buffer, 37 HB_UShort context_length, 38 int nesting_level ); 39 40 41 42 /********************** 43 * Auxiliary functions 44 **********************/ 45 46 47 48 HB_Error HB_Load_GSUB_Table( HB_Stream stream, 49 HB_GSUBHeader** retptr, 50 HB_GDEFHeader* gdef, 51 HB_Stream gdefStream ) 52 { 53 HB_Error error; 54 HB_UInt cur_offset, new_offset, base_offset; 55 56 HB_GSUBHeader* gsub; 57 58 if ( !retptr ) 59 return ERR(HB_Err_Invalid_Argument); 60 61 if ( GOTO_Table( TTAG_GSUB ) ) 62 return error; 63 64 base_offset = FILE_Pos(); 65 66 if ( ALLOC ( gsub, sizeof( *gsub ) ) ) 67 return error; 68 69 70 /* skip version */ 71 72 if ( FILE_Seek( base_offset + 4L ) || 73 ACCESS_Frame( 2L ) ) 74 goto Fail4; 75 76 new_offset = GET_UShort() + base_offset; 77 78 FORGET_Frame(); 79 80 cur_offset = FILE_Pos(); 81 if ( FILE_Seek( new_offset ) || 82 ( error = _HB_OPEN_Load_ScriptList( &gsub->ScriptList, 83 stream ) ) != HB_Err_Ok ) 84 goto Fail4; 85 (void)FILE_Seek( cur_offset ); 86 87 if ( ACCESS_Frame( 2L ) ) 88 goto Fail3; 89 90 new_offset = GET_UShort() + base_offset; 91 92 FORGET_Frame(); 93 94 cur_offset = FILE_Pos(); 95 if ( FILE_Seek( new_offset ) || 96 ( error = _HB_OPEN_Load_FeatureList( &gsub->FeatureList, 97 stream ) ) != HB_Err_Ok ) 98 goto Fail3; 99 (void)FILE_Seek( cur_offset ); 100 101 if ( ACCESS_Frame( 2L ) ) 102 goto Fail2; 103 104 new_offset = GET_UShort() + base_offset; 105 106 FORGET_Frame(); 107 108 cur_offset = FILE_Pos(); 109 if ( FILE_Seek( new_offset ) || 110 ( error = _HB_OPEN_Load_LookupList( &gsub->LookupList, 111 stream, HB_Type_GSUB ) ) != HB_Err_Ok ) 112 goto Fail2; 113 114 gsub->gdef = gdef; /* can be NULL */ 115 116 if ( ( error = _HB_GDEF_LoadMarkAttachClassDef_From_LookupFlags( gdef, gdefStream, 117 gsub->LookupList.Lookup, 118 gsub->LookupList.LookupCount ) ) ) 119 goto Fail1; 120 121 *retptr = gsub; 122 123 return HB_Err_Ok; 124 125 Fail1: 126 _HB_OPEN_Free_LookupList( &gsub->LookupList, HB_Type_GSUB ); 127 128 Fail2: 129 _HB_OPEN_Free_FeatureList( &gsub->FeatureList ); 130 131 Fail3: 132 _HB_OPEN_Free_ScriptList( &gsub->ScriptList ); 133 134 Fail4: 135 FREE ( gsub ); 136 137 138 return error; 139 } 140 141 142 HB_Error HB_Done_GSUB_Table( HB_GSUBHeader* gsub ) 143 { 144 _HB_OPEN_Free_LookupList( &gsub->LookupList, HB_Type_GSUB ); 145 _HB_OPEN_Free_FeatureList( &gsub->FeatureList ); 146 _HB_OPEN_Free_ScriptList( &gsub->ScriptList ); 147 148 FREE( gsub ); 149 150 return HB_Err_Ok; 151 } 152 153 /***************************** 154 * SubTable related functions 155 *****************************/ 156 157 158 /* LookupType 1 */ 159 160 /* SingleSubstFormat1 */ 161 /* SingleSubstFormat2 */ 162 163 static HB_Error Load_SingleSubst( HB_GSUB_SubTable* st, 164 HB_Stream stream ) 165 { 166 HB_Error error; 167 HB_SingleSubst* ss = &st->single; 168 169 HB_UShort n, count; 170 HB_UInt cur_offset, new_offset, base_offset; 171 172 HB_UShort* s; 173 174 175 base_offset = FILE_Pos(); 176 177 if ( ACCESS_Frame( 4L ) ) 178 return error; 179 180 ss->SubstFormat = GET_UShort(); 181 new_offset = GET_UShort() + base_offset; 182 183 FORGET_Frame(); 184 185 cur_offset = FILE_Pos(); 186 if ( FILE_Seek( new_offset ) || 187 ( error = _HB_OPEN_Load_Coverage( &ss->Coverage, stream ) ) != HB_Err_Ok ) 188 return error; 189 (void)FILE_Seek( cur_offset ); 190 191 switch ( ss->SubstFormat ) 192 { 193 case 1: 194 if ( ACCESS_Frame( 2L ) ) 195 goto Fail2; 196 197 ss->ssf.ssf1.DeltaGlyphID = GET_UShort(); 198 199 FORGET_Frame(); 200 201 break; 202 203 case 2: 204 if ( ACCESS_Frame( 2L ) ) 205 goto Fail2; 206 207 count = ss->ssf.ssf2.GlyphCount = GET_UShort(); 208 209 FORGET_Frame(); 210 211 ss->ssf.ssf2.Substitute = NULL; 212 213 if ( ALLOC_ARRAY( ss->ssf.ssf2.Substitute, count, HB_UShort ) ) 214 goto Fail2; 215 216 s = ss->ssf.ssf2.Substitute; 217 218 if ( ACCESS_Frame( count * 2L ) ) 219 goto Fail1; 220 221 for ( n = 0; n < count; n++ ) 222 s[n] = GET_UShort(); 223 224 FORGET_Frame(); 225 226 break; 227 228 default: 229 return ERR(HB_Err_Invalid_SubTable_Format); 230 } 231 232 return HB_Err_Ok; 233 234 Fail1: 235 FREE( s ); 236 237 Fail2: 238 _HB_OPEN_Free_Coverage( &ss->Coverage ); 239 return error; 240 } 241 242 243 static void Free_SingleSubst( HB_GSUB_SubTable* st ) 244 { 245 HB_SingleSubst* ss = &st->single; 246 247 switch ( ss->SubstFormat ) 248 { 249 case 1: 250 break; 251 252 case 2: 253 FREE( ss->ssf.ssf2.Substitute ); 254 break; 255 256 default: 257 break; 258 } 259 260 _HB_OPEN_Free_Coverage( &ss->Coverage ); 261 } 262 263 264 static HB_Error Lookup_SingleSubst( HB_GSUBHeader* gsub, 265 HB_GSUB_SubTable* st, 266 HB_Buffer buffer, 267 HB_UShort flags, 268 HB_UShort context_length, 269 int nesting_level ) 270 { 271 HB_UShort index, value, property; 272 HB_Error error; 273 HB_SingleSubst* ss = &st->single; 274 HB_GDEFHeader* gdef = gsub->gdef; 275 276 HB_UNUSED(nesting_level); 277 278 if ( context_length != 0xFFFF && context_length < 1 ) 279 return HB_Err_Not_Covered; 280 281 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) 282 return error; 283 284 error = _HB_OPEN_Coverage_Index( &ss->Coverage, IN_CURGLYPH(), &index ); 285 if ( error ) 286 return error; 287 288 switch ( ss->SubstFormat ) 289 { 290 case 1: 291 value = ( IN_CURGLYPH() + ss->ssf.ssf1.DeltaGlyphID ) & 0xFFFF; 292 if ( REPLACE_Glyph( buffer, value, nesting_level ) ) 293 return error; 294 break; 295 296 case 2: 297 if ( index >= ss->ssf.ssf2.GlyphCount ) 298 return ERR(HB_Err_Invalid_SubTable); 299 value = ss->ssf.ssf2.Substitute[index]; 300 if ( REPLACE_Glyph( buffer, value, nesting_level ) ) 301 return error; 302 break; 303 304 default: 305 return ERR(HB_Err_Invalid_SubTable); 306 } 307 308 if ( gdef && gdef->NewGlyphClasses ) 309 { 310 /* we inherit the old glyph class to the substituted glyph */ 311 312 error = _HB_GDEF_Add_Glyph_Property( gdef, value, property ); 313 if ( error && error != HB_Err_Not_Covered ) 314 return error; 315 } 316 317 return HB_Err_Ok; 318 } 319 320 321 /* LookupType 2 */ 322 323 /* Sequence */ 324 325 static HB_Error Load_Sequence( HB_Sequence* s, 326 HB_Stream stream ) 327 { 328 HB_Error error; 329 330 HB_UShort n, count; 331 HB_UShort* sub; 332 333 334 if ( ACCESS_Frame( 2L ) ) 335 return error; 336 337 count = s->GlyphCount = GET_UShort(); 338 339 FORGET_Frame(); 340 341 s->Substitute = NULL; 342 343 if ( count ) 344 { 345 if ( ALLOC_ARRAY( s->Substitute, count, HB_UShort ) ) 346 return error; 347 348 sub = s->Substitute; 349 350 if ( ACCESS_Frame( count * 2L ) ) 351 { 352 FREE( sub ); 353 return error; 354 } 355 356 for ( n = 0; n < count; n++ ) 357 sub[n] = GET_UShort(); 358 359 FORGET_Frame(); 360 } 361 362 return HB_Err_Ok; 363 } 364 365 366 static void Free_Sequence( HB_Sequence* s ) 367 { 368 FREE( s->Substitute ); 369 } 370 371 372 /* MultipleSubstFormat1 */ 373 374 static HB_Error Load_MultipleSubst( HB_GSUB_SubTable* st, 375 HB_Stream stream ) 376 { 377 HB_Error error; 378 HB_MultipleSubst* ms = &st->multiple; 379 380 HB_UShort n = 0, m, count; 381 HB_UInt cur_offset, new_offset, base_offset; 382 383 HB_Sequence* s; 384 385 386 base_offset = FILE_Pos(); 387 388 if ( ACCESS_Frame( 4L ) ) 389 return error; 390 391 ms->SubstFormat = GET_UShort(); /* should be 1 */ 392 new_offset = GET_UShort() + base_offset; 393 394 FORGET_Frame(); 395 396 cur_offset = FILE_Pos(); 397 if ( FILE_Seek( new_offset ) || 398 ( error = _HB_OPEN_Load_Coverage( &ms->Coverage, stream ) ) != HB_Err_Ok ) 399 return error; 400 (void)FILE_Seek( cur_offset ); 401 402 if ( ACCESS_Frame( 2L ) ) 403 goto Fail2; 404 405 count = ms->SequenceCount = GET_UShort(); 406 407 FORGET_Frame(); 408 409 ms->Sequence = NULL; 410 411 if ( ALLOC_ARRAY( ms->Sequence, count, HB_Sequence ) ) 412 goto Fail2; 413 414 s = ms->Sequence; 415 416 for ( n = 0; n < count; n++ ) 417 { 418 if ( ACCESS_Frame( 2L ) ) 419 goto Fail1; 420 421 new_offset = GET_UShort() + base_offset; 422 423 FORGET_Frame(); 424 425 cur_offset = FILE_Pos(); 426 if ( FILE_Seek( new_offset ) || 427 ( error = Load_Sequence( &s[n], stream ) ) != HB_Err_Ok ) 428 goto Fail1; 429 (void)FILE_Seek( cur_offset ); 430 } 431 432 return HB_Err_Ok; 433 434 Fail1: 435 for ( m = 0; m < n; m++ ) 436 Free_Sequence( &s[m] ); 437 438 FREE( s ); 439 440 Fail2: 441 _HB_OPEN_Free_Coverage( &ms->Coverage ); 442 return error; 443 } 444 445 446 static void Free_MultipleSubst( HB_GSUB_SubTable* st ) 447 { 448 HB_UShort n, count; 449 HB_MultipleSubst* ms = &st->multiple; 450 451 HB_Sequence* s; 452 453 454 if ( ms->Sequence ) 455 { 456 count = ms->SequenceCount; 457 s = ms->Sequence; 458 459 for ( n = 0; n < count; n++ ) 460 Free_Sequence( &s[n] ); 461 462 FREE( s ); 463 } 464 465 _HB_OPEN_Free_Coverage( &ms->Coverage ); 466 } 467 468 469 static HB_Error Lookup_MultipleSubst( HB_GSUBHeader* gsub, 470 HB_GSUB_SubTable* st, 471 HB_Buffer buffer, 472 HB_UShort flags, 473 HB_UShort context_length, 474 int nesting_level ) 475 { 476 HB_Error error; 477 HB_UShort index, property, n, count; 478 HB_UShort*s; 479 HB_MultipleSubst* ms = &st->multiple; 480 HB_GDEFHeader* gdef = gsub->gdef; 481 482 HB_UNUSED(nesting_level); 483 484 if ( context_length != 0xFFFF && context_length < 1 ) 485 return HB_Err_Not_Covered; 486 487 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) 488 return error; 489 490 error = _HB_OPEN_Coverage_Index( &ms->Coverage, IN_CURGLYPH(), &index ); 491 if ( error ) 492 return error; 493 494 if ( index >= ms->SequenceCount ) 495 return ERR(HB_Err_Invalid_SubTable); 496 497 count = ms->Sequence[index].GlyphCount; 498 s = ms->Sequence[index].Substitute; 499 500 if ( ADD_String( buffer, 1, count, s, 0xFFFF, 0xFFFF ) ) 501 return error; 502 503 if ( gdef && gdef->NewGlyphClasses ) 504 { 505 /* this is a guess only ... */ 506 507 if ( property == HB_GDEF_LIGATURE ) 508 property = HB_GDEF_BASE_GLYPH; 509 510 for ( n = 0; n < count; n++ ) 511 { 512 error = _HB_GDEF_Add_Glyph_Property( gdef, s[n], property ); 513 if ( error && error != HB_Err_Not_Covered ) 514 return error; 515 } 516 } 517 518 return HB_Err_Ok; 519 } 520 521 522 /* LookupType 3 */ 523 524 /* AlternateSet */ 525 526 static HB_Error Load_AlternateSet( HB_AlternateSet* as, 527 HB_Stream stream ) 528 { 529 HB_Error error; 530 531 HB_UShort n, count; 532 HB_UShort* a; 533 534 535 if ( ACCESS_Frame( 2L ) ) 536 return error; 537 538 count = as->GlyphCount = GET_UShort(); 539 540 FORGET_Frame(); 541 542 as->Alternate = NULL; 543 544 if ( ALLOC_ARRAY( as->Alternate, count, HB_UShort ) ) 545 return error; 546 547 a = as->Alternate; 548 549 if ( ACCESS_Frame( count * 2L ) ) 550 { 551 FREE( a ); 552 return error; 553 } 554 555 for ( n = 0; n < count; n++ ) 556 a[n] = GET_UShort(); 557 558 FORGET_Frame(); 559 560 return HB_Err_Ok; 561 } 562 563 564 static void Free_AlternateSet( HB_AlternateSet* as ) 565 { 566 FREE( as->Alternate ); 567 } 568 569 570 /* AlternateSubstFormat1 */ 571 572 static HB_Error Load_AlternateSubst( HB_GSUB_SubTable* st, 573 HB_Stream stream ) 574 { 575 HB_Error error; 576 HB_AlternateSubst* as = &st->alternate; 577 578 HB_UShort n = 0, m, count; 579 HB_UInt cur_offset, new_offset, base_offset; 580 581 HB_AlternateSet* aset; 582 583 584 base_offset = FILE_Pos(); 585 586 if ( ACCESS_Frame( 4L ) ) 587 return error; 588 589 as->SubstFormat = GET_UShort(); /* should be 1 */ 590 new_offset = GET_UShort() + base_offset; 591 592 FORGET_Frame(); 593 594 cur_offset = FILE_Pos(); 595 if ( FILE_Seek( new_offset ) || 596 ( error = _HB_OPEN_Load_Coverage( &as->Coverage, stream ) ) != HB_Err_Ok ) 597 return error; 598 (void)FILE_Seek( cur_offset ); 599 600 if ( ACCESS_Frame( 2L ) ) 601 goto Fail2; 602 603 count = as->AlternateSetCount = GET_UShort(); 604 605 FORGET_Frame(); 606 607 as->AlternateSet = NULL; 608 609 if ( ALLOC_ARRAY( as->AlternateSet, count, HB_AlternateSet ) ) 610 goto Fail2; 611 612 aset = as->AlternateSet; 613 614 for ( n = 0; n < count; n++ ) 615 { 616 if ( ACCESS_Frame( 2L ) ) 617 goto Fail1; 618 619 new_offset = GET_UShort() + base_offset; 620 621 FORGET_Frame(); 622 623 cur_offset = FILE_Pos(); 624 if ( FILE_Seek( new_offset ) || 625 ( error = Load_AlternateSet( &aset[n], stream ) ) != HB_Err_Ok ) 626 goto Fail1; 627 (void)FILE_Seek( cur_offset ); 628 } 629 630 return HB_Err_Ok; 631 632 Fail1: 633 for ( m = 0; m < n; m++ ) 634 Free_AlternateSet( &aset[m] ); 635 636 FREE( aset ); 637 638 Fail2: 639 _HB_OPEN_Free_Coverage( &as->Coverage ); 640 return error; 641 } 642 643 644 static void Free_AlternateSubst( HB_GSUB_SubTable* st ) 645 { 646 HB_UShort n, count; 647 HB_AlternateSubst* as = &st->alternate; 648 649 HB_AlternateSet* aset; 650 651 652 if ( as->AlternateSet ) 653 { 654 count = as->AlternateSetCount; 655 aset = as->AlternateSet; 656 657 for ( n = 0; n < count; n++ ) 658 Free_AlternateSet( &aset[n] ); 659 660 FREE( aset ); 661 } 662 663 _HB_OPEN_Free_Coverage( &as->Coverage ); 664 } 665 666 667 static HB_Error Lookup_AlternateSubst( HB_GSUBHeader* gsub, 668 HB_GSUB_SubTable* st, 669 HB_Buffer buffer, 670 HB_UShort flags, 671 HB_UShort context_length, 672 int nesting_level ) 673 { 674 HB_Error error; 675 HB_UShort index, value, alt_index, property; 676 HB_AlternateSubst* as = &st->alternate; 677 HB_GDEFHeader* gdef = gsub->gdef; 678 HB_AlternateSet aset; 679 680 HB_UNUSED(nesting_level); 681 682 if ( context_length != 0xFFFF && context_length < 1 ) 683 return HB_Err_Not_Covered; 684 685 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) 686 return error; 687 688 error = _HB_OPEN_Coverage_Index( &as->Coverage, IN_CURGLYPH(), &index ); 689 if ( error ) 690 return error; 691 692 aset = as->AlternateSet[index]; 693 694 /* we use a user-defined callback function to get the alternate index */ 695 696 if ( gsub->altfunc ) 697 alt_index = (gsub->altfunc)( buffer->out_pos, IN_CURGLYPH(), 698 aset.GlyphCount, aset.Alternate, 699 gsub->data ); 700 else 701 alt_index = 0; 702 703 value = aset.Alternate[alt_index]; 704 if ( REPLACE_Glyph( buffer, value, nesting_level ) ) 705 return error; 706 707 if ( gdef && gdef->NewGlyphClasses ) 708 { 709 /* we inherit the old glyph class to the substituted glyph */ 710 711 error = _HB_GDEF_Add_Glyph_Property( gdef, value, property ); 712 if ( error && error != HB_Err_Not_Covered ) 713 return error; 714 } 715 716 return HB_Err_Ok; 717 } 718 719 720 /* LookupType 4 */ 721 722 /* Ligature */ 723 724 static HB_Error Load_Ligature( HB_Ligature* l, 725 HB_Stream stream ) 726 { 727 HB_Error error; 728 729 HB_UShort n, count; 730 HB_UShort* c; 731 732 733 if ( ACCESS_Frame( 4L ) ) 734 return error; 735 736 l->LigGlyph = GET_UShort(); 737 l->ComponentCount = GET_UShort(); 738 739 FORGET_Frame(); 740 741 l->Component = NULL; 742 743 count = l->ComponentCount - 1; /* only ComponentCount - 1 elements */ 744 745 if ( ALLOC_ARRAY( l->Component, count, HB_UShort ) ) 746 return error; 747 748 c = l->Component; 749 750 if ( ACCESS_Frame( count * 2L ) ) 751 { 752 FREE( c ); 753 return error; 754 } 755 756 for ( n = 0; n < count; n++ ) 757 c[n] = GET_UShort(); 758 759 FORGET_Frame(); 760 761 return HB_Err_Ok; 762 } 763 764 765 static void Free_Ligature( HB_Ligature* l ) 766 { 767 FREE( l->Component ); 768 } 769 770 771 /* LigatureSet */ 772 773 static HB_Error Load_LigatureSet( HB_LigatureSet* ls, 774 HB_Stream stream ) 775 { 776 HB_Error error; 777 778 HB_UShort n = 0, m, count; 779 HB_UInt cur_offset, new_offset, base_offset; 780 781 HB_Ligature* l; 782 783 784 base_offset = FILE_Pos(); 785 786 if ( ACCESS_Frame( 2L ) ) 787 return error; 788 789 count = ls->LigatureCount = GET_UShort(); 790 791 FORGET_Frame(); 792 793 ls->Ligature = NULL; 794 795 if ( ALLOC_ARRAY( ls->Ligature, count, HB_Ligature ) ) 796 return error; 797 798 l = ls->Ligature; 799 800 for ( n = 0; n < count; n++ ) 801 { 802 if ( ACCESS_Frame( 2L ) ) 803 goto Fail; 804 805 new_offset = GET_UShort() + base_offset; 806 807 FORGET_Frame(); 808 809 cur_offset = FILE_Pos(); 810 if ( FILE_Seek( new_offset ) || 811 ( error = Load_Ligature( &l[n], stream ) ) != HB_Err_Ok ) 812 goto Fail; 813 (void)FILE_Seek( cur_offset ); 814 } 815 816 return HB_Err_Ok; 817 818 Fail: 819 for ( m = 0; m < n; m++ ) 820 Free_Ligature( &l[m] ); 821 822 FREE( l ); 823 return error; 824 } 825 826 827 static void Free_LigatureSet( HB_LigatureSet* ls ) 828 { 829 HB_UShort n, count; 830 831 HB_Ligature* l; 832 833 834 if ( ls->Ligature ) 835 { 836 count = ls->LigatureCount; 837 l = ls->Ligature; 838 839 for ( n = 0; n < count; n++ ) 840 Free_Ligature( &l[n] ); 841 842 FREE( l ); 843 } 844 } 845 846 847 /* LigatureSubstFormat1 */ 848 849 static HB_Error Load_LigatureSubst( HB_GSUB_SubTable* st, 850 HB_Stream stream ) 851 { 852 HB_Error error; 853 HB_LigatureSubst* ls = &st->ligature; 854 855 HB_UShort n = 0, m, count; 856 HB_UInt cur_offset, new_offset, base_offset; 857 858 HB_LigatureSet* lset; 859 860 861 base_offset = FILE_Pos(); 862 863 if ( ACCESS_Frame( 4L ) ) 864 return error; 865 866 ls->SubstFormat = GET_UShort(); /* should be 1 */ 867 new_offset = GET_UShort() + base_offset; 868 869 FORGET_Frame(); 870 871 cur_offset = FILE_Pos(); 872 if ( FILE_Seek( new_offset ) || 873 ( error = _HB_OPEN_Load_Coverage( &ls->Coverage, stream ) ) != HB_Err_Ok ) 874 return error; 875 (void)FILE_Seek( cur_offset ); 876 877 if ( ACCESS_Frame( 2L ) ) 878 goto Fail2; 879 880 count = ls->LigatureSetCount = GET_UShort(); 881 882 FORGET_Frame(); 883 884 ls->LigatureSet = NULL; 885 886 if ( ALLOC_ARRAY( ls->LigatureSet, count, HB_LigatureSet ) ) 887 goto Fail2; 888 889 lset = ls->LigatureSet; 890 891 for ( n = 0; n < count; n++ ) 892 { 893 if ( ACCESS_Frame( 2L ) ) 894 goto Fail1; 895 896 new_offset = GET_UShort() + base_offset; 897 898 FORGET_Frame(); 899 900 cur_offset = FILE_Pos(); 901 if ( FILE_Seek( new_offset ) || 902 ( error = Load_LigatureSet( &lset[n], stream ) ) != HB_Err_Ok ) 903 goto Fail1; 904 (void)FILE_Seek( cur_offset ); 905 } 906 907 return HB_Err_Ok; 908 909 Fail1: 910 for ( m = 0; m < n; m++ ) 911 Free_LigatureSet( &lset[m] ); 912 913 FREE( lset ); 914 915 Fail2: 916 _HB_OPEN_Free_Coverage( &ls->Coverage ); 917 return error; 918 } 919 920 921 static void Free_LigatureSubst( HB_GSUB_SubTable* st ) 922 { 923 HB_UShort n, count; 924 HB_LigatureSubst* ls = &st->ligature; 925 926 HB_LigatureSet* lset; 927 928 929 if ( ls->LigatureSet ) 930 { 931 count = ls->LigatureSetCount; 932 lset = ls->LigatureSet; 933 934 for ( n = 0; n < count; n++ ) 935 Free_LigatureSet( &lset[n] ); 936 937 FREE( lset ); 938 } 939 940 _HB_OPEN_Free_Coverage( &ls->Coverage ); 941 } 942 943 944 static HB_Error Lookup_LigatureSubst( HB_GSUBHeader* gsub, 945 HB_GSUB_SubTable* st, 946 HB_Buffer buffer, 947 HB_UShort flags, 948 HB_UShort context_length, 949 int nesting_level ) 950 { 951 HB_UShort index, property; 952 HB_Error error; 953 HB_UShort numlig, i, j, is_mark, first_is_mark = FALSE; 954 HB_UShort* c; 955 HB_LigatureSubst* ls = &st->ligature; 956 HB_GDEFHeader* gdef = gsub->gdef; 957 958 HB_Ligature* lig; 959 960 HB_UNUSED(nesting_level); 961 962 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) 963 return error; 964 965 if ( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) 966 first_is_mark = TRUE; 967 968 error = _HB_OPEN_Coverage_Index( &ls->Coverage, IN_CURGLYPH(), &index ); 969 if ( error ) 970 return error; 971 972 if ( index >= ls->LigatureSetCount ) 973 return ERR(HB_Err_Invalid_SubTable); 974 975 lig = ls->LigatureSet[index].Ligature; 976 977 for ( numlig = ls->LigatureSet[index].LigatureCount; 978 numlig; 979 numlig--, lig++ ) 980 { 981 if ( buffer->in_pos + lig->ComponentCount > buffer->in_length ) 982 goto next_ligature; /* Not enough glyphs in input */ 983 984 c = lig->Component; 985 986 is_mark = first_is_mark; 987 988 if ( context_length != 0xFFFF && context_length < lig->ComponentCount ) 989 break; 990 991 for ( i = 1, j = buffer->in_pos + 1; i < lig->ComponentCount; i++, j++ ) 992 { 993 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) 994 { 995 if ( error && error != HB_Err_Not_Covered ) 996 return error; 997 998 if ( j + lig->ComponentCount - i == (HB_Int)buffer->in_length ) 999 goto next_ligature; 1000 j++; 1001 } 1002 1003 if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) ) 1004 is_mark = FALSE; 1005 1006 if ( IN_GLYPH( j ) != c[i - 1] ) 1007 goto next_ligature; 1008 } 1009 1010 if ( gdef && gdef->NewGlyphClasses ) 1011 { 1012 /* this is just a guess ... */ 1013 1014 error = _HB_GDEF_Add_Glyph_Property( gdef, lig->LigGlyph, 1015 is_mark ? HB_GDEF_MARK : HB_GDEF_LIGATURE ); 1016 if ( error && error != HB_Err_Not_Covered ) 1017 return error; 1018 } 1019 1020 if ( j == buffer->in_pos + i ) /* No input glyphs skipped */ 1021 { 1022 /* We don't use a new ligature ID if there are no skipped 1023 glyphs and the ligature already has an ID. */ 1024 1025 if ( IN_LIGID( buffer->in_pos ) ) 1026 { 1027 if ( ADD_String( buffer, i, 1, &lig->LigGlyph, 1028 0xFFFF, 0xFFFF ) ) 1029 return error; 1030 } 1031 else 1032 { 1033 HB_UShort ligID = _hb_buffer_allocate_ligid( buffer ); 1034 if ( ADD_String( buffer, i, 1, &lig->LigGlyph, 1035 0xFFFF, ligID ) ) 1036 return error; 1037 } 1038 } 1039 else 1040 { 1041 HB_UShort ligID = _hb_buffer_allocate_ligid( buffer ); 1042 if ( ADD_Glyph( buffer, lig->LigGlyph, 0xFFFF, ligID ) ) 1043 return error; 1044 1045 /* Now we must do a second loop to copy the skipped glyphs to 1046 `out' and assign component values to it. We start with the 1047 glyph after the first component. Glyphs between component 1048 i and i+1 belong to component i. Together with the ligID 1049 value it is later possible to check whether a specific 1050 component value really belongs to a given ligature. */ 1051 1052 for ( i = 0; i < lig->ComponentCount - 1; i++ ) 1053 { 1054 while ( CHECK_Property( gdef, IN_CURITEM(), 1055 flags, &property ) ) 1056 if ( ADD_Glyph( buffer, IN_CURGLYPH(), i, ligID ) ) 1057 return error; 1058 1059 (buffer->in_pos)++; 1060 } 1061 } 1062 1063 return HB_Err_Ok; 1064 1065 next_ligature: 1066 ; 1067 } 1068 1069 return HB_Err_Not_Covered; 1070 } 1071 1072 1073 /* Do the actual substitution for a context substitution (either format 1074 5 or 6). This is only called after we've determined that the input 1075 matches the subrule. */ 1076 1077 static HB_Error Do_ContextSubst( HB_GSUBHeader* gsub, 1078 HB_UShort GlyphCount, 1079 HB_UShort SubstCount, 1080 HB_SubstLookupRecord* subst, 1081 HB_Buffer buffer, 1082 int nesting_level ) 1083 { 1084 HB_Error error; 1085 HB_UInt i, old_pos; 1086 1087 1088 i = 0; 1089 1090 while ( i < GlyphCount ) 1091 { 1092 if ( SubstCount && i == subst->SequenceIndex ) 1093 { 1094 old_pos = buffer->in_pos; 1095 1096 /* Do a substitution */ 1097 1098 error = GSUB_Do_Glyph_Lookup( gsub, subst->LookupListIndex, buffer, 1099 GlyphCount, nesting_level ); 1100 1101 subst++; 1102 SubstCount--; 1103 i += buffer->in_pos - old_pos; 1104 1105 if ( error == HB_Err_Not_Covered ) 1106 { 1107 if ( COPY_Glyph( buffer ) ) 1108 return error; 1109 i++; 1110 } 1111 else if ( error ) 1112 return error; 1113 } 1114 else 1115 { 1116 /* No substitution for this index */ 1117 1118 if ( COPY_Glyph( buffer ) ) 1119 return error; 1120 i++; 1121 } 1122 } 1123 1124 return HB_Err_Ok; 1125 } 1126 1127 1128 /* LookupType 5 */ 1129 1130 /* SubRule */ 1131 1132 static HB_Error Load_SubRule( HB_SubRule* sr, 1133 HB_Stream stream ) 1134 { 1135 HB_Error error; 1136 1137 HB_UShort n, count; 1138 HB_UShort* i; 1139 1140 HB_SubstLookupRecord* slr; 1141 1142 1143 if ( ACCESS_Frame( 4L ) ) 1144 return error; 1145 1146 sr->GlyphCount = GET_UShort(); 1147 sr->SubstCount = GET_UShort(); 1148 1149 FORGET_Frame(); 1150 1151 sr->Input = NULL; 1152 1153 count = sr->GlyphCount - 1; /* only GlyphCount - 1 elements */ 1154 1155 if ( ALLOC_ARRAY( sr->Input, count, HB_UShort ) ) 1156 return error; 1157 1158 i = sr->Input; 1159 1160 if ( ACCESS_Frame( count * 2L ) ) 1161 goto Fail2; 1162 1163 for ( n = 0; n < count; n++ ) 1164 i[n] = GET_UShort(); 1165 1166 FORGET_Frame(); 1167 1168 sr->SubstLookupRecord = NULL; 1169 1170 count = sr->SubstCount; 1171 1172 if ( ALLOC_ARRAY( sr->SubstLookupRecord, count, HB_SubstLookupRecord ) ) 1173 goto Fail2; 1174 1175 slr = sr->SubstLookupRecord; 1176 1177 if ( ACCESS_Frame( count * 4L ) ) 1178 goto Fail1; 1179 1180 for ( n = 0; n < count; n++ ) 1181 { 1182 slr[n].SequenceIndex = GET_UShort(); 1183 slr[n].LookupListIndex = GET_UShort(); 1184 } 1185 1186 FORGET_Frame(); 1187 1188 return HB_Err_Ok; 1189 1190 Fail1: 1191 FREE( slr ); 1192 1193 Fail2: 1194 FREE( i ); 1195 return error; 1196 } 1197 1198 1199 static void Free_SubRule( HB_SubRule* sr ) 1200 { 1201 FREE( sr->SubstLookupRecord ); 1202 FREE( sr->Input ); 1203 } 1204 1205 1206 /* SubRuleSet */ 1207 1208 static HB_Error Load_SubRuleSet( HB_SubRuleSet* srs, 1209 HB_Stream stream ) 1210 { 1211 HB_Error error; 1212 1213 HB_UShort n = 0, m, count; 1214 HB_UInt cur_offset, new_offset, base_offset; 1215 1216 HB_SubRule* sr; 1217 1218 1219 base_offset = FILE_Pos(); 1220 1221 if ( ACCESS_Frame( 2L ) ) 1222 return error; 1223 1224 count = srs->SubRuleCount = GET_UShort(); 1225 1226 FORGET_Frame(); 1227 1228 srs->SubRule = NULL; 1229 1230 if ( ALLOC_ARRAY( srs->SubRule, count, HB_SubRule ) ) 1231 return error; 1232 1233 sr = srs->SubRule; 1234 1235 for ( n = 0; n < count; n++ ) 1236 { 1237 if ( ACCESS_Frame( 2L ) ) 1238 goto Fail; 1239 1240 new_offset = GET_UShort() + base_offset; 1241 1242 FORGET_Frame(); 1243 1244 cur_offset = FILE_Pos(); 1245 if ( FILE_Seek( new_offset ) || 1246 ( error = Load_SubRule( &sr[n], stream ) ) != HB_Err_Ok ) 1247 goto Fail; 1248 (void)FILE_Seek( cur_offset ); 1249 } 1250 1251 return HB_Err_Ok; 1252 1253 Fail: 1254 for ( m = 0; m < n; m++ ) 1255 Free_SubRule( &sr[m] ); 1256 1257 FREE( sr ); 1258 return error; 1259 } 1260 1261 1262 static void Free_SubRuleSet( HB_SubRuleSet* srs ) 1263 { 1264 HB_UShort n, count; 1265 1266 HB_SubRule* sr; 1267 1268 1269 if ( srs->SubRule ) 1270 { 1271 count = srs->SubRuleCount; 1272 sr = srs->SubRule; 1273 1274 for ( n = 0; n < count; n++ ) 1275 Free_SubRule( &sr[n] ); 1276 1277 FREE( sr ); 1278 } 1279 } 1280 1281 1282 /* ContextSubstFormat1 */ 1283 1284 static HB_Error Load_ContextSubst1( HB_ContextSubstFormat1* csf1, 1285 HB_Stream stream ) 1286 { 1287 HB_Error error; 1288 1289 HB_UShort n = 0, m, count; 1290 HB_UInt cur_offset, new_offset, base_offset; 1291 1292 HB_SubRuleSet* srs; 1293 1294 1295 base_offset = FILE_Pos() - 2L; 1296 1297 if ( ACCESS_Frame( 2L ) ) 1298 return error; 1299 1300 new_offset = GET_UShort() + base_offset; 1301 1302 FORGET_Frame(); 1303 1304 cur_offset = FILE_Pos(); 1305 if ( FILE_Seek( new_offset ) || 1306 ( error = _HB_OPEN_Load_Coverage( &csf1->Coverage, stream ) ) != HB_Err_Ok ) 1307 return error; 1308 (void)FILE_Seek( cur_offset ); 1309 1310 if ( ACCESS_Frame( 2L ) ) 1311 goto Fail2; 1312 1313 count = csf1->SubRuleSetCount = GET_UShort(); 1314 1315 FORGET_Frame(); 1316 1317 csf1->SubRuleSet = NULL; 1318 1319 if ( ALLOC_ARRAY( csf1->SubRuleSet, count, HB_SubRuleSet ) ) 1320 goto Fail2; 1321 1322 srs = csf1->SubRuleSet; 1323 1324 for ( n = 0; n < count; n++ ) 1325 { 1326 if ( ACCESS_Frame( 2L ) ) 1327 goto Fail1; 1328 1329 new_offset = GET_UShort() + base_offset; 1330 1331 FORGET_Frame(); 1332 1333 cur_offset = FILE_Pos(); 1334 if ( FILE_Seek( new_offset ) || 1335 ( error = Load_SubRuleSet( &srs[n], stream ) ) != HB_Err_Ok ) 1336 goto Fail1; 1337 (void)FILE_Seek( cur_offset ); 1338 } 1339 1340 return HB_Err_Ok; 1341 1342 Fail1: 1343 for ( m = 0; m < n; m++ ) 1344 Free_SubRuleSet( &srs[m] ); 1345 1346 FREE( srs ); 1347 1348 Fail2: 1349 _HB_OPEN_Free_Coverage( &csf1->Coverage ); 1350 return error; 1351 } 1352 1353 1354 static void Free_ContextSubst1( HB_ContextSubstFormat1* csf1 ) 1355 { 1356 HB_UShort n, count; 1357 1358 HB_SubRuleSet* srs; 1359 1360 1361 if ( csf1->SubRuleSet ) 1362 { 1363 count = csf1->SubRuleSetCount; 1364 srs = csf1->SubRuleSet; 1365 1366 for ( n = 0; n < count; n++ ) 1367 Free_SubRuleSet( &srs[n] ); 1368 1369 FREE( srs ); 1370 } 1371 1372 _HB_OPEN_Free_Coverage( &csf1->Coverage ); 1373 } 1374 1375 1376 /* SubClassRule */ 1377 1378 static HB_Error Load_SubClassRule( HB_ContextSubstFormat2* csf2, 1379 HB_SubClassRule* scr, 1380 HB_Stream stream ) 1381 { 1382 HB_Error error; 1383 1384 HB_UShort n, count; 1385 1386 HB_UShort* c; 1387 HB_SubstLookupRecord* slr; 1388 1389 1390 if ( ACCESS_Frame( 4L ) ) 1391 return error; 1392 1393 scr->GlyphCount = GET_UShort(); 1394 scr->SubstCount = GET_UShort(); 1395 1396 if ( scr->GlyphCount > csf2->MaxContextLength ) 1397 csf2->MaxContextLength = scr->GlyphCount; 1398 1399 FORGET_Frame(); 1400 1401 scr->Class = NULL; 1402 1403 count = scr->GlyphCount - 1; /* only GlyphCount - 1 elements */ 1404 1405 if ( ALLOC_ARRAY( scr->Class, count, HB_UShort ) ) 1406 return error; 1407 1408 c = scr->Class; 1409 1410 if ( ACCESS_Frame( count * 2L ) ) 1411 goto Fail2; 1412 1413 for ( n = 0; n < count; n++ ) 1414 c[n] = GET_UShort(); 1415 1416 FORGET_Frame(); 1417 1418 scr->SubstLookupRecord = NULL; 1419 1420 count = scr->SubstCount; 1421 1422 if ( ALLOC_ARRAY( scr->SubstLookupRecord, count, HB_SubstLookupRecord ) ) 1423 goto Fail2; 1424 1425 slr = scr->SubstLookupRecord; 1426 1427 if ( ACCESS_Frame( count * 4L ) ) 1428 goto Fail1; 1429 1430 for ( n = 0; n < count; n++ ) 1431 { 1432 slr[n].SequenceIndex = GET_UShort(); 1433 slr[n].LookupListIndex = GET_UShort(); 1434 } 1435 1436 FORGET_Frame(); 1437 1438 return HB_Err_Ok; 1439 1440 Fail1: 1441 FREE( slr ); 1442 1443 Fail2: 1444 FREE( c ); 1445 return error; 1446 } 1447 1448 1449 static void Free_SubClassRule( HB_SubClassRule* scr ) 1450 { 1451 FREE( scr->SubstLookupRecord ); 1452 FREE( scr->Class ); 1453 } 1454 1455 1456 /* SubClassSet */ 1457 1458 static HB_Error Load_SubClassSet( HB_ContextSubstFormat2* csf2, 1459 HB_SubClassSet* scs, 1460 HB_Stream stream ) 1461 { 1462 HB_Error error; 1463 1464 HB_UShort n = 0, m, count; 1465 HB_UInt cur_offset, new_offset, base_offset; 1466 1467 HB_SubClassRule* scr; 1468 1469 1470 base_offset = FILE_Pos(); 1471 1472 if ( ACCESS_Frame( 2L ) ) 1473 return error; 1474 1475 count = scs->SubClassRuleCount = GET_UShort(); 1476 1477 FORGET_Frame(); 1478 1479 scs->SubClassRule = NULL; 1480 1481 if ( ALLOC_ARRAY( scs->SubClassRule, count, HB_SubClassRule ) ) 1482 return error; 1483 1484 scr = scs->SubClassRule; 1485 1486 for ( n = 0; n < count; n++ ) 1487 { 1488 if ( ACCESS_Frame( 2L ) ) 1489 goto Fail; 1490 1491 new_offset = GET_UShort() + base_offset; 1492 1493 FORGET_Frame(); 1494 1495 cur_offset = FILE_Pos(); 1496 if ( FILE_Seek( new_offset ) || 1497 ( error = Load_SubClassRule( csf2, &scr[n], 1498 stream ) ) != HB_Err_Ok ) 1499 goto Fail; 1500 (void)FILE_Seek( cur_offset ); 1501 } 1502 1503 return HB_Err_Ok; 1504 1505 Fail: 1506 for ( m = 0; m < n; m++ ) 1507 Free_SubClassRule( &scr[m] ); 1508 1509 FREE( scr ); 1510 return error; 1511 } 1512 1513 1514 static void Free_SubClassSet( HB_SubClassSet* scs ) 1515 { 1516 HB_UShort n, count; 1517 1518 HB_SubClassRule* scr; 1519 1520 1521 if ( scs->SubClassRule ) 1522 { 1523 count = scs->SubClassRuleCount; 1524 scr = scs->SubClassRule; 1525 1526 for ( n = 0; n < count; n++ ) 1527 Free_SubClassRule( &scr[n] ); 1528 1529 FREE( scr ); 1530 } 1531 } 1532 1533 1534 /* ContextSubstFormat2 */ 1535 1536 static HB_Error Load_ContextSubst2( HB_ContextSubstFormat2* csf2, 1537 HB_Stream stream ) 1538 { 1539 HB_Error error; 1540 1541 HB_UShort n = 0, m, count; 1542 HB_UInt cur_offset, new_offset, base_offset; 1543 1544 HB_SubClassSet* scs; 1545 1546 1547 base_offset = FILE_Pos() - 2; 1548 1549 if ( ACCESS_Frame( 2L ) ) 1550 return error; 1551 1552 new_offset = GET_UShort() + base_offset; 1553 1554 FORGET_Frame(); 1555 1556 cur_offset = FILE_Pos(); 1557 if ( FILE_Seek( new_offset ) || 1558 ( error = _HB_OPEN_Load_Coverage( &csf2->Coverage, stream ) ) != HB_Err_Ok ) 1559 return error; 1560 (void)FILE_Seek( cur_offset ); 1561 1562 if ( ACCESS_Frame( 4L ) ) 1563 goto Fail3; 1564 1565 new_offset = GET_UShort() + base_offset; 1566 1567 /* `SubClassSetCount' is the upper limit for class values, thus we 1568 read it now to make an additional safety check. */ 1569 1570 count = csf2->SubClassSetCount = GET_UShort(); 1571 1572 FORGET_Frame(); 1573 1574 cur_offset = FILE_Pos(); 1575 if ( FILE_Seek( new_offset ) || 1576 ( error = _HB_OPEN_Load_ClassDefinition( &csf2->ClassDef, count, 1577 stream ) ) != HB_Err_Ok ) 1578 goto Fail3; 1579 (void)FILE_Seek( cur_offset ); 1580 1581 csf2->SubClassSet = NULL; 1582 csf2->MaxContextLength = 0; 1583 1584 if ( ALLOC_ARRAY( csf2->SubClassSet, count, HB_SubClassSet ) ) 1585 goto Fail2; 1586 1587 scs = csf2->SubClassSet; 1588 1589 for ( n = 0; n < count; n++ ) 1590 { 1591 if ( ACCESS_Frame( 2L ) ) 1592 goto Fail1; 1593 1594 new_offset = GET_UShort() + base_offset; 1595 1596 FORGET_Frame(); 1597 1598 if ( new_offset != base_offset ) /* not a NULL offset */ 1599 { 1600 cur_offset = FILE_Pos(); 1601 if ( FILE_Seek( new_offset ) || 1602 ( error = Load_SubClassSet( csf2, &scs[n], 1603 stream ) ) != HB_Err_Ok ) 1604 goto Fail1; 1605 (void)FILE_Seek( cur_offset ); 1606 } 1607 else 1608 { 1609 /* we create a SubClassSet table with no entries */ 1610 1611 csf2->SubClassSet[n].SubClassRuleCount = 0; 1612 csf2->SubClassSet[n].SubClassRule = NULL; 1613 } 1614 } 1615 1616 return HB_Err_Ok; 1617 1618 Fail1: 1619 for ( m = 0; m < n; m++ ) 1620 Free_SubClassSet( &scs[m] ); 1621 1622 FREE( scs ); 1623 1624 Fail2: 1625 _HB_OPEN_Free_ClassDefinition( &csf2->ClassDef ); 1626 1627 Fail3: 1628 _HB_OPEN_Free_Coverage( &csf2->Coverage ); 1629 return error; 1630 } 1631 1632 1633 static void Free_ContextSubst2( HB_ContextSubstFormat2* csf2 ) 1634 { 1635 HB_UShort n, count; 1636 1637 HB_SubClassSet* scs; 1638 1639 1640 if ( csf2->SubClassSet ) 1641 { 1642 count = csf2->SubClassSetCount; 1643 scs = csf2->SubClassSet; 1644 1645 for ( n = 0; n < count; n++ ) 1646 Free_SubClassSet( &scs[n] ); 1647 1648 FREE( scs ); 1649 } 1650 1651 _HB_OPEN_Free_ClassDefinition( &csf2->ClassDef ); 1652 _HB_OPEN_Free_Coverage( &csf2->Coverage ); 1653 } 1654 1655 1656 /* ContextSubstFormat3 */ 1657 1658 static HB_Error Load_ContextSubst3( HB_ContextSubstFormat3* csf3, 1659 HB_Stream stream ) 1660 { 1661 HB_Error error; 1662 1663 HB_UShort n = 0, m, count; 1664 HB_UInt cur_offset, new_offset, base_offset; 1665 1666 HB_Coverage* c; 1667 HB_SubstLookupRecord* slr; 1668 1669 1670 base_offset = FILE_Pos() - 2L; 1671 1672 if ( ACCESS_Frame( 4L ) ) 1673 return error; 1674 1675 csf3->GlyphCount = GET_UShort(); 1676 csf3->SubstCount = GET_UShort(); 1677 1678 FORGET_Frame(); 1679 1680 csf3->Coverage = NULL; 1681 1682 count = csf3->GlyphCount; 1683 1684 if ( ALLOC_ARRAY( csf3->Coverage, count, HB_Coverage ) ) 1685 return error; 1686 1687 c = csf3->Coverage; 1688 1689 for ( n = 0; n < count; n++ ) 1690 { 1691 if ( ACCESS_Frame( 2L ) ) 1692 goto Fail2; 1693 1694 new_offset = GET_UShort() + base_offset; 1695 1696 FORGET_Frame(); 1697 1698 cur_offset = FILE_Pos(); 1699 if ( FILE_Seek( new_offset ) || 1700 ( error = _HB_OPEN_Load_Coverage( &c[n], stream ) ) != HB_Err_Ok ) 1701 goto Fail2; 1702 (void)FILE_Seek( cur_offset ); 1703 } 1704 1705 csf3->SubstLookupRecord = NULL; 1706 1707 count = csf3->SubstCount; 1708 1709 if ( ALLOC_ARRAY( csf3->SubstLookupRecord, count, 1710 HB_SubstLookupRecord ) ) 1711 goto Fail2; 1712 1713 slr = csf3->SubstLookupRecord; 1714 1715 if ( ACCESS_Frame( count * 4L ) ) 1716 goto Fail1; 1717 1718 for ( n = 0; n < count; n++ ) 1719 { 1720 slr[n].SequenceIndex = GET_UShort(); 1721 slr[n].LookupListIndex = GET_UShort(); 1722 } 1723 1724 FORGET_Frame(); 1725 1726 return HB_Err_Ok; 1727 1728 Fail1: 1729 FREE( slr ); 1730 1731 Fail2: 1732 for ( m = 0; m < n; m++ ) 1733 _HB_OPEN_Free_Coverage( &c[m] ); 1734 1735 FREE( c ); 1736 return error; 1737 } 1738 1739 1740 static void Free_ContextSubst3( HB_ContextSubstFormat3* csf3 ) 1741 { 1742 HB_UShort n, count; 1743 1744 HB_Coverage* c; 1745 1746 1747 FREE( csf3->SubstLookupRecord ); 1748 1749 if ( csf3->Coverage ) 1750 { 1751 count = csf3->GlyphCount; 1752 c = csf3->Coverage; 1753 1754 for ( n = 0; n < count; n++ ) 1755 _HB_OPEN_Free_Coverage( &c[n] ); 1756 1757 FREE( c ); 1758 } 1759 } 1760 1761 1762 /* ContextSubst */ 1763 1764 static HB_Error Load_ContextSubst( HB_GSUB_SubTable* st, 1765 HB_Stream stream ) 1766 { 1767 HB_Error error; 1768 HB_ContextSubst* cs = &st->context; 1769 1770 1771 if ( ACCESS_Frame( 2L ) ) 1772 return error; 1773 1774 cs->SubstFormat = GET_UShort(); 1775 1776 FORGET_Frame(); 1777 1778 switch ( cs->SubstFormat ) 1779 { 1780 case 1: return Load_ContextSubst1( &cs->csf.csf1, stream ); 1781 case 2: return Load_ContextSubst2( &cs->csf.csf2, stream ); 1782 case 3: return Load_ContextSubst3( &cs->csf.csf3, stream ); 1783 default: return ERR(HB_Err_Invalid_SubTable_Format); 1784 } 1785 1786 return HB_Err_Ok; /* never reached */ 1787 } 1788 1789 1790 static void Free_ContextSubst( HB_GSUB_SubTable* st ) 1791 { 1792 HB_ContextSubst* cs = &st->context; 1793 1794 switch ( cs->SubstFormat ) 1795 { 1796 case 1: Free_ContextSubst1( &cs->csf.csf1 ); break; 1797 case 2: Free_ContextSubst2( &cs->csf.csf2 ); break; 1798 case 3: Free_ContextSubst3( &cs->csf.csf3 ); break; 1799 default: break; 1800 } 1801 } 1802 1803 1804 static HB_Error Lookup_ContextSubst1( HB_GSUBHeader* gsub, 1805 HB_ContextSubstFormat1* csf1, 1806 HB_Buffer buffer, 1807 HB_UShort flags, 1808 HB_UShort context_length, 1809 int nesting_level ) 1810 { 1811 HB_UShort index, property; 1812 HB_UShort i, j, k, numsr; 1813 HB_Error error; 1814 1815 HB_SubRule* sr; 1816 HB_GDEFHeader* gdef; 1817 1818 1819 gdef = gsub->gdef; 1820 1821 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) 1822 return error; 1823 1824 error = _HB_OPEN_Coverage_Index( &csf1->Coverage, IN_CURGLYPH(), &index ); 1825 if ( error ) 1826 return error; 1827 1828 sr = csf1->SubRuleSet[index].SubRule; 1829 numsr = csf1->SubRuleSet[index].SubRuleCount; 1830 1831 for ( k = 0; k < numsr; k++ ) 1832 { 1833 if ( context_length != 0xFFFF && context_length < sr[k].GlyphCount ) 1834 goto next_subrule; 1835 1836 if ( buffer->in_pos + sr[k].GlyphCount > buffer->in_length ) 1837 goto next_subrule; /* context is too long */ 1838 1839 for ( i = 1, j = buffer->in_pos + 1; i < sr[k].GlyphCount; i++, j++ ) 1840 { 1841 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) 1842 { 1843 if ( error && error != HB_Err_Not_Covered ) 1844 return error; 1845 1846 if ( j + sr[k].GlyphCount - i == (HB_Int)buffer->in_length ) 1847 goto next_subrule; 1848 j++; 1849 } 1850 1851 if ( IN_GLYPH( j ) != sr[k].Input[i - 1] ) 1852 goto next_subrule; 1853 } 1854 1855 return Do_ContextSubst( gsub, sr[k].GlyphCount, 1856 sr[k].SubstCount, sr[k].SubstLookupRecord, 1857 buffer, 1858 nesting_level ); 1859 next_subrule: 1860 ; 1861 } 1862 1863 return HB_Err_Not_Covered; 1864 } 1865 1866 1867 static HB_Error Lookup_ContextSubst2( HB_GSUBHeader* gsub, 1868 HB_ContextSubstFormat2* csf2, 1869 HB_Buffer buffer, 1870 HB_UShort flags, 1871 HB_UShort context_length, 1872 int nesting_level ) 1873 { 1874 HB_UShort index, property; 1875 HB_Error error; 1876 HB_UShort i, j, k, known_classes; 1877 1878 HB_UShort* classes; 1879 HB_UShort* cl; 1880 1881 HB_SubClassSet* scs; 1882 HB_SubClassRule* sr; 1883 HB_GDEFHeader* gdef; 1884 1885 1886 gdef = gsub->gdef; 1887 1888 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) 1889 return error; 1890 1891 /* Note: The coverage table in format 2 doesn't give an index into 1892 anything. It just lets us know whether or not we need to 1893 do any lookup at all. */ 1894 1895 error = _HB_OPEN_Coverage_Index( &csf2->Coverage, IN_CURGLYPH(), &index ); 1896 if ( error ) 1897 return error; 1898 1899 if (csf2->MaxContextLength < 1) 1900 return HB_Err_Not_Covered; 1901 1902 if ( ALLOC_ARRAY( classes, csf2->MaxContextLength, HB_UShort ) ) 1903 return error; 1904 1905 error = _HB_OPEN_Get_Class( &csf2->ClassDef, IN_CURGLYPH(), 1906 &classes[0], NULL ); 1907 if ( error && error != HB_Err_Not_Covered ) 1908 goto End; 1909 known_classes = 0; 1910 1911 scs = &csf2->SubClassSet[classes[0]]; 1912 if ( !scs ) 1913 { 1914 error = ERR(HB_Err_Invalid_SubTable); 1915 goto End; 1916 } 1917 1918 for ( k = 0; k < scs->SubClassRuleCount; k++ ) 1919 { 1920 sr = &scs->SubClassRule[k]; 1921 1922 if ( context_length != 0xFFFF && context_length < sr->GlyphCount ) 1923 goto next_subclassrule; 1924 1925 if ( buffer->in_pos + sr->GlyphCount > buffer->in_length ) 1926 goto next_subclassrule; /* context is too long */ 1927 1928 cl = sr->Class; 1929 1930 /* Start at 1 because [0] is implied */ 1931 1932 for ( i = 1, j = buffer->in_pos + 1; i < sr->GlyphCount; i++, j++ ) 1933 { 1934 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) 1935 { 1936 if ( error && error != HB_Err_Not_Covered ) 1937 goto End; 1938 1939 if ( j + sr->GlyphCount - i < (HB_Int)buffer->in_length ) 1940 goto next_subclassrule; 1941 j++; 1942 } 1943 1944 if ( i > known_classes ) 1945 { 1946 /* Keeps us from having to do this for each rule */ 1947 1948 error = _HB_OPEN_Get_Class( &csf2->ClassDef, IN_GLYPH( j ), &classes[i], NULL ); 1949 if ( error && error != HB_Err_Not_Covered ) 1950 goto End; 1951 known_classes = i; 1952 } 1953 1954 if ( cl[i - 1] != classes[i] ) 1955 goto next_subclassrule; 1956 } 1957 1958 error = Do_ContextSubst( gsub, sr->GlyphCount, 1959 sr->SubstCount, sr->SubstLookupRecord, 1960 buffer, 1961 nesting_level ); 1962 goto End; 1963 1964 next_subclassrule: 1965 ; 1966 } 1967 1968 error = HB_Err_Not_Covered; 1969 1970 End: 1971 FREE( classes ); 1972 return error; 1973 } 1974 1975 1976 static HB_Error Lookup_ContextSubst3( HB_GSUBHeader* gsub, 1977 HB_ContextSubstFormat3* csf3, 1978 HB_Buffer buffer, 1979 HB_UShort flags, 1980 HB_UShort context_length, 1981 int nesting_level ) 1982 { 1983 HB_Error error; 1984 HB_UShort index, i, j, property; 1985 1986 HB_Coverage* c; 1987 HB_GDEFHeader* gdef; 1988 1989 1990 gdef = gsub->gdef; 1991 1992 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) 1993 return error; 1994 1995 if ( context_length != 0xFFFF && context_length < csf3->GlyphCount ) 1996 return HB_Err_Not_Covered; 1997 1998 if ( buffer->in_pos + csf3->GlyphCount > buffer->in_length ) 1999 return HB_Err_Not_Covered; /* context is too long */ 2000 2001 c = csf3->Coverage; 2002 2003 for ( i = 1, j = buffer->in_pos + 1; i < csf3->GlyphCount; i++, j++ ) 2004 { 2005 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) 2006 { 2007 if ( error && error != HB_Err_Not_Covered ) 2008 return error; 2009 2010 if ( j + csf3->GlyphCount - i == (HB_Int)buffer->in_length ) 2011 return HB_Err_Not_Covered; 2012 j++; 2013 } 2014 2015 error = _HB_OPEN_Coverage_Index( &c[i], IN_GLYPH( j ), &index ); 2016 if ( error ) 2017 return error; 2018 } 2019 2020 return Do_ContextSubst( gsub, csf3->GlyphCount, 2021 csf3->SubstCount, csf3->SubstLookupRecord, 2022 buffer, 2023 nesting_level ); 2024 } 2025 2026 2027 static HB_Error Lookup_ContextSubst( HB_GSUBHeader* gsub, 2028 HB_GSUB_SubTable* st, 2029 HB_Buffer buffer, 2030 HB_UShort flags, 2031 HB_UShort context_length, 2032 int nesting_level ) 2033 { 2034 HB_ContextSubst* cs = &st->context; 2035 2036 switch ( cs->SubstFormat ) 2037 { 2038 case 1: return Lookup_ContextSubst1( gsub, &cs->csf.csf1, buffer, flags, context_length, nesting_level ); 2039 case 2: return Lookup_ContextSubst2( gsub, &cs->csf.csf2, buffer, flags, context_length, nesting_level ); 2040 case 3: return Lookup_ContextSubst3( gsub, &cs->csf.csf3, buffer, flags, context_length, nesting_level ); 2041 default: return ERR(HB_Err_Invalid_SubTable_Format); 2042 } 2043 2044 return HB_Err_Ok; /* never reached */ 2045 } 2046 2047 2048 /* LookupType 6 */ 2049 2050 /* ChainSubRule */ 2051 2052 static HB_Error Load_ChainSubRule( HB_ChainSubRule* csr, 2053 HB_Stream stream ) 2054 { 2055 HB_Error error; 2056 2057 HB_UShort n, count; 2058 HB_UShort* b; 2059 HB_UShort* i; 2060 HB_UShort* l; 2061 2062 HB_SubstLookupRecord* slr; 2063 2064 2065 if ( ACCESS_Frame( 2L ) ) 2066 return error; 2067 2068 csr->BacktrackGlyphCount = GET_UShort(); 2069 2070 FORGET_Frame(); 2071 2072 csr->Backtrack = NULL; 2073 2074 count = csr->BacktrackGlyphCount; 2075 2076 if ( ALLOC_ARRAY( csr->Backtrack, count, HB_UShort ) ) 2077 return error; 2078 2079 b = csr->Backtrack; 2080 2081 if ( ACCESS_Frame( count * 2L ) ) 2082 goto Fail4; 2083 2084 for ( n = 0; n < count; n++ ) 2085 b[n] = GET_UShort(); 2086 2087 FORGET_Frame(); 2088 2089 if ( ACCESS_Frame( 2L ) ) 2090 goto Fail4; 2091 2092 csr->InputGlyphCount = GET_UShort(); 2093 2094 FORGET_Frame(); 2095 2096 csr->Input = NULL; 2097 2098 count = csr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */ 2099 2100 if ( ALLOC_ARRAY( csr->Input, count, HB_UShort ) ) 2101 goto Fail4; 2102 2103 i = csr->Input; 2104 2105 if ( ACCESS_Frame( count * 2L ) ) 2106 goto Fail3; 2107 2108 for ( n = 0; n < count; n++ ) 2109 i[n] = GET_UShort(); 2110 2111 FORGET_Frame(); 2112 2113 if ( ACCESS_Frame( 2L ) ) 2114 goto Fail3; 2115 2116 csr->LookaheadGlyphCount = GET_UShort(); 2117 2118 FORGET_Frame(); 2119 2120 csr->Lookahead = NULL; 2121 2122 count = csr->LookaheadGlyphCount; 2123 2124 if ( ALLOC_ARRAY( csr->Lookahead, count, HB_UShort ) ) 2125 goto Fail3; 2126 2127 l = csr->Lookahead; 2128 2129 if ( ACCESS_Frame( count * 2L ) ) 2130 goto Fail2; 2131 2132 for ( n = 0; n < count; n++ ) 2133 l[n] = GET_UShort(); 2134 2135 FORGET_Frame(); 2136 2137 if ( ACCESS_Frame( 2L ) ) 2138 goto Fail2; 2139 2140 csr->SubstCount = GET_UShort(); 2141 2142 FORGET_Frame(); 2143 2144 csr->SubstLookupRecord = NULL; 2145 2146 count = csr->SubstCount; 2147 2148 if ( ALLOC_ARRAY( csr->SubstLookupRecord, count, HB_SubstLookupRecord ) ) 2149 goto Fail2; 2150 2151 slr = csr->SubstLookupRecord; 2152 2153 if ( ACCESS_Frame( count * 4L ) ) 2154 goto Fail1; 2155 2156 for ( n = 0; n < count; n++ ) 2157 { 2158 slr[n].SequenceIndex = GET_UShort(); 2159 slr[n].LookupListIndex = GET_UShort(); 2160 } 2161 2162 FORGET_Frame(); 2163 2164 return HB_Err_Ok; 2165 2166 Fail1: 2167 FREE( slr ); 2168 2169 Fail2: 2170 FREE( l ); 2171 2172 Fail3: 2173 FREE( i ); 2174 2175 Fail4: 2176 FREE( b ); 2177 return error; 2178 } 2179 2180 2181 static void Free_ChainSubRule( HB_ChainSubRule* csr ) 2182 { 2183 FREE( csr->SubstLookupRecord ); 2184 FREE( csr->Lookahead ); 2185 FREE( csr->Input ); 2186 FREE( csr->Backtrack ); 2187 } 2188 2189 2190 /* ChainSubRuleSet */ 2191 2192 static HB_Error Load_ChainSubRuleSet( HB_ChainSubRuleSet* csrs, 2193 HB_Stream stream ) 2194 { 2195 HB_Error error; 2196 2197 HB_UShort n = 0, m, count; 2198 HB_UInt cur_offset, new_offset, base_offset; 2199 2200 HB_ChainSubRule* csr; 2201 2202 2203 base_offset = FILE_Pos(); 2204 2205 if ( ACCESS_Frame( 2L ) ) 2206 return error; 2207 2208 count = csrs->ChainSubRuleCount = GET_UShort(); 2209 2210 FORGET_Frame(); 2211 2212 csrs->ChainSubRule = NULL; 2213 2214 if ( ALLOC_ARRAY( csrs->ChainSubRule, count, HB_ChainSubRule ) ) 2215 return error; 2216 2217 csr = csrs->ChainSubRule; 2218 2219 for ( n = 0; n < count; n++ ) 2220 { 2221 if ( ACCESS_Frame( 2L ) ) 2222 goto Fail; 2223 2224 new_offset = GET_UShort() + base_offset; 2225 2226 FORGET_Frame(); 2227 2228 cur_offset = FILE_Pos(); 2229 if ( FILE_Seek( new_offset ) || 2230 ( error = Load_ChainSubRule( &csr[n], stream ) ) != HB_Err_Ok ) 2231 goto Fail; 2232 (void)FILE_Seek( cur_offset ); 2233 } 2234 2235 return HB_Err_Ok; 2236 2237 Fail: 2238 for ( m = 0; m < n; m++ ) 2239 Free_ChainSubRule( &csr[m] ); 2240 2241 FREE( csr ); 2242 return error; 2243 } 2244 2245 2246 static void Free_ChainSubRuleSet( HB_ChainSubRuleSet* csrs ) 2247 { 2248 HB_UShort n, count; 2249 2250 HB_ChainSubRule* csr; 2251 2252 2253 if ( csrs->ChainSubRule ) 2254 { 2255 count = csrs->ChainSubRuleCount; 2256 csr = csrs->ChainSubRule; 2257 2258 for ( n = 0; n < count; n++ ) 2259 Free_ChainSubRule( &csr[n] ); 2260 2261 FREE( csr ); 2262 } 2263 } 2264 2265 2266 /* ChainContextSubstFormat1 */ 2267 2268 static HB_Error Load_ChainContextSubst1( 2269 HB_ChainContextSubstFormat1* ccsf1, 2270 HB_Stream stream ) 2271 { 2272 HB_Error error; 2273 2274 HB_UShort n = 0, m, count; 2275 HB_UInt cur_offset, new_offset, base_offset; 2276 2277 HB_ChainSubRuleSet* csrs; 2278 2279 2280 base_offset = FILE_Pos() - 2L; 2281 2282 if ( ACCESS_Frame( 2L ) ) 2283 return error; 2284 2285 new_offset = GET_UShort() + base_offset; 2286 2287 FORGET_Frame(); 2288 2289 cur_offset = FILE_Pos(); 2290 if ( FILE_Seek( new_offset ) || 2291 ( error = _HB_OPEN_Load_Coverage( &ccsf1->Coverage, stream ) ) != HB_Err_Ok ) 2292 return error; 2293 (void)FILE_Seek( cur_offset ); 2294 2295 if ( ACCESS_Frame( 2L ) ) 2296 goto Fail2; 2297 2298 count = ccsf1->ChainSubRuleSetCount = GET_UShort(); 2299 2300 FORGET_Frame(); 2301 2302 ccsf1->ChainSubRuleSet = NULL; 2303 2304 if ( ALLOC_ARRAY( ccsf1->ChainSubRuleSet, count, HB_ChainSubRuleSet ) ) 2305 goto Fail2; 2306 2307 csrs = ccsf1->ChainSubRuleSet; 2308 2309 for ( n = 0; n < count; n++ ) 2310 { 2311 if ( ACCESS_Frame( 2L ) ) 2312 goto Fail1; 2313 2314 new_offset = GET_UShort() + base_offset; 2315 2316 FORGET_Frame(); 2317 2318 cur_offset = FILE_Pos(); 2319 if ( FILE_Seek( new_offset ) || 2320 ( error = Load_ChainSubRuleSet( &csrs[n], stream ) ) != HB_Err_Ok ) 2321 goto Fail1; 2322 (void)FILE_Seek( cur_offset ); 2323 } 2324 2325 return HB_Err_Ok; 2326 2327 Fail1: 2328 for ( m = 0; m < n; m++ ) 2329 Free_ChainSubRuleSet( &csrs[m] ); 2330 2331 FREE( csrs ); 2332 2333 Fail2: 2334 _HB_OPEN_Free_Coverage( &ccsf1->Coverage ); 2335 return error; 2336 } 2337 2338 2339 static void Free_ChainContextSubst1( HB_ChainContextSubstFormat1* ccsf1 ) 2340 { 2341 HB_UShort n, count; 2342 2343 HB_ChainSubRuleSet* csrs; 2344 2345 2346 if ( ccsf1->ChainSubRuleSet ) 2347 { 2348 count = ccsf1->ChainSubRuleSetCount; 2349 csrs = ccsf1->ChainSubRuleSet; 2350 2351 for ( n = 0; n < count; n++ ) 2352 Free_ChainSubRuleSet( &csrs[n] ); 2353 2354 FREE( csrs ); 2355 } 2356 2357 _HB_OPEN_Free_Coverage( &ccsf1->Coverage ); 2358 } 2359 2360 2361 /* ChainSubClassRule */ 2362 2363 static HB_Error Load_ChainSubClassRule( 2364 HB_ChainContextSubstFormat2* ccsf2, 2365 HB_ChainSubClassRule* cscr, 2366 HB_Stream stream ) 2367 { 2368 HB_Error error; 2369 2370 HB_UShort n, count; 2371 2372 HB_UShort* b; 2373 HB_UShort* i; 2374 HB_UShort* l; 2375 HB_SubstLookupRecord* slr; 2376 2377 2378 if ( ACCESS_Frame( 2L ) ) 2379 return error; 2380 2381 cscr->BacktrackGlyphCount = GET_UShort(); 2382 2383 FORGET_Frame(); 2384 2385 if ( cscr->BacktrackGlyphCount > ccsf2->MaxBacktrackLength ) 2386 ccsf2->MaxBacktrackLength = cscr->BacktrackGlyphCount; 2387 2388 cscr->Backtrack = NULL; 2389 2390 count = cscr->BacktrackGlyphCount; 2391 2392 if ( ALLOC_ARRAY( cscr->Backtrack, count, HB_UShort ) ) 2393 return error; 2394 2395 b = cscr->Backtrack; 2396 2397 if ( ACCESS_Frame( count * 2L ) ) 2398 goto Fail4; 2399 2400 for ( n = 0; n < count; n++ ) 2401 b[n] = GET_UShort(); 2402 2403 FORGET_Frame(); 2404 2405 if ( ACCESS_Frame( 2L ) ) 2406 goto Fail4; 2407 2408 cscr->InputGlyphCount = GET_UShort(); 2409 2410 FORGET_Frame(); 2411 2412 if ( cscr->InputGlyphCount > ccsf2->MaxInputLength ) 2413 ccsf2->MaxInputLength = cscr->InputGlyphCount; 2414 2415 cscr->Input = NULL; 2416 2417 count = cscr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */ 2418 2419 if ( ALLOC_ARRAY( cscr->Input, count, HB_UShort ) ) 2420 goto Fail4; 2421 2422 i = cscr->Input; 2423 2424 if ( ACCESS_Frame( count * 2L ) ) 2425 goto Fail3; 2426 2427 for ( n = 0; n < count; n++ ) 2428 i[n] = GET_UShort(); 2429 2430 FORGET_Frame(); 2431 2432 if ( ACCESS_Frame( 2L ) ) 2433 goto Fail3; 2434 2435 cscr->LookaheadGlyphCount = GET_UShort(); 2436 2437 FORGET_Frame(); 2438 2439 if ( cscr->LookaheadGlyphCount > ccsf2->MaxLookaheadLength ) 2440 ccsf2->MaxLookaheadLength = cscr->LookaheadGlyphCount; 2441 2442 cscr->Lookahead = NULL; 2443 2444 count = cscr->LookaheadGlyphCount; 2445 2446 if ( ALLOC_ARRAY( cscr->Lookahead, count, HB_UShort ) ) 2447 goto Fail3; 2448 2449 l = cscr->Lookahead; 2450 2451 if ( ACCESS_Frame( count * 2L ) ) 2452 goto Fail2; 2453 2454 for ( n = 0; n < count; n++ ) 2455 l[n] = GET_UShort(); 2456 2457 FORGET_Frame(); 2458 2459 if ( ACCESS_Frame( 2L ) ) 2460 goto Fail2; 2461 2462 cscr->SubstCount = GET_UShort(); 2463 2464 FORGET_Frame(); 2465 2466 cscr->SubstLookupRecord = NULL; 2467 2468 count = cscr->SubstCount; 2469 2470 if ( ALLOC_ARRAY( cscr->SubstLookupRecord, count, 2471 HB_SubstLookupRecord ) ) 2472 goto Fail2; 2473 2474 slr = cscr->SubstLookupRecord; 2475 2476 if ( ACCESS_Frame( count * 4L ) ) 2477 goto Fail1; 2478 2479 for ( n = 0; n < count; n++ ) 2480 { 2481 slr[n].SequenceIndex = GET_UShort(); 2482 slr[n].LookupListIndex = GET_UShort(); 2483 } 2484 2485 FORGET_Frame(); 2486 2487 return HB_Err_Ok; 2488 2489 Fail1: 2490 FREE( slr ); 2491 2492 Fail2: 2493 FREE( l ); 2494 2495 Fail3: 2496 FREE( i ); 2497 2498 Fail4: 2499 FREE( b ); 2500 return error; 2501 } 2502 2503 2504 static void Free_ChainSubClassRule( HB_ChainSubClassRule* cscr ) 2505 { 2506 FREE( cscr->SubstLookupRecord ); 2507 FREE( cscr->Lookahead ); 2508 FREE( cscr->Input ); 2509 FREE( cscr->Backtrack ); 2510 } 2511 2512 2513 /* SubClassSet */ 2514 2515 static HB_Error Load_ChainSubClassSet( 2516 HB_ChainContextSubstFormat2* ccsf2, 2517 HB_ChainSubClassSet* cscs, 2518 HB_Stream stream ) 2519 { 2520 HB_Error error; 2521 2522 HB_UShort n = 0, m, count; 2523 HB_UInt cur_offset, new_offset, base_offset; 2524 2525 HB_ChainSubClassRule* cscr; 2526 2527 2528 base_offset = FILE_Pos(); 2529 2530 if ( ACCESS_Frame( 2L ) ) 2531 return error; 2532 2533 count = cscs->ChainSubClassRuleCount = GET_UShort(); 2534 2535 FORGET_Frame(); 2536 2537 cscs->ChainSubClassRule = NULL; 2538 2539 if ( ALLOC_ARRAY( cscs->ChainSubClassRule, count, 2540 HB_ChainSubClassRule ) ) 2541 return error; 2542 2543 cscr = cscs->ChainSubClassRule; 2544 2545 for ( n = 0; n < count; n++ ) 2546 { 2547 if ( ACCESS_Frame( 2L ) ) 2548 goto Fail; 2549 2550 new_offset = GET_UShort() + base_offset; 2551 2552 FORGET_Frame(); 2553 2554 cur_offset = FILE_Pos(); 2555 if ( FILE_Seek( new_offset ) || 2556 ( error = Load_ChainSubClassRule( ccsf2, &cscr[n], 2557 stream ) ) != HB_Err_Ok ) 2558 goto Fail; 2559 (void)FILE_Seek( cur_offset ); 2560 } 2561 2562 return HB_Err_Ok; 2563 2564 Fail: 2565 for ( m = 0; m < n; m++ ) 2566 Free_ChainSubClassRule( &cscr[m] ); 2567 2568 FREE( cscr ); 2569 return error; 2570 } 2571 2572 2573 static void Free_ChainSubClassSet( HB_ChainSubClassSet* cscs ) 2574 { 2575 HB_UShort n, count; 2576 2577 HB_ChainSubClassRule* cscr; 2578 2579 2580 if ( cscs->ChainSubClassRule ) 2581 { 2582 count = cscs->ChainSubClassRuleCount; 2583 cscr = cscs->ChainSubClassRule; 2584 2585 for ( n = 0; n < count; n++ ) 2586 Free_ChainSubClassRule( &cscr[n] ); 2587 2588 FREE( cscr ); 2589 } 2590 } 2591 2592 2593 /* ChainContextSubstFormat2 */ 2594 2595 static HB_Error Load_ChainContextSubst2( 2596 HB_ChainContextSubstFormat2* ccsf2, 2597 HB_Stream stream ) 2598 { 2599 HB_Error error; 2600 2601 HB_UShort n = 0, m, count; 2602 HB_UInt cur_offset, new_offset, base_offset; 2603 HB_UInt backtrack_offset, input_offset, lookahead_offset; 2604 2605 HB_ChainSubClassSet* cscs; 2606 2607 2608 base_offset = FILE_Pos() - 2; 2609 2610 if ( ACCESS_Frame( 2L ) ) 2611 return error; 2612 2613 new_offset = GET_UShort() + base_offset; 2614 2615 FORGET_Frame(); 2616 2617 cur_offset = FILE_Pos(); 2618 if ( FILE_Seek( new_offset ) || 2619 ( error = _HB_OPEN_Load_Coverage( &ccsf2->Coverage, stream ) ) != HB_Err_Ok ) 2620 return error; 2621 (void)FILE_Seek( cur_offset ); 2622 2623 if ( ACCESS_Frame( 8L ) ) 2624 goto Fail5; 2625 2626 backtrack_offset = GET_UShort(); 2627 input_offset = GET_UShort(); 2628 lookahead_offset = GET_UShort(); 2629 2630 /* `ChainSubClassSetCount' is the upper limit for input class values, 2631 thus we read it now to make an additional safety check. No limit 2632 is known or needed for the other two class definitions */ 2633 2634 count = ccsf2->ChainSubClassSetCount = GET_UShort(); 2635 2636 FORGET_Frame(); 2637 2638 if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccsf2->BacktrackClassDef, 65535, 2639 backtrack_offset, base_offset, 2640 stream ) ) != HB_Err_Ok ) 2641 goto Fail5; 2642 2643 if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccsf2->InputClassDef, count, 2644 input_offset, base_offset, 2645 stream ) ) != HB_Err_Ok ) 2646 goto Fail4; 2647 if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccsf2->LookaheadClassDef, 65535, 2648 lookahead_offset, base_offset, 2649 stream ) ) != HB_Err_Ok ) 2650 goto Fail3; 2651 2652 ccsf2->ChainSubClassSet = NULL; 2653 ccsf2->MaxBacktrackLength = 0; 2654 ccsf2->MaxInputLength = 0; 2655 ccsf2->MaxLookaheadLength = 0; 2656 2657 if ( ALLOC_ARRAY( ccsf2->ChainSubClassSet, count, HB_ChainSubClassSet ) ) 2658 goto Fail2; 2659 2660 cscs = ccsf2->ChainSubClassSet; 2661 2662 for ( n = 0; n < count; n++ ) 2663 { 2664 if ( ACCESS_Frame( 2L ) ) 2665 goto Fail1; 2666 2667 new_offset = GET_UShort() + base_offset; 2668 2669 FORGET_Frame(); 2670 2671 if ( new_offset != base_offset ) /* not a NULL offset */ 2672 { 2673 cur_offset = FILE_Pos(); 2674 if ( FILE_Seek( new_offset ) || 2675 ( error = Load_ChainSubClassSet( ccsf2, &cscs[n], 2676 stream ) ) != HB_Err_Ok ) 2677 goto Fail1; 2678 (void)FILE_Seek( cur_offset ); 2679 } 2680 else 2681 { 2682 /* we create a ChainSubClassSet table with no entries */ 2683 2684 ccsf2->ChainSubClassSet[n].ChainSubClassRuleCount = 0; 2685 ccsf2->ChainSubClassSet[n].ChainSubClassRule = NULL; 2686 } 2687 } 2688 2689 return HB_Err_Ok; 2690 2691 Fail1: 2692 for ( m = 0; m < n; m++ ) 2693 Free_ChainSubClassSet( &cscs[m] ); 2694 2695 FREE( cscs ); 2696 2697 Fail2: 2698 _HB_OPEN_Free_ClassDefinition( &ccsf2->LookaheadClassDef ); 2699 2700 Fail3: 2701 _HB_OPEN_Free_ClassDefinition( &ccsf2->InputClassDef ); 2702 2703 Fail4: 2704 _HB_OPEN_Free_ClassDefinition( &ccsf2->BacktrackClassDef ); 2705 2706 Fail5: 2707 _HB_OPEN_Free_Coverage( &ccsf2->Coverage ); 2708 return error; 2709 } 2710 2711 2712 static void Free_ChainContextSubst2( HB_ChainContextSubstFormat2* ccsf2 ) 2713 { 2714 HB_UShort n, count; 2715 2716 HB_ChainSubClassSet* cscs; 2717 2718 2719 if ( ccsf2->ChainSubClassSet ) 2720 { 2721 count = ccsf2->ChainSubClassSetCount; 2722 cscs = ccsf2->ChainSubClassSet; 2723 2724 for ( n = 0; n < count; n++ ) 2725 Free_ChainSubClassSet( &cscs[n] ); 2726 2727 FREE( cscs ); 2728 } 2729 2730 _HB_OPEN_Free_ClassDefinition( &ccsf2->LookaheadClassDef ); 2731 _HB_OPEN_Free_ClassDefinition( &ccsf2->InputClassDef ); 2732 _HB_OPEN_Free_ClassDefinition( &ccsf2->BacktrackClassDef ); 2733 2734 _HB_OPEN_Free_Coverage( &ccsf2->Coverage ); 2735 } 2736 2737 2738 /* ChainContextSubstFormat3 */ 2739 2740 static HB_Error Load_ChainContextSubst3( 2741 HB_ChainContextSubstFormat3* ccsf3, 2742 HB_Stream stream ) 2743 { 2744 HB_Error error; 2745 2746 HB_UShort n, nb = 0, ni =0, nl = 0, m, count; 2747 HB_UShort backtrack_count, input_count, lookahead_count; 2748 HB_UInt cur_offset, new_offset, base_offset; 2749 2750 HB_Coverage* b; 2751 HB_Coverage* i; 2752 HB_Coverage* l; 2753 HB_SubstLookupRecord* slr; 2754 2755 2756 base_offset = FILE_Pos() - 2L; 2757 2758 if ( ACCESS_Frame( 2L ) ) 2759 return error; 2760 2761 ccsf3->BacktrackGlyphCount = GET_UShort(); 2762 2763 FORGET_Frame(); 2764 2765 ccsf3->BacktrackCoverage = NULL; 2766 2767 backtrack_count = ccsf3->BacktrackGlyphCount; 2768 2769 if ( ALLOC_ARRAY( ccsf3->BacktrackCoverage, backtrack_count, 2770 HB_Coverage ) ) 2771 return error; 2772 2773 b = ccsf3->BacktrackCoverage; 2774 2775 for ( nb = 0; nb < backtrack_count; nb++ ) 2776 { 2777 if ( ACCESS_Frame( 2L ) ) 2778 goto Fail4; 2779 2780 new_offset = GET_UShort() + base_offset; 2781 2782 FORGET_Frame(); 2783 2784 cur_offset = FILE_Pos(); 2785 if ( FILE_Seek( new_offset ) || 2786 ( error = _HB_OPEN_Load_Coverage( &b[nb], stream ) ) != HB_Err_Ok ) 2787 goto Fail4; 2788 (void)FILE_Seek( cur_offset ); 2789 } 2790 2791 if ( ACCESS_Frame( 2L ) ) 2792 goto Fail4; 2793 2794 ccsf3->InputGlyphCount = GET_UShort(); 2795 2796 FORGET_Frame(); 2797 2798 ccsf3->InputCoverage = NULL; 2799 2800 input_count = ccsf3->InputGlyphCount; 2801 2802 if ( ALLOC_ARRAY( ccsf3->InputCoverage, input_count, HB_Coverage ) ) 2803 goto Fail4; 2804 2805 i = ccsf3->InputCoverage; 2806 2807 for ( ni = 0; ni < input_count; ni++ ) 2808 { 2809 if ( ACCESS_Frame( 2L ) ) 2810 goto Fail3; 2811 2812 new_offset = GET_UShort() + base_offset; 2813 2814 FORGET_Frame(); 2815 2816 cur_offset = FILE_Pos(); 2817 if ( FILE_Seek( new_offset ) || 2818 ( error = _HB_OPEN_Load_Coverage( &i[ni], stream ) ) != HB_Err_Ok ) 2819 goto Fail3; 2820 (void)FILE_Seek( cur_offset ); 2821 } 2822 2823 if ( ACCESS_Frame( 2L ) ) 2824 goto Fail3; 2825 2826 ccsf3->LookaheadGlyphCount = GET_UShort(); 2827 2828 FORGET_Frame(); 2829 2830 ccsf3->LookaheadCoverage = NULL; 2831 2832 lookahead_count = ccsf3->LookaheadGlyphCount; 2833 2834 if ( ALLOC_ARRAY( ccsf3->LookaheadCoverage, lookahead_count, 2835 HB_Coverage ) ) 2836 goto Fail3; 2837 2838 l = ccsf3->LookaheadCoverage; 2839 2840 for ( nl = 0; nl < lookahead_count; nl++ ) 2841 { 2842 if ( ACCESS_Frame( 2L ) ) 2843 goto Fail2; 2844 2845 new_offset = GET_UShort() + base_offset; 2846 2847 FORGET_Frame(); 2848 2849 cur_offset = FILE_Pos(); 2850 if ( FILE_Seek( new_offset ) || 2851 ( error = _HB_OPEN_Load_Coverage( &l[nl], stream ) ) != HB_Err_Ok ) 2852 goto Fail2; 2853 (void)FILE_Seek( cur_offset ); 2854 } 2855 2856 if ( ACCESS_Frame( 2L ) ) 2857 goto Fail2; 2858 2859 ccsf3->SubstCount = GET_UShort(); 2860 2861 FORGET_Frame(); 2862 2863 ccsf3->SubstLookupRecord = NULL; 2864 2865 count = ccsf3->SubstCount; 2866 2867 if ( ALLOC_ARRAY( ccsf3->SubstLookupRecord, count, 2868 HB_SubstLookupRecord ) ) 2869 goto Fail2; 2870 2871 slr = ccsf3->SubstLookupRecord; 2872 2873 if ( ACCESS_Frame( count * 4L ) ) 2874 goto Fail1; 2875 2876 for ( n = 0; n < count; n++ ) 2877 { 2878 slr[n].SequenceIndex = GET_UShort(); 2879 slr[n].LookupListIndex = GET_UShort(); 2880 } 2881 2882 FORGET_Frame(); 2883 2884 return HB_Err_Ok; 2885 2886 Fail1: 2887 FREE( slr ); 2888 2889 Fail2: 2890 for ( m = 0; m < nl; m++ ) 2891 _HB_OPEN_Free_Coverage( &l[m] ); 2892 2893 FREE( l ); 2894 2895 Fail3: 2896 for ( m = 0; m < ni; m++ ) 2897 _HB_OPEN_Free_Coverage( &i[m] ); 2898 2899 FREE( i ); 2900 2901 Fail4: 2902 for ( m = 0; m < nb; m++ ) 2903 _HB_OPEN_Free_Coverage( &b[m] ); 2904 2905 FREE( b ); 2906 return error; 2907 } 2908 2909 2910 static void Free_ChainContextSubst3( HB_ChainContextSubstFormat3* ccsf3 ) 2911 { 2912 HB_UShort n, count; 2913 2914 HB_Coverage* c; 2915 2916 2917 FREE( ccsf3->SubstLookupRecord ); 2918 2919 if ( ccsf3->LookaheadCoverage ) 2920 { 2921 count = ccsf3->LookaheadGlyphCount; 2922 c = ccsf3->LookaheadCoverage; 2923 2924 for ( n = 0; n < count; n++ ) 2925 _HB_OPEN_Free_Coverage( &c[n] ); 2926 2927 FREE( c ); 2928 } 2929 2930 if ( ccsf3->InputCoverage ) 2931 { 2932 count = ccsf3->InputGlyphCount; 2933 c = ccsf3->InputCoverage; 2934 2935 for ( n = 0; n < count; n++ ) 2936 _HB_OPEN_Free_Coverage( &c[n] ); 2937 2938 FREE( c ); 2939 } 2940 2941 if ( ccsf3->BacktrackCoverage ) 2942 { 2943 count = ccsf3->BacktrackGlyphCount; 2944 c = ccsf3->BacktrackCoverage; 2945 2946 for ( n = 0; n < count; n++ ) 2947 _HB_OPEN_Free_Coverage( &c[n] ); 2948 2949 FREE( c ); 2950 } 2951 } 2952 2953 2954 /* ChainContextSubst */ 2955 2956 static HB_Error Load_ChainContextSubst( HB_GSUB_SubTable* st, 2957 HB_Stream stream ) 2958 { 2959 HB_Error error; 2960 HB_ChainContextSubst* ccs = &st->chain; 2961 2962 if ( ACCESS_Frame( 2L ) ) 2963 return error; 2964 2965 ccs->SubstFormat = GET_UShort(); 2966 2967 FORGET_Frame(); 2968 2969 switch ( ccs->SubstFormat ) { 2970 case 1: return Load_ChainContextSubst1( &ccs->ccsf.ccsf1, stream ); 2971 case 2: return Load_ChainContextSubst2( &ccs->ccsf.ccsf2, stream ); 2972 case 3: return Load_ChainContextSubst3( &ccs->ccsf.ccsf3, stream ); 2973 default: return ERR(HB_Err_Invalid_SubTable_Format); 2974 } 2975 2976 return HB_Err_Ok; /* never reached */ 2977 } 2978 2979 2980 static void Free_ChainContextSubst( HB_GSUB_SubTable* st ) 2981 { 2982 HB_ChainContextSubst* ccs = &st->chain; 2983 2984 switch ( ccs->SubstFormat ) { 2985 case 1: Free_ChainContextSubst1( &ccs->ccsf.ccsf1 ); break; 2986 case 2: Free_ChainContextSubst2( &ccs->ccsf.ccsf2 ); break; 2987 case 3: Free_ChainContextSubst3( &ccs->ccsf.ccsf3 ); break; 2988 default: break; 2989 } 2990 } 2991 2992 2993 static HB_Error Lookup_ChainContextSubst1( HB_GSUBHeader* gsub, 2994 HB_ChainContextSubstFormat1* ccsf1, 2995 HB_Buffer buffer, 2996 HB_UShort flags, 2997 HB_UShort context_length, 2998 int nesting_level ) 2999 { 3000 HB_UShort index, property; 3001 HB_UShort i, j, k, num_csr; 3002 HB_UShort bgc, igc, lgc; 3003 HB_Error error; 3004 3005 HB_ChainSubRule* csr; 3006 HB_ChainSubRule curr_csr; 3007 HB_GDEFHeader* gdef; 3008 3009 3010 gdef = gsub->gdef; 3011 3012 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) 3013 return error; 3014 3015 error = _HB_OPEN_Coverage_Index( &ccsf1->Coverage, IN_CURGLYPH(), &index ); 3016 if ( error ) 3017 return error; 3018 3019 csr = ccsf1->ChainSubRuleSet[index].ChainSubRule; 3020 num_csr = ccsf1->ChainSubRuleSet[index].ChainSubRuleCount; 3021 3022 for ( k = 0; k < num_csr; k++ ) 3023 { 3024 curr_csr = csr[k]; 3025 bgc = curr_csr.BacktrackGlyphCount; 3026 igc = curr_csr.InputGlyphCount; 3027 lgc = curr_csr.LookaheadGlyphCount; 3028 3029 if ( context_length != 0xFFFF && context_length < igc ) 3030 goto next_chainsubrule; 3031 3032 /* check whether context is too long; it is a first guess only */ 3033 3034 if ( bgc > buffer->out_pos || buffer->in_pos + igc + lgc > buffer->in_length ) 3035 goto next_chainsubrule; 3036 3037 if ( bgc ) 3038 { 3039 /* since we don't know in advance the number of glyphs to inspect, 3040 we search backwards for matches in the backtrack glyph array */ 3041 3042 for ( i = 0, j = buffer->out_pos - 1; i < bgc; i++, j-- ) 3043 { 3044 while ( CHECK_Property( gdef, OUT_ITEM( j ), flags, &property ) ) 3045 { 3046 if ( error && error != HB_Err_Not_Covered ) 3047 return error; 3048 3049 if ( j + 1 == bgc - i ) 3050 goto next_chainsubrule; 3051 j--; 3052 } 3053 3054 /* In OpenType 1.3, it is undefined whether the offsets of 3055 backtrack glyphs is in logical order or not. Version 1.4 3056 will clarify this: 3057 3058 Logical order - a b c d e f g h i j 3059 i 3060 Input offsets - 0 1 3061 Backtrack offsets - 3 2 1 0 3062 Lookahead offsets - 0 1 2 3 */ 3063 3064 if ( OUT_GLYPH( j ) != curr_csr.Backtrack[i] ) 3065 goto next_chainsubrule; 3066 } 3067 } 3068 3069 /* Start at 1 because [0] is implied */ 3070 3071 for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ ) 3072 { 3073 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) 3074 { 3075 if ( error && error != HB_Err_Not_Covered ) 3076 return error; 3077 3078 if ( j + igc - i + lgc == (HB_Int)buffer->in_length ) 3079 goto next_chainsubrule; 3080 j++; 3081 } 3082 3083 if ( IN_GLYPH( j ) != curr_csr.Input[i - 1] ) 3084 goto next_chainsubrule; 3085 } 3086 3087 /* we are starting to check for lookahead glyphs right after the 3088 last context glyph */ 3089 3090 for ( i = 0; i < lgc; i++, j++ ) 3091 { 3092 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) 3093 { 3094 if ( error && error != HB_Err_Not_Covered ) 3095 return error; 3096 3097 if ( j + lgc - i == (HB_Int)buffer->in_length ) 3098 goto next_chainsubrule; 3099 j++; 3100 } 3101 3102 if ( IN_GLYPH( j ) != curr_csr.Lookahead[i] ) 3103 goto next_chainsubrule; 3104 } 3105 3106 return Do_ContextSubst( gsub, igc, 3107 curr_csr.SubstCount, 3108 curr_csr.SubstLookupRecord, 3109 buffer, 3110 nesting_level ); 3111 3112 next_chainsubrule: 3113 ; 3114 } 3115 3116 return HB_Err_Not_Covered; 3117 } 3118 3119 3120 static HB_Error Lookup_ChainContextSubst2( HB_GSUBHeader* gsub, 3121 HB_ChainContextSubstFormat2* ccsf2, 3122 HB_Buffer buffer, 3123 HB_UShort flags, 3124 HB_UShort context_length, 3125 int nesting_level ) 3126 { 3127 HB_UShort index, property; 3128 HB_Error error; 3129 HB_UShort i, j, k; 3130 HB_UShort bgc, igc, lgc; 3131 HB_UShort known_backtrack_classes, 3132 known_input_classes, 3133 known_lookahead_classes; 3134 3135 HB_UShort* backtrack_classes; 3136 HB_UShort* input_classes; 3137 HB_UShort* lookahead_classes; 3138 3139 HB_UShort* bc; 3140 HB_UShort* ic; 3141 HB_UShort* lc; 3142 3143 HB_ChainSubClassSet* cscs; 3144 HB_ChainSubClassRule ccsr; 3145 HB_GDEFHeader* gdef; 3146 3147 3148 gdef = gsub->gdef; 3149 3150 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) 3151 return error; 3152 3153 /* Note: The coverage table in format 2 doesn't give an index into 3154 anything. It just lets us know whether or not we need to 3155 do any lookup at all. */ 3156 3157 error = _HB_OPEN_Coverage_Index( &ccsf2->Coverage, IN_CURGLYPH(), &index ); 3158 if ( error ) 3159 return error; 3160 3161 if ( ALLOC_ARRAY( backtrack_classes, ccsf2->MaxBacktrackLength, HB_UShort ) ) 3162 return error; 3163 known_backtrack_classes = 0; 3164 3165 if (ccsf2->MaxInputLength < 1) 3166 return HB_Err_Not_Covered; 3167 3168 if ( ALLOC_ARRAY( input_classes, ccsf2->MaxInputLength, HB_UShort ) ) 3169 goto End3; 3170 known_input_classes = 1; 3171 3172 if ( ALLOC_ARRAY( lookahead_classes, ccsf2->MaxLookaheadLength, HB_UShort ) ) 3173 goto End2; 3174 known_lookahead_classes = 0; 3175 3176 error = _HB_OPEN_Get_Class( &ccsf2->InputClassDef, IN_CURGLYPH(), 3177 &input_classes[0], NULL ); 3178 if ( error && error != HB_Err_Not_Covered ) 3179 goto End1; 3180 3181 cscs = &ccsf2->ChainSubClassSet[input_classes[0]]; 3182 if ( !cscs ) 3183 { 3184 error = ERR(HB_Err_Invalid_SubTable); 3185 goto End1; 3186 } 3187 3188 for ( k = 0; k < cscs->ChainSubClassRuleCount; k++ ) 3189 { 3190 ccsr = cscs->ChainSubClassRule[k]; 3191 bgc = ccsr.BacktrackGlyphCount; 3192 igc = ccsr.InputGlyphCount; 3193 lgc = ccsr.LookaheadGlyphCount; 3194 3195 if ( context_length != 0xFFFF && context_length < igc ) 3196 goto next_chainsubclassrule; 3197 3198 /* check whether context is too long; it is a first guess only */ 3199 3200 if ( bgc > buffer->out_pos || buffer->in_pos + igc + lgc > buffer->in_length ) 3201 goto next_chainsubclassrule; 3202 3203 if ( bgc ) 3204 { 3205 /* Since we don't know in advance the number of glyphs to inspect, 3206 we search backwards for matches in the backtrack glyph array. 3207 Note that `known_backtrack_classes' starts at index 0. */ 3208 3209 bc = ccsr.Backtrack; 3210 3211 for ( i = 0, j = buffer->out_pos - 1; i < bgc; i++, j-- ) 3212 { 3213 while ( CHECK_Property( gdef, OUT_ITEM( j ), flags, &property ) ) 3214 { 3215 if ( error && error != HB_Err_Not_Covered ) 3216 goto End1; 3217 3218 if ( j + 1 == bgc - i ) 3219 goto next_chainsubclassrule; 3220 j--; 3221 } 3222 3223 if ( i >= known_backtrack_classes ) 3224 { 3225 /* Keeps us from having to do this for each rule */ 3226 3227 error = _HB_OPEN_Get_Class( &ccsf2->BacktrackClassDef, OUT_GLYPH( j ), 3228 &backtrack_classes[i], NULL ); 3229 if ( error && error != HB_Err_Not_Covered ) 3230 goto End1; 3231 known_backtrack_classes = i; 3232 } 3233 3234 if ( bc[i] != backtrack_classes[i] ) 3235 goto next_chainsubclassrule; 3236 } 3237 } 3238 3239 ic = ccsr.Input; 3240 3241 /* Start at 1 because [0] is implied */ 3242 3243 for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ ) 3244 { 3245 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) 3246 { 3247 if ( error && error != HB_Err_Not_Covered ) 3248 goto End1; 3249 3250 if ( j + igc - i + lgc == (HB_Int)buffer->in_length ) 3251 goto next_chainsubclassrule; 3252 j++; 3253 } 3254 3255 if ( i >= known_input_classes ) 3256 { 3257 error = _HB_OPEN_Get_Class( &ccsf2->InputClassDef, IN_GLYPH( j ), 3258 &input_classes[i], NULL ); 3259 if ( error && error != HB_Err_Not_Covered ) 3260 goto End1; 3261 known_input_classes = i; 3262 } 3263 3264 if ( ic[i - 1] != input_classes[i] ) 3265 goto next_chainsubclassrule; 3266 } 3267 3268 /* we are starting to check for lookahead glyphs right after the 3269 last context glyph */ 3270 3271 lc = ccsr.Lookahead; 3272 3273 for ( i = 0; i < lgc; i++, j++ ) 3274 { 3275 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) 3276 { 3277 if ( error && error != HB_Err_Not_Covered ) 3278 goto End1; 3279 3280 if ( j + lgc - i == (HB_Int)buffer->in_length ) 3281 goto next_chainsubclassrule; 3282 j++; 3283 } 3284 3285 if ( i >= known_lookahead_classes ) 3286 { 3287 error = _HB_OPEN_Get_Class( &ccsf2->LookaheadClassDef, IN_GLYPH( j ), 3288 &lookahead_classes[i], NULL ); 3289 if ( error && error != HB_Err_Not_Covered ) 3290 goto End1; 3291 known_lookahead_classes = i; 3292 } 3293 3294 if ( lc[i] != lookahead_classes[i] ) 3295 goto next_chainsubclassrule; 3296 } 3297 3298 error = Do_ContextSubst( gsub, igc, 3299 ccsr.SubstCount, 3300 ccsr.SubstLookupRecord, 3301 buffer, 3302 nesting_level ); 3303 goto End1; 3304 3305 next_chainsubclassrule: 3306 ; 3307 } 3308 3309 error = HB_Err_Not_Covered; 3310 3311 End1: 3312 FREE( lookahead_classes ); 3313 3314 End2: 3315 FREE( input_classes ); 3316 3317 End3: 3318 FREE( backtrack_classes ); 3319 return error; 3320 } 3321 3322 3323 static HB_Error Lookup_ChainContextSubst3( HB_GSUBHeader* gsub, 3324 HB_ChainContextSubstFormat3* ccsf3, 3325 HB_Buffer buffer, 3326 HB_UShort flags, 3327 HB_UShort context_length, 3328 int nesting_level ) 3329 { 3330 HB_UShort index, i, j, property; 3331 HB_UShort bgc, igc, lgc; 3332 HB_Error error; 3333 3334 HB_Coverage* bc; 3335 HB_Coverage* ic; 3336 HB_Coverage* lc; 3337 HB_GDEFHeader* gdef; 3338 3339 3340 gdef = gsub->gdef; 3341 3342 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) 3343 return error; 3344 3345 bgc = ccsf3->BacktrackGlyphCount; 3346 igc = ccsf3->InputGlyphCount; 3347 lgc = ccsf3->LookaheadGlyphCount; 3348 3349 if ( context_length != 0xFFFF && context_length < igc ) 3350 return HB_Err_Not_Covered; 3351 3352 /* check whether context is too long; it is a first guess only */ 3353 3354 if ( bgc > buffer->out_pos || buffer->in_pos + igc + lgc > buffer->in_length ) 3355 return HB_Err_Not_Covered; 3356 3357 if ( bgc ) 3358 { 3359 /* Since we don't know in advance the number of glyphs to inspect, 3360 we search backwards for matches in the backtrack glyph array */ 3361 3362 bc = ccsf3->BacktrackCoverage; 3363 3364 for ( i = 0, j = buffer->out_pos - 1; i < bgc; i++, j-- ) 3365 { 3366 while ( CHECK_Property( gdef, OUT_ITEM( j ), flags, &property ) ) 3367 { 3368 if ( error && error != HB_Err_Not_Covered ) 3369 return error; 3370 3371 if ( j + 1 == bgc - i ) 3372 return HB_Err_Not_Covered; 3373 j--; 3374 } 3375 3376 error = _HB_OPEN_Coverage_Index( &bc[i], OUT_GLYPH( j ), &index ); 3377 if ( error ) 3378 return error; 3379 } 3380 } 3381 3382 ic = ccsf3->InputCoverage; 3383 3384 for ( i = 0, j = buffer->in_pos; i < igc; i++, j++ ) 3385 { 3386 /* We already called CHECK_Property for IN_GLYPH( buffer->in_pos ) */ 3387 while ( j > buffer->in_pos && CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) 3388 { 3389 if ( error && error != HB_Err_Not_Covered ) 3390 return error; 3391 3392 if ( j + igc - i + lgc == (HB_Int)buffer->in_length ) 3393 return HB_Err_Not_Covered; 3394 j++; 3395 } 3396 3397 error = _HB_OPEN_Coverage_Index( &ic[i], IN_GLYPH( j ), &index ); 3398 if ( error ) 3399 return error; 3400 } 3401 3402 /* we are starting for lookahead glyphs right after the last context 3403 glyph */ 3404 3405 lc = ccsf3->LookaheadCoverage; 3406 3407 for ( i = 0; i < lgc; i++, j++ ) 3408 { 3409 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) 3410 { 3411 if ( error && error != HB_Err_Not_Covered ) 3412 return error; 3413 3414 if ( j + lgc - i == (HB_Int)buffer->in_length ) 3415 return HB_Err_Not_Covered; 3416 j++; 3417 } 3418 3419 error = _HB_OPEN_Coverage_Index( &lc[i], IN_GLYPH( j ), &index ); 3420 if ( error ) 3421 return error; 3422 } 3423 3424 return Do_ContextSubst( gsub, igc, 3425 ccsf3->SubstCount, 3426 ccsf3->SubstLookupRecord, 3427 buffer, 3428 nesting_level ); 3429 } 3430 3431 3432 static HB_Error Lookup_ChainContextSubst( HB_GSUBHeader* gsub, 3433 HB_GSUB_SubTable* st, 3434 HB_Buffer buffer, 3435 HB_UShort flags, 3436 HB_UShort context_length, 3437 int nesting_level ) 3438 { 3439 HB_ChainContextSubst* ccs = &st->chain; 3440 3441 switch ( ccs->SubstFormat ) { 3442 case 1: return Lookup_ChainContextSubst1( gsub, &ccs->ccsf.ccsf1, buffer, flags, context_length, nesting_level ); 3443 case 2: return Lookup_ChainContextSubst2( gsub, &ccs->ccsf.ccsf2, buffer, flags, context_length, nesting_level ); 3444 case 3: return Lookup_ChainContextSubst3( gsub, &ccs->ccsf.ccsf3, buffer, flags, context_length, nesting_level ); 3445 default: return ERR(HB_Err_Invalid_SubTable_Format); 3446 } 3447 } 3448 3449 3450 static HB_Error Load_ReverseChainContextSubst( HB_GSUB_SubTable* st, 3451 HB_Stream stream ) 3452 { 3453 HB_Error error; 3454 HB_ReverseChainContextSubst* rccs = &st->reverse; 3455 3456 HB_UShort m, count; 3457 3458 HB_UShort nb = 0, nl = 0, n; 3459 HB_UShort backtrack_count, lookahead_count; 3460 HB_UInt cur_offset, new_offset, base_offset; 3461 3462 HB_Coverage* b; 3463 HB_Coverage* l; 3464 HB_UShort* sub; 3465 3466 base_offset = FILE_Pos(); 3467 3468 if ( ACCESS_Frame( 2L ) ) 3469 return error; 3470 3471 rccs->SubstFormat = GET_UShort(); 3472 3473 if ( rccs->SubstFormat != 1 ) 3474 return ERR(HB_Err_Invalid_SubTable_Format); 3475 3476 FORGET_Frame(); 3477 3478 if ( ACCESS_Frame( 2L ) ) 3479 return error; 3480 3481 new_offset = GET_UShort() + base_offset; 3482 3483 FORGET_Frame(); 3484 3485 cur_offset = FILE_Pos(); 3486 if ( FILE_Seek( new_offset ) || 3487 ( error = _HB_OPEN_Load_Coverage( &rccs->Coverage, stream ) ) != HB_Err_Ok ) 3488 return error; 3489 (void)FILE_Seek( cur_offset ); 3490 3491 3492 if ( ACCESS_Frame( 2L ) ) 3493 goto Fail4; 3494 3495 rccs->BacktrackGlyphCount = GET_UShort(); 3496 3497 FORGET_Frame(); 3498 3499 rccs->BacktrackCoverage = NULL; 3500 3501 backtrack_count = rccs->BacktrackGlyphCount; 3502 3503 if ( ALLOC_ARRAY( rccs->BacktrackCoverage, backtrack_count, 3504 HB_Coverage ) ) 3505 goto Fail4; 3506 3507 b = rccs->BacktrackCoverage; 3508 3509 for ( nb = 0; nb < backtrack_count; nb++ ) 3510 { 3511 if ( ACCESS_Frame( 2L ) ) 3512 goto Fail3; 3513 3514 new_offset = GET_UShort() + base_offset; 3515 3516 FORGET_Frame(); 3517 3518 cur_offset = FILE_Pos(); 3519 if ( FILE_Seek( new_offset ) || 3520 ( error = _HB_OPEN_Load_Coverage( &b[nb], stream ) ) != HB_Err_Ok ) 3521 goto Fail3; 3522 (void)FILE_Seek( cur_offset ); 3523 } 3524 3525 3526 if ( ACCESS_Frame( 2L ) ) 3527 goto Fail3; 3528 3529 rccs->LookaheadGlyphCount = GET_UShort(); 3530 3531 FORGET_Frame(); 3532 3533 rccs->LookaheadCoverage = NULL; 3534 3535 lookahead_count = rccs->LookaheadGlyphCount; 3536 3537 if ( ALLOC_ARRAY( rccs->LookaheadCoverage, lookahead_count, 3538 HB_Coverage ) ) 3539 goto Fail3; 3540 3541 l = rccs->LookaheadCoverage; 3542 3543 for ( nl = 0; nl < lookahead_count; nl++ ) 3544 { 3545 if ( ACCESS_Frame( 2L ) ) 3546 goto Fail2; 3547 3548 new_offset = GET_UShort() + base_offset; 3549 3550 FORGET_Frame(); 3551 3552 cur_offset = FILE_Pos(); 3553 if ( FILE_Seek( new_offset ) || 3554 ( error = _HB_OPEN_Load_Coverage( &l[nl], stream ) ) != HB_Err_Ok ) 3555 goto Fail2; 3556 (void)FILE_Seek( cur_offset ); 3557 } 3558 3559 if ( ACCESS_Frame( 2L ) ) 3560 goto Fail2; 3561 3562 rccs->GlyphCount = GET_UShort(); 3563 3564 FORGET_Frame(); 3565 3566 rccs->Substitute = NULL; 3567 3568 count = rccs->GlyphCount; 3569 3570 if ( ALLOC_ARRAY( rccs->Substitute, count, 3571 HB_UShort ) ) 3572 goto Fail2; 3573 3574 sub = rccs->Substitute; 3575 3576 if ( ACCESS_Frame( count * 2L ) ) 3577 goto Fail1; 3578 3579 for ( n = 0; n < count; n++ ) 3580 sub[n] = GET_UShort(); 3581 3582 FORGET_Frame(); 3583 3584 return HB_Err_Ok; 3585 3586 Fail1: 3587 FREE( sub ); 3588 3589 Fail2: 3590 for ( m = 0; m < nl; m++ ) 3591 _HB_OPEN_Free_Coverage( &l[m] ); 3592 3593 FREE( l ); 3594 3595 Fail3: 3596 for ( m = 0; m < nb; m++ ) 3597 _HB_OPEN_Free_Coverage( &b[m] ); 3598 3599 FREE( b ); 3600 3601 Fail4: 3602 _HB_OPEN_Free_Coverage( &rccs->Coverage ); 3603 return error; 3604 } 3605 3606 3607 static void Free_ReverseChainContextSubst( HB_GSUB_SubTable* st ) 3608 { 3609 HB_UShort n, count; 3610 HB_ReverseChainContextSubst* rccs = &st->reverse; 3611 3612 HB_Coverage* c; 3613 3614 _HB_OPEN_Free_Coverage( &rccs->Coverage ); 3615 3616 if ( rccs->LookaheadCoverage ) 3617 { 3618 count = rccs->LookaheadGlyphCount; 3619 c = rccs->LookaheadCoverage; 3620 3621 for ( n = 0; n < count; n++ ) 3622 _HB_OPEN_Free_Coverage( &c[n] ); 3623 3624 FREE( c ); 3625 } 3626 3627 if ( rccs->BacktrackCoverage ) 3628 { 3629 count = rccs->BacktrackGlyphCount; 3630 c = rccs->BacktrackCoverage; 3631 3632 for ( n = 0; n < count; n++ ) 3633 _HB_OPEN_Free_Coverage( &c[n] ); 3634 3635 FREE( c ); 3636 } 3637 3638 FREE ( rccs->Substitute ); 3639 } 3640 3641 3642 static HB_Error Lookup_ReverseChainContextSubst( HB_GSUBHeader* gsub, 3643 HB_GSUB_SubTable* st, 3644 HB_Buffer buffer, 3645 HB_UShort flags, 3646 HB_UShort context_length, 3647 int nesting_level ) 3648 { 3649 HB_UShort index, input_index, i, j, property; 3650 HB_UShort bgc, lgc; 3651 HB_Error error; 3652 3653 HB_ReverseChainContextSubst* rccs = &st->reverse; 3654 HB_Coverage* bc; 3655 HB_Coverage* lc; 3656 HB_GDEFHeader* gdef; 3657 3658 if ( nesting_level != 1 || context_length != 0xFFFF ) 3659 return HB_Err_Not_Covered; 3660 3661 gdef = gsub->gdef; 3662 3663 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) 3664 return error; 3665 3666 bgc = rccs->BacktrackGlyphCount; 3667 lgc = rccs->LookaheadGlyphCount; 3668 3669 /* check whether context is too long; it is a first guess only */ 3670 3671 if ( bgc > buffer->in_pos || buffer->in_pos + 1 + lgc > buffer->in_length ) 3672 return HB_Err_Not_Covered; 3673 3674 if ( bgc ) 3675 { 3676 /* Since we don't know in advance the number of glyphs to inspect, 3677 we search backwards for matches in the backtrack glyph array */ 3678 3679 bc = rccs->BacktrackCoverage; 3680 3681 for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- ) 3682 { 3683 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) 3684 { 3685 if ( error && error != HB_Err_Not_Covered ) 3686 return error; 3687 3688 if ( j + 1 == bgc - i ) 3689 return HB_Err_Not_Covered; 3690 j--; 3691 } 3692 3693 error = _HB_OPEN_Coverage_Index( &bc[i], IN_GLYPH( j ), &index ); 3694 if ( error ) 3695 return error; 3696 } 3697 } 3698 3699 j = buffer->in_pos; 3700 3701 error = _HB_OPEN_Coverage_Index( &rccs->Coverage, IN_GLYPH( j ), &input_index ); 3702 if ( error ) 3703 return error; 3704 3705 lc = rccs->LookaheadCoverage; 3706 3707 for ( i = 0, j = buffer->in_pos + 1; i < lgc; i++, j++ ) 3708 { 3709 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) 3710 { 3711 if ( error && error != HB_Err_Not_Covered ) 3712 return error; 3713 3714 if ( j + lgc - i == (HB_Int)buffer->in_length ) 3715 return HB_Err_Not_Covered; 3716 j++; 3717 } 3718 3719 error = _HB_OPEN_Coverage_Index( &lc[i], IN_GLYPH( j ), &index ); 3720 if ( error ) 3721 return error; 3722 } 3723 3724 IN_CURGLYPH() = rccs->Substitute[input_index]; 3725 buffer->in_pos--; /* Reverse! */ 3726 3727 return error; 3728 } 3729 3730 3731 3732 /*********** 3733 * GSUB API 3734 ***********/ 3735 3736 3737 3738 HB_Error HB_GSUB_Select_Script( HB_GSUBHeader* gsub, 3739 HB_UInt script_tag, 3740 HB_UShort* script_index ) 3741 { 3742 HB_UShort n; 3743 3744 HB_ScriptList* sl; 3745 HB_ScriptRecord* sr; 3746 3747 3748 if ( !gsub || !script_index ) 3749 return ERR(HB_Err_Invalid_Argument); 3750 3751 sl = &gsub->ScriptList; 3752 sr = sl->ScriptRecord; 3753 3754 for ( n = 0; n < sl->ScriptCount; n++ ) 3755 if ( script_tag == sr[n].ScriptTag ) 3756 { 3757 *script_index = n; 3758 3759 return HB_Err_Ok; 3760 } 3761 3762 return HB_Err_Not_Covered; 3763 } 3764 3765 3766 3767 HB_Error HB_GSUB_Select_Language( HB_GSUBHeader* gsub, 3768 HB_UInt language_tag, 3769 HB_UShort script_index, 3770 HB_UShort* language_index, 3771 HB_UShort* req_feature_index ) 3772 { 3773 HB_UShort n; 3774 3775 HB_ScriptList* sl; 3776 HB_ScriptRecord* sr; 3777 HB_ScriptTable* s; 3778 HB_LangSysRecord* lsr; 3779 3780 3781 if ( !gsub || !language_index || !req_feature_index ) 3782 return ERR(HB_Err_Invalid_Argument); 3783 3784 sl = &gsub->ScriptList; 3785 sr = sl->ScriptRecord; 3786 3787 if ( script_index >= sl->ScriptCount ) 3788 return ERR(HB_Err_Invalid_Argument); 3789 3790 s = &sr[script_index].Script; 3791 lsr = s->LangSysRecord; 3792 3793 for ( n = 0; n < s->LangSysCount; n++ ) 3794 if ( language_tag == lsr[n].LangSysTag ) 3795 { 3796 *language_index = n; 3797 *req_feature_index = lsr[n].LangSys.ReqFeatureIndex; 3798 3799 return HB_Err_Ok; 3800 } 3801 3802 return HB_Err_Not_Covered; 3803 } 3804 3805 3806 /* selecting 0xFFFF for language_index asks for the values of the 3807 default language (DefaultLangSys) */ 3808 3809 3810 HB_Error HB_GSUB_Select_Feature( HB_GSUBHeader* gsub, 3811 HB_UInt feature_tag, 3812 HB_UShort script_index, 3813 HB_UShort language_index, 3814 HB_UShort* feature_index ) 3815 { 3816 HB_UShort n; 3817 3818 HB_ScriptList* sl; 3819 HB_ScriptRecord* sr; 3820 HB_ScriptTable* s; 3821 HB_LangSysRecord* lsr; 3822 HB_LangSys* ls; 3823 HB_UShort* fi; 3824 3825 HB_FeatureList* fl; 3826 HB_FeatureRecord* fr; 3827 3828 3829 if ( !gsub || !feature_index ) 3830 return ERR(HB_Err_Invalid_Argument); 3831 3832 sl = &gsub->ScriptList; 3833 sr = sl->ScriptRecord; 3834 3835 fl = &gsub->FeatureList; 3836 fr = fl->FeatureRecord; 3837 3838 if ( script_index >= sl->ScriptCount ) 3839 return ERR(HB_Err_Invalid_Argument); 3840 3841 s = &sr[script_index].Script; 3842 lsr = s->LangSysRecord; 3843 3844 if ( language_index == 0xFFFF ) 3845 ls = &s->DefaultLangSys; 3846 else 3847 { 3848 if ( language_index >= s->LangSysCount ) 3849 return ERR(HB_Err_Invalid_Argument); 3850 3851 ls = &lsr[language_index].LangSys; 3852 } 3853 3854 fi = ls->FeatureIndex; 3855 3856 for ( n = 0; n < ls->FeatureCount; n++ ) 3857 { 3858 if ( fi[n] >= fl->FeatureCount ) 3859 return ERR(HB_Err_Invalid_SubTable_Format); 3860 3861 if ( feature_tag == fr[fi[n]].FeatureTag ) 3862 { 3863 *feature_index = fi[n]; 3864 3865 return HB_Err_Ok; 3866 } 3867 } 3868 3869 return HB_Err_Not_Covered; 3870 } 3871 3872 3873 /* The next three functions return a null-terminated list */ 3874 3875 3876 HB_Error HB_GSUB_Query_Scripts( HB_GSUBHeader* gsub, 3877 HB_UInt** script_tag_list ) 3878 { 3879 HB_UShort n; 3880 HB_Error error; 3881 HB_UInt* stl; 3882 3883 HB_ScriptList* sl; 3884 HB_ScriptRecord* sr; 3885 3886 3887 if ( !gsub || !script_tag_list ) 3888 return ERR(HB_Err_Invalid_Argument); 3889 3890 sl = &gsub->ScriptList; 3891 sr = sl->ScriptRecord; 3892 3893 if ( ALLOC_ARRAY( stl, sl->ScriptCount + 1, HB_UInt ) ) 3894 return error; 3895 3896 for ( n = 0; n < sl->ScriptCount; n++ ) 3897 stl[n] = sr[n].ScriptTag; 3898 stl[n] = 0; 3899 3900 *script_tag_list = stl; 3901 3902 return HB_Err_Ok; 3903 } 3904 3905 3906 3907 HB_Error HB_GSUB_Query_Languages( HB_GSUBHeader* gsub, 3908 HB_UShort script_index, 3909 HB_UInt** language_tag_list ) 3910 { 3911 HB_UShort n; 3912 HB_Error error; 3913 HB_UInt* ltl; 3914 3915 HB_ScriptList* sl; 3916 HB_ScriptRecord* sr; 3917 HB_ScriptTable* s; 3918 HB_LangSysRecord* lsr; 3919 3920 3921 if ( !gsub || !language_tag_list ) 3922 return ERR(HB_Err_Invalid_Argument); 3923 3924 sl = &gsub->ScriptList; 3925 sr = sl->ScriptRecord; 3926 3927 if ( script_index >= sl->ScriptCount ) 3928 return ERR(HB_Err_Invalid_Argument); 3929 3930 s = &sr[script_index].Script; 3931 lsr = s->LangSysRecord; 3932 3933 if ( ALLOC_ARRAY( ltl, s->LangSysCount + 1, HB_UInt ) ) 3934 return error; 3935 3936 for ( n = 0; n < s->LangSysCount; n++ ) 3937 ltl[n] = lsr[n].LangSysTag; 3938 ltl[n] = 0; 3939 3940 *language_tag_list = ltl; 3941 3942 return HB_Err_Ok; 3943 } 3944 3945 3946 /* selecting 0xFFFF for language_index asks for the values of the 3947 default language (DefaultLangSys) */ 3948 3949 3950 HB_Error HB_GSUB_Query_Features( HB_GSUBHeader* gsub, 3951 HB_UShort script_index, 3952 HB_UShort language_index, 3953 HB_UInt** feature_tag_list ) 3954 { 3955 HB_UShort n; 3956 HB_Error error; 3957 HB_UInt* ftl; 3958 3959 HB_ScriptList* sl; 3960 HB_ScriptRecord* sr; 3961 HB_ScriptTable* s; 3962 HB_LangSysRecord* lsr; 3963 HB_LangSys* ls; 3964 HB_UShort* fi; 3965 3966 HB_FeatureList* fl; 3967 HB_FeatureRecord* fr; 3968 3969 3970 if ( !gsub || !feature_tag_list ) 3971 return ERR(HB_Err_Invalid_Argument); 3972 3973 sl = &gsub->ScriptList; 3974 sr = sl->ScriptRecord; 3975 3976 fl = &gsub->FeatureList; 3977 fr = fl->FeatureRecord; 3978 3979 if ( script_index >= sl->ScriptCount ) 3980 return ERR(HB_Err_Invalid_Argument); 3981 3982 s = &sr[script_index].Script; 3983 lsr = s->LangSysRecord; 3984 3985 if ( language_index == 0xFFFF ) 3986 ls = &s->DefaultLangSys; 3987 else 3988 { 3989 if ( language_index >= s->LangSysCount ) 3990 return ERR(HB_Err_Invalid_Argument); 3991 3992 ls = &lsr[language_index].LangSys; 3993 } 3994 3995 fi = ls->FeatureIndex; 3996 3997 if ( ALLOC_ARRAY( ftl, ls->FeatureCount + 1, HB_UInt ) ) 3998 return error; 3999 4000 for ( n = 0; n < ls->FeatureCount; n++ ) 4001 { 4002 if ( fi[n] >= fl->FeatureCount ) 4003 { 4004 FREE( ftl ); 4005 return ERR(HB_Err_Invalid_SubTable_Format); 4006 } 4007 ftl[n] = fr[fi[n]].FeatureTag; 4008 } 4009 ftl[n] = 0; 4010 4011 *feature_tag_list = ftl; 4012 4013 return HB_Err_Ok; 4014 } 4015 4016 4017 /* Do an individual subtable lookup. Returns HB_Err_Ok if substitution 4018 has been done, or HB_Err_Not_Covered if not. */ 4019 static HB_Error GSUB_Do_Glyph_Lookup( HB_GSUBHeader* gsub, 4020 HB_UShort lookup_index, 4021 HB_Buffer buffer, 4022 HB_UShort context_length, 4023 int nesting_level ) 4024 { 4025 HB_Error error = HB_Err_Not_Covered; 4026 HB_UShort i, flags, lookup_count; 4027 HB_Lookup* lo; 4028 int lookup_type; 4029 4030 nesting_level++; 4031 4032 if ( nesting_level > HB_MAX_NESTING_LEVEL ) 4033 return ERR(HB_Err_Not_Covered); /* ERR() call intended */ 4034 4035 lookup_count = gsub->LookupList.LookupCount; 4036 if (lookup_index >= lookup_count) 4037 return error; 4038 4039 lo = &gsub->LookupList.Lookup[lookup_index]; 4040 flags = lo->LookupFlag; 4041 lookup_type = lo->LookupType; 4042 4043 for ( i = 0; i < lo->SubTableCount; i++ ) 4044 { 4045 HB_GSUB_SubTable *st = &lo->SubTable[i].st.gsub; 4046 4047 switch (lookup_type) { 4048 case HB_GSUB_LOOKUP_SINGLE: 4049 error = Lookup_SingleSubst ( gsub, st, buffer, flags, context_length, nesting_level ); break; 4050 case HB_GSUB_LOOKUP_MULTIPLE: 4051 error = Lookup_MultipleSubst ( gsub, st, buffer, flags, context_length, nesting_level ); break; 4052 case HB_GSUB_LOOKUP_ALTERNATE: 4053 error = Lookup_AlternateSubst ( gsub, st, buffer, flags, context_length, nesting_level ); break; 4054 case HB_GSUB_LOOKUP_LIGATURE: 4055 error = Lookup_LigatureSubst ( gsub, st, buffer, flags, context_length, nesting_level ); break; 4056 case HB_GSUB_LOOKUP_CONTEXT: 4057 error = Lookup_ContextSubst ( gsub, st, buffer, flags, context_length, nesting_level ); break; 4058 case HB_GSUB_LOOKUP_CHAIN: 4059 error = Lookup_ChainContextSubst ( gsub, st, buffer, flags, context_length, nesting_level ); break; 4060 /*case HB_GSUB_LOOKUP_EXTENSION: 4061 error = Lookup_ExtensionSubst ( gsub, st, buffer, flags, context_length, nesting_level ); break;*/ 4062 case HB_GSUB_LOOKUP_REVERSE_CHAIN: 4063 error = Lookup_ReverseChainContextSubst ( gsub, st, buffer, flags, context_length, nesting_level ); break; 4064 default: 4065 error = HB_Err_Not_Covered; 4066 }; 4067 4068 /* Check whether we have a successful substitution or an error other 4069 than HB_Err_Not_Covered */ 4070 if ( error != HB_Err_Not_Covered ) 4071 return error; 4072 } 4073 4074 return HB_Err_Not_Covered; 4075 } 4076 4077 4078 HB_INTERNAL HB_Error 4079 _HB_GSUB_Load_SubTable( HB_GSUB_SubTable* st, 4080 HB_Stream stream, 4081 HB_UShort lookup_type ) 4082 { 4083 switch (lookup_type) { 4084 case HB_GSUB_LOOKUP_SINGLE: return Load_SingleSubst ( st, stream ); 4085 case HB_GSUB_LOOKUP_MULTIPLE: return Load_MultipleSubst ( st, stream ); 4086 case HB_GSUB_LOOKUP_ALTERNATE: return Load_AlternateSubst ( st, stream ); 4087 case HB_GSUB_LOOKUP_LIGATURE: return Load_LigatureSubst ( st, stream ); 4088 case HB_GSUB_LOOKUP_CONTEXT: return Load_ContextSubst ( st, stream ); 4089 case HB_GSUB_LOOKUP_CHAIN: return Load_ChainContextSubst ( st, stream ); 4090 /*case HB_GSUB_LOOKUP_EXTENSION: return Load_ExtensionSubst ( st, stream );*/ 4091 case HB_GSUB_LOOKUP_REVERSE_CHAIN: return Load_ReverseChainContextSubst ( st, stream ); 4092 default: return ERR(HB_Err_Invalid_SubTable_Format); 4093 }; 4094 } 4095 4096 4097 HB_INTERNAL void 4098 _HB_GSUB_Free_SubTable( HB_GSUB_SubTable* st, 4099 HB_UShort lookup_type ) 4100 { 4101 switch ( lookup_type ) { 4102 case HB_GSUB_LOOKUP_SINGLE: Free_SingleSubst ( st ); return; 4103 case HB_GSUB_LOOKUP_MULTIPLE: Free_MultipleSubst ( st ); return; 4104 case HB_GSUB_LOOKUP_ALTERNATE: Free_AlternateSubst ( st ); return; 4105 case HB_GSUB_LOOKUP_LIGATURE: Free_LigatureSubst ( st ); return; 4106 case HB_GSUB_LOOKUP_CONTEXT: Free_ContextSubst ( st ); return; 4107 case HB_GSUB_LOOKUP_CHAIN: Free_ChainContextSubst ( st ); return; 4108 /*case HB_GSUB_LOOKUP_EXTENSION: Free_ExtensionSubst ( st ); return;*/ 4109 case HB_GSUB_LOOKUP_REVERSE_CHAIN: Free_ReverseChainContextSubst ( st ); return; 4110 default: return; 4111 }; 4112 } 4113 4114 4115 4116 /* apply one lookup to the input string object */ 4117 4118 static HB_Error GSUB_Do_String_Lookup( HB_GSUBHeader* gsub, 4119 HB_UShort lookup_index, 4120 HB_Buffer buffer ) 4121 { 4122 HB_Error error, retError = HB_Err_Not_Covered; 4123 4124 HB_UInt* properties = gsub->LookupList.Properties; 4125 int lookup_type = gsub->LookupList.Lookup[lookup_index].LookupType; 4126 4127 const int nesting_level = 0; 4128 /* 0xFFFF indicates that we don't have a context length yet */ 4129 const HB_UShort context_length = 0xFFFF; 4130 4131 switch (lookup_type) { 4132 4133 case HB_GSUB_LOOKUP_SINGLE: 4134 case HB_GSUB_LOOKUP_MULTIPLE: 4135 case HB_GSUB_LOOKUP_ALTERNATE: 4136 case HB_GSUB_LOOKUP_LIGATURE: 4137 case HB_GSUB_LOOKUP_CONTEXT: 4138 case HB_GSUB_LOOKUP_CHAIN: 4139 /* in/out forward substitution (implemented lazy) */ 4140 4141 _hb_buffer_clear_output ( buffer ); 4142 buffer->in_pos = 0; 4143 while ( buffer->in_pos < buffer->in_length ) 4144 { 4145 if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] ) 4146 { 4147 error = GSUB_Do_Glyph_Lookup( gsub, lookup_index, buffer, context_length, nesting_level ); 4148 if ( error ) 4149 { 4150 if ( error != HB_Err_Not_Covered ) 4151 return error; 4152 } 4153 else 4154 retError = error; 4155 } 4156 else 4157 error = HB_Err_Not_Covered; 4158 4159 if ( error == HB_Err_Not_Covered ) 4160 if ( COPY_Glyph ( buffer ) ) 4161 return error; 4162 } 4163 /* we shouldn't swap if error occurred. 4164 * 4165 * also don't swap if nothing changed (ie HB_Err_Not_Covered). 4166 * shouldn't matter in that case though. 4167 */ 4168 if ( retError == HB_Err_Ok ) 4169 _hb_buffer_swap( buffer ); 4170 4171 return retError; 4172 4173 case HB_GSUB_LOOKUP_REVERSE_CHAIN: 4174 /* in-place backward substitution */ 4175 4176 buffer->in_pos = buffer->in_length - 1; 4177 do 4178 { 4179 if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] ) 4180 { 4181 error = GSUB_Do_Glyph_Lookup( gsub, lookup_index, buffer, context_length, nesting_level ); 4182 if ( error ) 4183 { 4184 if ( error != HB_Err_Not_Covered ) 4185 return error; 4186 } 4187 else 4188 retError = error; 4189 } 4190 else 4191 error = HB_Err_Not_Covered; 4192 4193 if ( error == HB_Err_Not_Covered ) 4194 buffer->in_pos--; 4195 } 4196 while ((HB_Int) buffer->in_pos >= 0); 4197 4198 return retError; 4199 4200 /*case HB_GSUB_LOOKUP_EXTENSION:*/ 4201 default: 4202 return retError; 4203 }; 4204 } 4205 4206 4207 HB_Error HB_GSUB_Add_Feature( HB_GSUBHeader* gsub, 4208 HB_UShort feature_index, 4209 HB_UInt property ) 4210 { 4211 HB_UShort i; 4212 4213 HB_Feature feature; 4214 HB_UInt* properties; 4215 HB_UShort* index; 4216 HB_UShort lookup_count; 4217 4218 /* Each feature can only be added once */ 4219 4220 if ( !gsub || 4221 feature_index >= gsub->FeatureList.FeatureCount || 4222 gsub->FeatureList.ApplyCount == gsub->FeatureList.FeatureCount ) 4223 return ERR(HB_Err_Invalid_Argument); 4224 4225 gsub->FeatureList.ApplyOrder[gsub->FeatureList.ApplyCount++] = feature_index; 4226 4227 properties = gsub->LookupList.Properties; 4228 4229 feature = gsub->FeatureList.FeatureRecord[feature_index].Feature; 4230 index = feature.LookupListIndex; 4231 lookup_count = gsub->LookupList.LookupCount; 4232 4233 for ( i = 0; i < feature.LookupListCount; i++ ) 4234 { 4235 HB_UShort lookup_index = index[i]; 4236 if (lookup_index < lookup_count) 4237 properties[lookup_index] |= property; 4238 } 4239 4240 return HB_Err_Ok; 4241 } 4242 4243 4244 4245 HB_Error HB_GSUB_Clear_Features( HB_GSUBHeader* gsub ) 4246 { 4247 HB_UShort i; 4248 4249 HB_UInt* properties; 4250 4251 4252 if ( !gsub ) 4253 return ERR(HB_Err_Invalid_Argument); 4254 4255 gsub->FeatureList.ApplyCount = 0; 4256 4257 properties = gsub->LookupList.Properties; 4258 4259 for ( i = 0; i < gsub->LookupList.LookupCount; i++ ) 4260 properties[i] = 0; 4261 4262 return HB_Err_Ok; 4263 } 4264 4265 4266 4267 HB_Error HB_GSUB_Register_Alternate_Function( HB_GSUBHeader* gsub, 4268 HB_AltFunction altfunc, 4269 void* data ) 4270 { 4271 if ( !gsub ) 4272 return ERR(HB_Err_Invalid_Argument); 4273 4274 gsub->altfunc = altfunc; 4275 gsub->data = data; 4276 4277 return HB_Err_Ok; 4278 } 4279 4280 /* returns error if one happened, otherwise returns HB_Err_Not_Covered if no 4281 * feature were applied, or HB_Err_Ok otherwise. 4282 */ 4283 HB_Error HB_GSUB_Apply_String( HB_GSUBHeader* gsub, 4284 HB_Buffer buffer ) 4285 { 4286 HB_Error error, retError = HB_Err_Not_Covered; 4287 int i, j, lookup_count, num_features; 4288 4289 if ( !gsub || 4290 !buffer) 4291 return ERR(HB_Err_Invalid_Argument); 4292 4293 if ( buffer->in_length == 0 ) 4294 return retError; 4295 4296 lookup_count = gsub->LookupList.LookupCount; 4297 num_features = gsub->FeatureList.ApplyCount; 4298 4299 for ( i = 0; i < num_features; i++) 4300 { 4301 HB_UShort feature_index = gsub->FeatureList.ApplyOrder[i]; 4302 HB_Feature feature = gsub->FeatureList.FeatureRecord[feature_index].Feature; 4303 4304 for ( j = 0; j < feature.LookupListCount; j++ ) 4305 { 4306 HB_UShort lookup_index = feature.LookupListIndex[j]; 4307 4308 /* Skip nonexistant lookups */ 4309 if (lookup_index >= lookup_count) 4310 continue; 4311 4312 error = GSUB_Do_String_Lookup( gsub, lookup_index, buffer ); 4313 if ( error ) 4314 { 4315 if ( error != HB_Err_Not_Covered ) 4316 return error; 4317 } 4318 else 4319 retError = error; 4320 } 4321 } 4322 4323 error = retError; 4324 4325 return error; 4326 } 4327 4328 4329 /* END */ 4330