1/* 2 * Copyright (C) 1998-2004 David Turner and Werner Lemberg 3 * Copyright (C) 2006 Behdad Esfahbod 4 * 5 * This is part of HarfBuzz, an OpenType Layout engine library. 6 * 7 * Permission is hereby granted, without written agreement and without 8 * license or royalty fees, to use, copy, modify, and distribute this 9 * software and its documentation for any purpose, provided that the 10 * above copyright notice and the following two paragraphs appear in 11 * all copies of this software. 12 * 13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 17 * DAMAGE. 18 * 19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 24 */ 25 26#include "harfbuzz-impl.h" 27#include "harfbuzz-gdef-private.h" 28#include "harfbuzz-open-private.h" 29 30static HB_Error Load_AttachList( HB_AttachList* al, 31 HB_Stream stream ); 32static HB_Error Load_LigCaretList( HB_LigCaretList* lcl, 33 HB_Stream stream ); 34 35static void Free_AttachList( HB_AttachList* al); 36static void Free_LigCaretList( HB_LigCaretList* lcl); 37 38static void Free_NewGlyphClasses( HB_GDEFHeader* gdef); 39 40 41 42/* GDEF glyph classes */ 43 44#define UNCLASSIFIED_GLYPH 0 45#define SIMPLE_GLYPH 1 46#define LIGATURE_GLYPH 2 47#define MARK_GLYPH 3 48#define COMPONENT_GLYPH 4 49 50 51 52 53 54 55HB_Error HB_New_GDEF_Table( HB_GDEFHeader** retptr ) 56{ 57 HB_Error error; 58 59 HB_GDEFHeader* gdef; 60 61 if ( !retptr ) 62 return ERR(HB_Err_Invalid_Argument); 63 64 if ( ALLOC( gdef, sizeof( *gdef ) ) ) 65 return error; 66 67 gdef->GlyphClassDef.loaded = FALSE; 68 gdef->AttachList.loaded = FALSE; 69 gdef->LigCaretList.loaded = FALSE; 70 gdef->MarkAttachClassDef_offset = 0; 71 gdef->MarkAttachClassDef.loaded = FALSE; 72 73 gdef->LastGlyph = 0; 74 gdef->NewGlyphClasses = NULL; 75 76 *retptr = gdef; 77 78 return HB_Err_Ok; 79} 80 81 82HB_Error HB_Load_GDEF_Table( HB_Stream stream, 83 HB_GDEFHeader** retptr ) 84{ 85 HB_Error error; 86 HB_UInt cur_offset, new_offset, base_offset; 87 88 HB_GDEFHeader* gdef; 89 90 91 if ( !retptr ) 92 return ERR(HB_Err_Invalid_Argument); 93 94 if ( GOTO_Table( TTAG_GDEF ) ) 95 return error; 96 97 if (( error = HB_New_GDEF_Table ( &gdef ) )) 98 return error; 99 100 base_offset = FILE_Pos(); 101 102 /* skip version */ 103 104 if ( FILE_Seek( base_offset + 4L ) || 105 ACCESS_Frame( 2L ) ) 106 goto Fail0; 107 108 new_offset = GET_UShort(); 109 110 FORGET_Frame(); 111 112 /* all GDEF subtables are optional */ 113 114 if ( new_offset ) 115 { 116 new_offset += base_offset; 117 118 /* only classes 1-4 are allowed here */ 119 120 cur_offset = FILE_Pos(); 121 if ( FILE_Seek( new_offset ) || 122 ( error = _HB_OPEN_Load_ClassDefinition( &gdef->GlyphClassDef, 5, 123 stream ) ) != HB_Err_Ok ) 124 goto Fail0; 125 (void)FILE_Seek( cur_offset ); 126 } 127 128 if ( ACCESS_Frame( 2L ) ) 129 goto Fail1; 130 131 new_offset = GET_UShort(); 132 133 FORGET_Frame(); 134 135 if ( new_offset ) 136 { 137 new_offset += base_offset; 138 139 cur_offset = FILE_Pos(); 140 if ( FILE_Seek( new_offset ) || 141 ( error = Load_AttachList( &gdef->AttachList, 142 stream ) ) != HB_Err_Ok ) 143 goto Fail1; 144 (void)FILE_Seek( cur_offset ); 145 } 146 147 if ( ACCESS_Frame( 2L ) ) 148 goto Fail2; 149 150 new_offset = GET_UShort(); 151 152 FORGET_Frame(); 153 154 if ( new_offset ) 155 { 156 new_offset += base_offset; 157 158 cur_offset = FILE_Pos(); 159 if ( FILE_Seek( new_offset ) || 160 ( error = Load_LigCaretList( &gdef->LigCaretList, 161 stream ) ) != HB_Err_Ok ) 162 goto Fail2; 163 (void)FILE_Seek( cur_offset ); 164 } 165 166 /* OpenType 1.2 has introduced the `MarkAttachClassDef' field. We 167 first have to scan the LookupFlag values to find out whether we 168 must load it or not. Here we only store the offset of the table. */ 169 170 if ( ACCESS_Frame( 2L ) ) 171 goto Fail3; 172 173 new_offset = GET_UShort(); 174 175 FORGET_Frame(); 176 177 if ( new_offset ) 178 gdef->MarkAttachClassDef_offset = new_offset + base_offset; 179 else 180 gdef->MarkAttachClassDef_offset = 0; 181 182 *retptr = gdef; 183 184 return HB_Err_Ok; 185 186Fail3: 187 Free_LigCaretList( &gdef->LigCaretList ); 188 189Fail2: 190 Free_AttachList( &gdef->AttachList ); 191 192Fail1: 193 _HB_OPEN_Free_ClassDefinition( &gdef->GlyphClassDef ); 194 195Fail0: 196 FREE( gdef ); 197 198 return error; 199} 200 201 202HB_Error HB_Done_GDEF_Table ( HB_GDEFHeader* gdef ) 203{ 204 Free_LigCaretList( &gdef->LigCaretList ); 205 Free_AttachList( &gdef->AttachList ); 206 _HB_OPEN_Free_ClassDefinition( &gdef->GlyphClassDef ); 207 _HB_OPEN_Free_ClassDefinition( &gdef->MarkAttachClassDef ); 208 209 Free_NewGlyphClasses( gdef ); 210 211 FREE( gdef ); 212 213 return HB_Err_Ok; 214} 215 216 217 218 219/******************************* 220 * AttachList related functions 221 *******************************/ 222 223 224/* AttachPoint */ 225 226static HB_Error Load_AttachPoint( HB_AttachPoint* ap, 227 HB_Stream stream ) 228{ 229 HB_Error error; 230 231 HB_UShort n, count; 232 HB_UShort* pi; 233 234 235 if ( ACCESS_Frame( 2L ) ) 236 return error; 237 238 count = ap->PointCount = GET_UShort(); 239 240 FORGET_Frame(); 241 242 ap->PointIndex = NULL; 243 244 if ( count ) 245 { 246 if ( ALLOC_ARRAY( ap->PointIndex, count, HB_UShort ) ) 247 return error; 248 249 pi = ap->PointIndex; 250 251 if ( ACCESS_Frame( count * 2L ) ) 252 { 253 FREE( pi ); 254 return error; 255 } 256 257 for ( n = 0; n < count; n++ ) 258 pi[n] = GET_UShort(); 259 260 FORGET_Frame(); 261 } 262 263 return HB_Err_Ok; 264} 265 266 267static void Free_AttachPoint( HB_AttachPoint* ap ) 268{ 269 FREE( ap->PointIndex ); 270} 271 272 273/* AttachList */ 274 275static HB_Error Load_AttachList( HB_AttachList* al, 276 HB_Stream stream ) 277{ 278 HB_Error error; 279 280 HB_UShort n, m, count; 281 HB_UInt cur_offset, new_offset, base_offset; 282 283 HB_AttachPoint* ap; 284 285 286 base_offset = FILE_Pos(); 287 288 if ( ACCESS_Frame( 2L ) ) 289 return error; 290 291 new_offset = GET_UShort() + base_offset; 292 293 FORGET_Frame(); 294 295 cur_offset = FILE_Pos(); 296 if ( FILE_Seek( new_offset ) || 297 ( error = _HB_OPEN_Load_Coverage( &al->Coverage, stream ) ) != HB_Err_Ok ) 298 return error; 299 (void)FILE_Seek( cur_offset ); 300 301 if ( ACCESS_Frame( 2L ) ) 302 goto Fail2; 303 304 count = al->GlyphCount = GET_UShort(); 305 306 FORGET_Frame(); 307 308 al->AttachPoint = NULL; 309 310 if ( ALLOC_ARRAY( al->AttachPoint, count, HB_AttachPoint ) ) 311 goto Fail2; 312 313 ap = al->AttachPoint; 314 315 for ( n = 0; n < count; n++ ) 316 { 317 if ( ACCESS_Frame( 2L ) ) 318 goto Fail1; 319 320 new_offset = GET_UShort() + base_offset; 321 322 FORGET_Frame(); 323 324 cur_offset = FILE_Pos(); 325 if ( FILE_Seek( new_offset ) || 326 ( error = Load_AttachPoint( &ap[n], stream ) ) != HB_Err_Ok ) 327 goto Fail1; 328 (void)FILE_Seek( cur_offset ); 329 } 330 331 al->loaded = TRUE; 332 333 return HB_Err_Ok; 334 335Fail1: 336 for ( m = 0; m < n; m++ ) 337 Free_AttachPoint( &ap[m] ); 338 339 FREE( ap ); 340 341Fail2: 342 _HB_OPEN_Free_Coverage( &al->Coverage ); 343 return error; 344} 345 346 347static void Free_AttachList( HB_AttachList* al) 348{ 349 HB_UShort n, count; 350 351 HB_AttachPoint* ap; 352 353 354 if ( !al->loaded ) 355 return; 356 357 if ( al->AttachPoint ) 358 { 359 count = al->GlyphCount; 360 ap = al->AttachPoint; 361 362 for ( n = 0; n < count; n++ ) 363 Free_AttachPoint( &ap[n] ); 364 365 FREE( ap ); 366 } 367 368 _HB_OPEN_Free_Coverage( &al->Coverage ); 369} 370 371 372 373/********************************* 374 * LigCaretList related functions 375 *********************************/ 376 377 378/* CaretValueFormat1 */ 379/* CaretValueFormat2 */ 380/* CaretValueFormat3 */ 381/* CaretValueFormat4 */ 382 383static HB_Error Load_CaretValue( HB_CaretValue* cv, 384 HB_Stream stream ) 385{ 386 HB_Error error; 387 388 HB_UInt cur_offset, new_offset, base_offset; 389 390 391 base_offset = FILE_Pos(); 392 393 if ( ACCESS_Frame( 2L ) ) 394 return error; 395 396 cv->CaretValueFormat = GET_UShort(); 397 398 FORGET_Frame(); 399 400 switch ( cv->CaretValueFormat ) 401 { 402 case 1: 403 if ( ACCESS_Frame( 2L ) ) 404 return error; 405 406 cv->cvf.cvf1.Coordinate = GET_Short(); 407 408 FORGET_Frame(); 409 410 break; 411 412 case 2: 413 if ( ACCESS_Frame( 2L ) ) 414 return error; 415 416 cv->cvf.cvf2.CaretValuePoint = GET_UShort(); 417 418 FORGET_Frame(); 419 420 break; 421 422 case 3: 423 if ( ACCESS_Frame( 4L ) ) 424 return error; 425 426 cv->cvf.cvf3.Coordinate = GET_Short(); 427 428 new_offset = GET_UShort() + base_offset; 429 430 FORGET_Frame(); 431 432 cur_offset = FILE_Pos(); 433 if ( FILE_Seek( new_offset ) || 434 ( error = _HB_OPEN_Load_Device( &cv->cvf.cvf3.Device, 435 stream ) ) != HB_Err_Ok ) 436 return error; 437 (void)FILE_Seek( cur_offset ); 438 439 break; 440 441 case 4: 442 if ( ACCESS_Frame( 2L ) ) 443 return error; 444 445#ifdef HB_SUPPORT_MULTIPLE_MASTER 446 cv->cvf.cvf4.IdCaretValue = GET_UShort(); 447#else 448 (void) GET_UShort(); 449#endif 450 451 FORGET_Frame(); 452 break; 453 454 default: 455 return ERR(HB_Err_Invalid_SubTable_Format); 456 } 457 458 return HB_Err_Ok; 459} 460 461 462static void Free_CaretValue( HB_CaretValue* cv) 463{ 464 if ( cv->CaretValueFormat == 3 ) 465 _HB_OPEN_Free_Device( cv->cvf.cvf3.Device ); 466} 467 468 469/* LigGlyph */ 470 471static HB_Error Load_LigGlyph( HB_LigGlyph* lg, 472 HB_Stream stream ) 473{ 474 HB_Error error; 475 476 HB_UShort n, m, count; 477 HB_UInt cur_offset, new_offset, base_offset; 478 479 HB_CaretValue* cv; 480 481 482 base_offset = FILE_Pos(); 483 484 if ( ACCESS_Frame( 2L ) ) 485 return error; 486 487 count = lg->CaretCount = GET_UShort(); 488 489 FORGET_Frame(); 490 491 lg->CaretValue = NULL; 492 493 if ( ALLOC_ARRAY( lg->CaretValue, count, HB_CaretValue ) ) 494 return error; 495 496 cv = lg->CaretValue; 497 498 for ( n = 0; n < count; n++ ) 499 { 500 if ( ACCESS_Frame( 2L ) ) 501 goto Fail; 502 503 new_offset = GET_UShort() + base_offset; 504 505 FORGET_Frame(); 506 507 cur_offset = FILE_Pos(); 508 if ( FILE_Seek( new_offset ) || 509 ( error = Load_CaretValue( &cv[n], stream ) ) != HB_Err_Ok ) 510 goto Fail; 511 (void)FILE_Seek( cur_offset ); 512 } 513 514 return HB_Err_Ok; 515 516Fail: 517 for ( m = 0; m < n; m++ ) 518 Free_CaretValue( &cv[m] ); 519 520 FREE( cv ); 521 return error; 522} 523 524 525static void Free_LigGlyph( HB_LigGlyph* lg) 526{ 527 HB_UShort n, count; 528 529 HB_CaretValue* cv; 530 531 532 if ( lg->CaretValue ) 533 { 534 count = lg->CaretCount; 535 cv = lg->CaretValue; 536 537 for ( n = 0; n < count; n++ ) 538 Free_CaretValue( &cv[n] ); 539 540 FREE( cv ); 541 } 542} 543 544 545/* LigCaretList */ 546 547static HB_Error Load_LigCaretList( HB_LigCaretList* lcl, 548 HB_Stream stream ) 549{ 550 HB_Error error; 551 552 HB_UShort m, n, count; 553 HB_UInt cur_offset, new_offset, base_offset; 554 555 HB_LigGlyph* lg; 556 557 558 base_offset = FILE_Pos(); 559 560 if ( ACCESS_Frame( 2L ) ) 561 return error; 562 563 new_offset = GET_UShort() + base_offset; 564 565 FORGET_Frame(); 566 567 cur_offset = FILE_Pos(); 568 if ( FILE_Seek( new_offset ) || 569 ( error = _HB_OPEN_Load_Coverage( &lcl->Coverage, stream ) ) != HB_Err_Ok ) 570 return error; 571 (void)FILE_Seek( cur_offset ); 572 573 if ( ACCESS_Frame( 2L ) ) 574 goto Fail2; 575 576 count = lcl->LigGlyphCount = GET_UShort(); 577 578 FORGET_Frame(); 579 580 lcl->LigGlyph = NULL; 581 582 if ( ALLOC_ARRAY( lcl->LigGlyph, count, HB_LigGlyph ) ) 583 goto Fail2; 584 585 lg = lcl->LigGlyph; 586 587 for ( n = 0; n < count; n++ ) 588 { 589 if ( ACCESS_Frame( 2L ) ) 590 goto Fail1; 591 592 new_offset = GET_UShort() + base_offset; 593 594 FORGET_Frame(); 595 596 cur_offset = FILE_Pos(); 597 if ( FILE_Seek( new_offset ) || 598 ( error = Load_LigGlyph( &lg[n], stream ) ) != HB_Err_Ok ) 599 goto Fail1; 600 (void)FILE_Seek( cur_offset ); 601 } 602 603 lcl->loaded = TRUE; 604 605 return HB_Err_Ok; 606 607Fail1: 608 for ( m = 0; m < n; m++ ) 609 Free_LigGlyph( &lg[m] ); 610 611 FREE( lg ); 612 613Fail2: 614 _HB_OPEN_Free_Coverage( &lcl->Coverage ); 615 return error; 616} 617 618 619static void Free_LigCaretList( HB_LigCaretList* lcl ) 620{ 621 HB_UShort n, count; 622 623 HB_LigGlyph* lg; 624 625 626 if ( !lcl->loaded ) 627 return; 628 629 if ( lcl->LigGlyph ) 630 { 631 count = lcl->LigGlyphCount; 632 lg = lcl->LigGlyph; 633 634 for ( n = 0; n < count; n++ ) 635 Free_LigGlyph( &lg[n] ); 636 637 FREE( lg ); 638 } 639 640 _HB_OPEN_Free_Coverage( &lcl->Coverage ); 641} 642 643 644 645/*********** 646 * GDEF API 647 ***********/ 648 649 650static HB_UShort Get_New_Class( HB_GDEFHeader* gdef, 651 HB_UShort glyphID, 652 HB_UShort index ) 653{ 654 HB_UShort glyph_index, array_index, count; 655 HB_UShort byte, bits; 656 657 HB_ClassRangeRecord* gcrr; 658 HB_UShort** ngc; 659 660 661 if ( glyphID >= gdef->LastGlyph ) 662 return 0; 663 664 count = gdef->GlyphClassDef.cd.cd2.ClassRangeCount; 665 gcrr = gdef->GlyphClassDef.cd.cd2.ClassRangeRecord; 666 ngc = gdef->NewGlyphClasses; 667 668 if ( index < count && glyphID < gcrr[index].Start ) 669 { 670 array_index = index; 671 if ( index == 0 ) 672 glyph_index = glyphID; 673 else 674 glyph_index = glyphID - gcrr[index - 1].End - 1; 675 } 676 else 677 { 678 array_index = index + 1; 679 glyph_index = glyphID - gcrr[index].End - 1; 680 } 681 682 byte = ngc[array_index][glyph_index / 4]; 683 bits = byte >> ( 16 - ( glyph_index % 4 + 1 ) * 4 ); 684 685 return bits & 0x000F; 686} 687 688 689 690HB_Error HB_GDEF_Get_Glyph_Property( HB_GDEFHeader* gdef, 691 HB_UShort glyphID, 692 HB_UShort* property ) 693{ 694 HB_UShort class = 0, index = 0; /* shut compiler up */ 695 696 HB_Error error; 697 698 699 if ( !gdef || !property ) 700 return ERR(HB_Err_Invalid_Argument); 701 702 /* first, we check for mark attach classes */ 703 704 if ( gdef->MarkAttachClassDef.loaded ) 705 { 706 error = _HB_OPEN_Get_Class( &gdef->MarkAttachClassDef, glyphID, &class, &index ); 707 if ( error && error != HB_Err_Not_Covered ) 708 return error; 709 if ( !error ) 710 { 711 *property = class << 8; 712 return HB_Err_Ok; 713 } 714 } 715 716 error = _HB_OPEN_Get_Class( &gdef->GlyphClassDef, glyphID, &class, &index ); 717 if ( error && error != HB_Err_Not_Covered ) 718 return error; 719 720 /* if we have a constructed class table, check whether additional 721 values have been assigned */ 722 723 if ( error == HB_Err_Not_Covered && gdef->NewGlyphClasses ) 724 class = Get_New_Class( gdef, glyphID, index ); 725 726 switch ( class ) 727 { 728 default: 729 case UNCLASSIFIED_GLYPH: 730 *property = 0; 731 break; 732 733 case SIMPLE_GLYPH: 734 *property = HB_GDEF_BASE_GLYPH; 735 break; 736 737 case LIGATURE_GLYPH: 738 *property = HB_GDEF_LIGATURE; 739 break; 740 741 case MARK_GLYPH: 742 *property = HB_GDEF_MARK; 743 break; 744 745 case COMPONENT_GLYPH: 746 *property = HB_GDEF_COMPONENT; 747 break; 748 } 749 750 return HB_Err_Ok; 751} 752 753 754static HB_Error Make_ClassRange( HB_ClassDefinition* cd, 755 HB_UShort start, 756 HB_UShort end, 757 HB_UShort class ) 758{ 759 HB_Error error; 760 HB_UShort index; 761 762 HB_ClassDefFormat2* cdf2; 763 HB_ClassRangeRecord* crr; 764 765 766 cdf2 = &cd->cd.cd2; 767 768 if ( REALLOC_ARRAY( cdf2->ClassRangeRecord, 769 cdf2->ClassRangeCount + 1 , 770 HB_ClassRangeRecord ) ) 771 return error; 772 773 cdf2->ClassRangeCount++; 774 775 crr = cdf2->ClassRangeRecord; 776 index = cdf2->ClassRangeCount - 1; 777 778 crr[index].Start = start; 779 crr[index].End = end; 780 crr[index].Class = class; 781 782 return HB_Err_Ok; 783} 784 785 786 787HB_Error HB_GDEF_Build_ClassDefinition( HB_GDEFHeader* gdef, 788 HB_UShort num_glyphs, 789 HB_UShort glyph_count, 790 HB_UShort* glyph_array, 791 HB_UShort* class_array ) 792{ 793 HB_UShort start, curr_glyph, curr_class; 794 HB_UShort n, m, count; 795 HB_Error error; 796 797 HB_ClassDefinition* gcd; 798 HB_ClassRangeRecord* gcrr; 799 HB_UShort** ngc; 800 801 802 if ( !gdef || !glyph_array || !class_array ) 803 return ERR(HB_Err_Invalid_Argument); 804 805 gcd = &gdef->GlyphClassDef; 806 807 /* We build a format 2 table */ 808 809 gcd->ClassFormat = 2; 810 811 gcd->cd.cd2.ClassRangeCount = 0; 812 gcd->cd.cd2.ClassRangeRecord = NULL; 813 814 start = glyph_array[0]; 815 curr_class = class_array[0]; 816 curr_glyph = start; 817 818 if ( curr_class >= 5 ) 819 { 820 error = ERR(HB_Err_Invalid_Argument); 821 goto Fail4; 822 } 823 824 glyph_count--; 825 826 for ( n = 0; n < glyph_count + 1; n++ ) 827 { 828 if ( curr_glyph == glyph_array[n] && curr_class == class_array[n] ) 829 { 830 if ( n == glyph_count ) 831 { 832 if ( ( error = Make_ClassRange( gcd, start, 833 curr_glyph, 834 curr_class) ) != HB_Err_Ok ) 835 goto Fail3; 836 } 837 else 838 { 839 if ( curr_glyph == 0xFFFF ) 840 { 841 error = ERR(HB_Err_Invalid_Argument); 842 goto Fail3; 843 } 844 else 845 curr_glyph++; 846 } 847 } 848 else 849 { 850 if ( ( error = Make_ClassRange( gcd, start, 851 curr_glyph - 1, 852 curr_class) ) != HB_Err_Ok ) 853 goto Fail3; 854 855 if ( curr_glyph > glyph_array[n] ) 856 { 857 error = ERR(HB_Err_Invalid_Argument); 858 goto Fail3; 859 } 860 861 start = glyph_array[n]; 862 curr_class = class_array[n]; 863 curr_glyph = start; 864 865 if ( curr_class >= 5 ) 866 { 867 error = ERR(HB_Err_Invalid_Argument); 868 goto Fail3; 869 } 870 871 if ( n == glyph_count ) 872 { 873 if ( ( error = Make_ClassRange( gcd, start, 874 curr_glyph, 875 curr_class) ) != HB_Err_Ok ) 876 goto Fail3; 877 } 878 else 879 { 880 if ( curr_glyph == 0xFFFF ) 881 { 882 error = ERR(HB_Err_Invalid_Argument); 883 goto Fail3; 884 } 885 else 886 curr_glyph++; 887 } 888 } 889 } 890 891 /* now prepare the arrays for class values assigned during the lookup 892 process */ 893 894 if ( ALLOC_ARRAY( gdef->NewGlyphClasses, 895 gcd->cd.cd2.ClassRangeCount + 1, HB_UShort* ) ) 896 goto Fail3; 897 898 count = gcd->cd.cd2.ClassRangeCount; 899 gcrr = gcd->cd.cd2.ClassRangeRecord; 900 ngc = gdef->NewGlyphClasses; 901 902 /* We allocate arrays for all glyphs not covered by the class range 903 records. Each element holds four class values. */ 904 905 if ( count > 0 ) 906 { 907 if ( gcrr[0].Start ) 908 { 909 if ( ALLOC_ARRAY( ngc[0], ( gcrr[0].Start + 3 ) / 4, HB_UShort ) ) 910 goto Fail2; 911 } 912 913 for ( n = 1; n < count; n++ ) 914 { 915 if ( gcrr[n].Start - gcrr[n - 1].End > 1 ) 916 if ( ALLOC_ARRAY( ngc[n], 917 ( gcrr[n].Start - gcrr[n - 1].End + 2 ) / 4, 918 HB_UShort ) ) 919 goto Fail1; 920 } 921 922 if ( gcrr[count - 1].End != num_glyphs - 1 ) 923 { 924 if ( ALLOC_ARRAY( ngc[count], 925 ( num_glyphs - gcrr[count - 1].End + 2 ) / 4, 926 HB_UShort ) ) 927 goto Fail1; 928 } 929 } 930 else if ( num_glyphs > 0 ) 931 { 932 if ( ALLOC_ARRAY( ngc[count], 933 ( num_glyphs + 3 ) / 4, 934 HB_UShort ) ) 935 goto Fail2; 936 } 937 938 gdef->LastGlyph = num_glyphs - 1; 939 940 gdef->MarkAttachClassDef_offset = 0L; 941 gdef->MarkAttachClassDef.loaded = FALSE; 942 943 gcd->loaded = TRUE; 944 945 return HB_Err_Ok; 946 947Fail1: 948 for ( m = 0; m < n; m++ ) 949 FREE( ngc[m] ); 950 951Fail2: 952 FREE( gdef->NewGlyphClasses ); 953 954Fail3: 955 FREE( gcd->cd.cd2.ClassRangeRecord ); 956 957Fail4: 958 return error; 959} 960 961 962static void Free_NewGlyphClasses( HB_GDEFHeader* gdef ) 963{ 964 HB_UShort** ngc; 965 HB_UShort n, count; 966 967 968 if ( gdef->NewGlyphClasses ) 969 { 970 count = gdef->GlyphClassDef.cd.cd2.ClassRangeCount + 1; 971 ngc = gdef->NewGlyphClasses; 972 973 for ( n = 0; n < count; n++ ) 974 FREE( ngc[n] ); 975 976 FREE( ngc ); 977 } 978} 979 980 981HB_INTERNAL HB_Error 982_HB_GDEF_Add_Glyph_Property( HB_GDEFHeader* gdef, 983 HB_UShort glyphID, 984 HB_UShort property ) 985{ 986 HB_Error error; 987 HB_UShort class, new_class, index = 0; /* shut compiler up */ 988 HB_UShort byte, bits, mask; 989 HB_UShort array_index, glyph_index, count; 990 991 HB_ClassRangeRecord* gcrr; 992 HB_UShort** ngc; 993 994 995 error = _HB_OPEN_Get_Class( &gdef->GlyphClassDef, glyphID, &class, &index ); 996 if ( error && error != HB_Err_Not_Covered ) 997 return error; 998 999 /* we don't accept glyphs covered in `GlyphClassDef' */ 1000 1001 if ( !error ) 1002 return HB_Err_Not_Covered; 1003 1004 switch ( property ) 1005 { 1006 case 0: 1007 new_class = UNCLASSIFIED_GLYPH; 1008 break; 1009 1010 case HB_GDEF_BASE_GLYPH: 1011 new_class = SIMPLE_GLYPH; 1012 break; 1013 1014 case HB_GDEF_LIGATURE: 1015 new_class = LIGATURE_GLYPH; 1016 break; 1017 1018 case HB_GDEF_MARK: 1019 new_class = MARK_GLYPH; 1020 break; 1021 1022 case HB_GDEF_COMPONENT: 1023 new_class = COMPONENT_GLYPH; 1024 break; 1025 1026 default: 1027 return ERR(HB_Err_Invalid_Argument); 1028 } 1029 1030 count = gdef->GlyphClassDef.cd.cd2.ClassRangeCount; 1031 gcrr = gdef->GlyphClassDef.cd.cd2.ClassRangeRecord; 1032 ngc = gdef->NewGlyphClasses; 1033 1034 if ( index < count && glyphID < gcrr[index].Start ) 1035 { 1036 array_index = index; 1037 if ( index == 0 ) 1038 glyph_index = glyphID; 1039 else 1040 glyph_index = glyphID - gcrr[index - 1].End - 1; 1041 } 1042 else 1043 { 1044 array_index = index + 1; 1045 glyph_index = glyphID - gcrr[index].End - 1; 1046 } 1047 1048 byte = ngc[array_index][glyph_index / 4]; 1049 bits = byte >> ( 16 - ( glyph_index % 4 + 1 ) * 4 ); 1050 class = bits & 0x000F; 1051 1052 /* we don't overwrite existing entries */ 1053 1054 if ( !class ) 1055 { 1056 bits = new_class << ( 16 - ( glyph_index % 4 + 1 ) * 4 ); 1057 mask = ~( 0x000F << ( 16 - ( glyph_index % 4 + 1 ) * 4 ) ); 1058 1059 ngc[array_index][glyph_index / 4] &= mask; 1060 ngc[array_index][glyph_index / 4] |= bits; 1061 } 1062 1063 return HB_Err_Ok; 1064} 1065 1066 1067HB_INTERNAL HB_Error 1068_HB_GDEF_Check_Property( HB_GDEFHeader* gdef, 1069 HB_GlyphItem gitem, 1070 HB_UShort flags, 1071 HB_UShort* property ) 1072{ 1073 HB_Error error; 1074 1075 if ( gdef ) 1076 { 1077 HB_UShort basic_glyph_class; 1078 HB_UShort desired_attachment_class; 1079 1080 if ( gitem->gproperties == HB_GLYPH_PROPERTIES_UNKNOWN ) 1081 { 1082 error = HB_GDEF_Get_Glyph_Property( gdef, gitem->gindex, &gitem->gproperties ); 1083 if ( error ) 1084 return error; 1085 } 1086 1087 *property = gitem->gproperties; 1088 1089 /* If the glyph was found in the MarkAttachmentClass table, 1090 * then that class value is the high byte of the result, 1091 * otherwise the low byte contains the basic type of the glyph 1092 * as defined by the GlyphClassDef table. 1093 */ 1094 if ( *property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) 1095 basic_glyph_class = HB_GDEF_MARK; 1096 else 1097 basic_glyph_class = *property; 1098 1099 /* Return Not_Covered, if, for example, basic_glyph_class 1100 * is HB_GDEF_LIGATURE and LookFlags includes HB_LOOKUP_FLAG_IGNORE_LIGATURES 1101 */ 1102 if ( flags & basic_glyph_class ) 1103 return HB_Err_Not_Covered; 1104 1105 /* The high byte of LookupFlags has the meaning 1106 * "ignore marks of attachment type different than 1107 * the attachment type specified." 1108 */ 1109 desired_attachment_class = flags & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS; 1110 if ( desired_attachment_class ) 1111 { 1112 if ( basic_glyph_class == HB_GDEF_MARK && 1113 *property != desired_attachment_class ) 1114 return HB_Err_Not_Covered; 1115 } 1116 } else { 1117 *property = 0; 1118 } 1119 1120 return HB_Err_Ok; 1121} 1122 1123HB_INTERNAL HB_Error 1124_HB_GDEF_LoadMarkAttachClassDef_From_LookupFlags( HB_GDEFHeader* gdef, 1125 HB_Stream stream, 1126 HB_Lookup* lo, 1127 HB_UShort num_lookups) 1128{ 1129 HB_Error error = HB_Err_Ok; 1130 HB_UShort i; 1131 1132 /* We now check the LookupFlags for values larger than 0xFF to find 1133 out whether we need to load the `MarkAttachClassDef' field of the 1134 GDEF table -- this hack is necessary for OpenType 1.2 tables since 1135 the version field of the GDEF table hasn't been incremented. 1136 1137 For constructed GDEF tables, we only load it if 1138 `MarkAttachClassDef_offset' is not zero (nevertheless, a build of 1139 a constructed mark attach table is not supported currently). */ 1140 1141 if ( gdef && 1142 gdef->MarkAttachClassDef_offset && !gdef->MarkAttachClassDef.loaded ) 1143 { 1144 for ( i = 0; i < num_lookups; i++ ) 1145 { 1146 1147 if ( lo[i].LookupFlag & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) 1148 { 1149 if ( FILE_Seek( gdef->MarkAttachClassDef_offset ) || 1150 ( error = _HB_OPEN_Load_ClassDefinition( &gdef->MarkAttachClassDef, 1151 256, stream ) ) != HB_Err_Ok ) 1152 goto Done; 1153 1154 break; 1155 } 1156 } 1157 } 1158 1159Done: 1160 return error; 1161} 1162 1163/* END */ 1164