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