1 /* 2 * Copyright (C) 1998-2004 David Turner and Werner Lemberg 3 * Copyright (C) 2006 Behdad Esfahbod 4 * Copyright (C) 2007 Red Hat, Inc. 5 * 6 * This is part of HarfBuzz, an OpenType Layout engine library. 7 * 8 * Permission is hereby granted, without written agreement and without 9 * license or royalty fees, to use, copy, modify, and distribute this 10 * software and its documentation for any purpose, provided that the 11 * above copyright notice and the following two paragraphs appear in 12 * all copies of this software. 13 * 14 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 15 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 16 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 17 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 18 * DAMAGE. 19 * 20 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 21 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 22 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 23 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 24 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 25 * 26 * Red Hat Author(s): Behdad Esfahbod 27 */ 28 29 #include "harfbuzz-impl.h" 30 #include "harfbuzz-gpos-private.h" 31 #include "harfbuzz-open-private.h" 32 #include "harfbuzz-gdef-private.h" 33 #include "harfbuzz-shaper.h" 34 35 struct GPOS_Instance_ 36 { 37 HB_GPOSHeader* gpos; 38 HB_Font font; 39 HB_Bool dvi; 40 HB_UShort load_flags; /* how the glyph should be loaded */ 41 HB_Bool r2l; 42 43 HB_UShort last; /* the last valid glyph -- used 44 with cursive positioning */ 45 HB_Fixed anchor_x; /* the coordinates of the anchor point */ 46 HB_Fixed anchor_y; /* of the last valid glyph */ 47 }; 48 49 typedef struct GPOS_Instance_ GPOS_Instance; 50 51 52 static HB_Error GPOS_Do_Glyph_Lookup( GPOS_Instance* gpi, 53 HB_UShort lookup_index, 54 HB_Buffer buffer, 55 HB_UShort context_length, 56 int nesting_level ); 57 58 59 60 #ifdef HB_SUPPORT_MULTIPLE_MASTER 61 /* the client application must replace this with something more 62 meaningful if multiple master fonts are to be supported. */ 63 64 static HB_Error default_mmfunc( HB_Font font, 65 HB_UShort metric_id, 66 HB_Fixed* metric_value, 67 void* data ) 68 { 69 HB_UNUSED(font); 70 HB_UNUSED(metric_id); 71 HB_UNUSED(metric_value); 72 HB_UNUSED(data); 73 return ERR(HB_Err_Not_Covered); /* ERR() call intended */ 74 } 75 #endif 76 77 78 79 HB_Error HB_Load_GPOS_Table( HB_Stream stream, 80 HB_GPOSHeader** retptr, 81 HB_GDEFHeader* gdef, 82 HB_Stream gdefStream ) 83 { 84 HB_UInt cur_offset, new_offset, base_offset; 85 86 HB_GPOSHeader* gpos; 87 88 HB_Error error; 89 90 91 if ( !retptr ) 92 return ERR(HB_Err_Invalid_Argument); 93 94 if ( GOTO_Table( TTAG_GPOS ) ) 95 return error; 96 97 base_offset = FILE_Pos(); 98 99 if ( ALLOC ( gpos, sizeof( *gpos ) ) ) 100 return error; 101 102 #ifdef HB_SUPPORT_MULTIPLE_MASTER 103 gpos->mmfunc = default_mmfunc; 104 #endif 105 106 /* skip version */ 107 108 if ( FILE_Seek( base_offset + 4L ) || 109 ACCESS_Frame( 2L ) ) 110 goto Fail4; 111 112 new_offset = GET_UShort() + base_offset; 113 114 FORGET_Frame(); 115 116 cur_offset = FILE_Pos(); 117 if ( FILE_Seek( new_offset ) || 118 ( error = _HB_OPEN_Load_ScriptList( &gpos->ScriptList, 119 stream ) ) != HB_Err_Ok ) 120 goto Fail4; 121 (void)FILE_Seek( cur_offset ); 122 123 if ( ACCESS_Frame( 2L ) ) 124 goto Fail3; 125 126 new_offset = GET_UShort() + base_offset; 127 128 FORGET_Frame(); 129 130 cur_offset = FILE_Pos(); 131 if ( FILE_Seek( new_offset ) || 132 ( error = _HB_OPEN_Load_FeatureList( &gpos->FeatureList, 133 stream ) ) != HB_Err_Ok ) 134 goto Fail3; 135 (void)FILE_Seek( cur_offset ); 136 137 if ( ACCESS_Frame( 2L ) ) 138 goto Fail2; 139 140 new_offset = GET_UShort() + base_offset; 141 142 FORGET_Frame(); 143 144 cur_offset = FILE_Pos(); 145 if ( FILE_Seek( new_offset ) || 146 ( error = _HB_OPEN_Load_LookupList( &gpos->LookupList, 147 stream, HB_Type_GPOS ) ) != HB_Err_Ok ) 148 goto Fail2; 149 150 gpos->gdef = gdef; /* can be NULL */ 151 152 if ( ( error = _HB_GDEF_LoadMarkAttachClassDef_From_LookupFlags( gdef, gdefStream, 153 gpos->LookupList.Lookup, 154 gpos->LookupList.LookupCount ) ) ) 155 goto Fail1; 156 157 *retptr = gpos; 158 159 return HB_Err_Ok; 160 161 Fail1: 162 _HB_OPEN_Free_LookupList( &gpos->LookupList, HB_Type_GPOS ); 163 164 Fail2: 165 _HB_OPEN_Free_FeatureList( &gpos->FeatureList ); 166 167 Fail3: 168 _HB_OPEN_Free_ScriptList( &gpos->ScriptList ); 169 170 Fail4: 171 FREE( gpos ); 172 173 return error; 174 } 175 176 177 HB_Error HB_Done_GPOS_Table( HB_GPOSHeader* gpos ) 178 { 179 _HB_OPEN_Free_LookupList( &gpos->LookupList, HB_Type_GPOS ); 180 _HB_OPEN_Free_FeatureList( &gpos->FeatureList ); 181 _HB_OPEN_Free_ScriptList( &gpos->ScriptList ); 182 183 FREE( gpos ); 184 185 return HB_Err_Ok; 186 } 187 188 189 /***************************** 190 * SubTable related functions 191 *****************************/ 192 193 /* shared tables */ 194 195 /* ValueRecord */ 196 197 /* There is a subtle difference in the specs between a `table' and a 198 `record' -- offsets for device tables in ValueRecords are taken from 199 the parent table and not the parent record. */ 200 201 static HB_Error Load_ValueRecord( HB_ValueRecord* vr, 202 HB_UShort format, 203 HB_UInt base_offset, 204 HB_Stream stream ) 205 { 206 HB_Error error; 207 208 HB_UInt cur_offset, new_offset; 209 210 211 if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT ) 212 { 213 if ( ACCESS_Frame( 2L ) ) 214 return error; 215 216 vr->XPlacement = GET_Short(); 217 218 FORGET_Frame(); 219 } 220 else 221 vr->XPlacement = 0; 222 223 if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT ) 224 { 225 if ( ACCESS_Frame( 2L ) ) 226 return error; 227 228 vr->YPlacement = GET_Short(); 229 230 FORGET_Frame(); 231 } 232 else 233 vr->YPlacement = 0; 234 235 if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE ) 236 { 237 if ( ACCESS_Frame( 2L ) ) 238 return error; 239 240 vr->XAdvance = GET_Short(); 241 242 FORGET_Frame(); 243 } 244 else 245 vr->XAdvance = 0; 246 247 if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE ) 248 { 249 if ( ACCESS_Frame( 2L ) ) 250 return error; 251 252 vr->YAdvance = GET_Short(); 253 254 FORGET_Frame(); 255 } 256 else 257 vr->YAdvance = 0; 258 259 if ( format & HB_GPOS_FORMAT_HAVE_DEVICE_TABLES ) 260 { 261 if ( ALLOC_ARRAY( vr->DeviceTables, 4, HB_Device ) ) 262 return error; 263 vr->DeviceTables[VR_X_ADVANCE_DEVICE] = 0; 264 vr->DeviceTables[VR_Y_ADVANCE_DEVICE] = 0; 265 vr->DeviceTables[VR_X_PLACEMENT_DEVICE] = 0; 266 vr->DeviceTables[VR_Y_PLACEMENT_DEVICE] = 0; 267 } 268 else 269 { 270 vr->DeviceTables = 0; 271 } 272 273 if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE ) 274 { 275 if ( ACCESS_Frame( 2L ) ) 276 goto Fail4; 277 278 new_offset = GET_UShort(); 279 280 FORGET_Frame(); 281 282 if ( new_offset ) 283 { 284 new_offset += base_offset; 285 286 cur_offset = FILE_Pos(); 287 if ( FILE_Seek( new_offset ) || 288 ( error = _HB_OPEN_Load_Device( &vr->DeviceTables[VR_X_PLACEMENT_DEVICE], 289 stream ) ) != HB_Err_Ok ) 290 goto Fail4; 291 (void)FILE_Seek( cur_offset ); 292 } 293 } 294 295 if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE ) 296 { 297 if ( ACCESS_Frame( 2L ) ) 298 goto Fail3; 299 300 new_offset = GET_UShort(); 301 302 FORGET_Frame(); 303 304 if ( new_offset ) 305 { 306 new_offset += base_offset; 307 308 cur_offset = FILE_Pos(); 309 if ( FILE_Seek( new_offset ) || 310 ( error = _HB_OPEN_Load_Device( &vr->DeviceTables[VR_Y_PLACEMENT_DEVICE], 311 stream ) ) != HB_Err_Ok ) 312 goto Fail3; 313 (void)FILE_Seek( cur_offset ); 314 } 315 } 316 317 if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE ) 318 { 319 if ( ACCESS_Frame( 2L ) ) 320 goto Fail2; 321 322 new_offset = GET_UShort(); 323 324 FORGET_Frame(); 325 326 if ( new_offset ) 327 { 328 new_offset += base_offset; 329 330 cur_offset = FILE_Pos(); 331 if ( FILE_Seek( new_offset ) || 332 ( error = _HB_OPEN_Load_Device( &vr->DeviceTables[VR_X_ADVANCE_DEVICE], 333 stream ) ) != HB_Err_Ok ) 334 goto Fail2; 335 (void)FILE_Seek( cur_offset ); 336 } 337 } 338 339 if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE ) 340 { 341 if ( ACCESS_Frame( 2L ) ) 342 goto Fail1; 343 344 new_offset = GET_UShort(); 345 346 FORGET_Frame(); 347 348 if ( new_offset ) 349 { 350 new_offset += base_offset; 351 352 cur_offset = FILE_Pos(); 353 if ( FILE_Seek( new_offset ) || 354 ( error = _HB_OPEN_Load_Device( &vr->DeviceTables[VR_Y_ADVANCE_DEVICE], 355 stream ) ) != HB_Err_Ok ) 356 goto Fail1; 357 (void)FILE_Seek( cur_offset ); 358 } 359 } 360 361 if ( format & HB_GPOS_FORMAT_HAVE_X_ID_PLACEMENT ) 362 { 363 if ( ACCESS_Frame( 2L ) ) 364 goto Fail1; 365 366 #ifdef HB_SUPPORT_MULTIPLE_MASTER 367 vr->XIdPlacement = GET_UShort(); 368 #else 369 (void) GET_UShort(); 370 #endif 371 372 FORGET_Frame(); 373 } 374 #ifdef HB_SUPPORT_MULTIPLE_MASTER 375 else 376 vr->XIdPlacement = 0; 377 #endif 378 379 if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_PLACEMENT ) 380 { 381 if ( ACCESS_Frame( 2L ) ) 382 goto Fail1; 383 384 #ifdef HB_SUPPORT_MULTIPLE_MASTER 385 vr->YIdPlacement = GET_UShort(); 386 #else 387 (void) GET_UShort(); 388 #endif 389 390 FORGET_Frame(); 391 } 392 #ifdef HB_SUPPORT_MULTIPLE_MASTER 393 else 394 vr->YIdPlacement = 0; 395 #endif 396 397 if ( format & HB_GPOS_FORMAT_HAVE_X_ID_ADVANCE ) 398 { 399 if ( ACCESS_Frame( 2L ) ) 400 goto Fail1; 401 402 #ifdef HB_SUPPORT_MULTIPLE_MASTER 403 vr->XIdAdvance = GET_UShort(); 404 #else 405 (void) GET_UShort(); 406 #endif 407 408 FORGET_Frame(); 409 } 410 #ifdef HB_SUPPORT_MULTIPLE_MASTER 411 else 412 vr->XIdAdvance = 0; 413 #endif 414 415 if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_ADVANCE ) 416 { 417 if ( ACCESS_Frame( 2L ) ) 418 goto Fail1; 419 420 #ifdef HB_SUPPORT_MULTIPLE_MASTER 421 vr->YIdAdvance = GET_UShort(); 422 #else 423 (void) GET_UShort(); 424 #endif 425 426 FORGET_Frame(); 427 } 428 #ifdef HB_SUPPORT_MULTIPLE_MASTER 429 else 430 vr->YIdAdvance = 0; 431 #endif 432 433 return HB_Err_Ok; 434 435 Fail1: 436 if ( vr->DeviceTables ) 437 _HB_OPEN_Free_Device( vr->DeviceTables[VR_Y_ADVANCE_DEVICE] ); 438 439 Fail2: 440 if ( vr->DeviceTables ) 441 _HB_OPEN_Free_Device( vr->DeviceTables[VR_X_ADVANCE_DEVICE] ); 442 443 Fail3: 444 if ( vr->DeviceTables ) 445 _HB_OPEN_Free_Device( vr->DeviceTables[VR_Y_PLACEMENT_DEVICE] ); 446 447 Fail4: 448 FREE( vr->DeviceTables ); 449 return error; 450 } 451 452 453 static void Free_ValueRecord( HB_ValueRecord* vr, 454 HB_UShort format ) 455 { 456 if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE ) 457 _HB_OPEN_Free_Device( vr->DeviceTables[VR_Y_ADVANCE_DEVICE] ); 458 if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE ) 459 _HB_OPEN_Free_Device( vr->DeviceTables[VR_X_ADVANCE_DEVICE] ); 460 if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE ) 461 _HB_OPEN_Free_Device( vr->DeviceTables[VR_Y_PLACEMENT_DEVICE] ); 462 if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE ) 463 _HB_OPEN_Free_Device( vr->DeviceTables[VR_X_PLACEMENT_DEVICE] ); 464 FREE( vr->DeviceTables ); 465 } 466 467 468 static HB_Error Get_ValueRecord( GPOS_Instance* gpi, 469 HB_ValueRecord* vr, 470 HB_UShort format, 471 HB_Position gd ) 472 { 473 HB_Short pixel_value; 474 HB_Error error = HB_Err_Ok; 475 #ifdef HB_SUPPORT_MULTIPLE_MASTER 476 HB_GPOSHeader* gpos = gpi->gpos; 477 HB_Fixed value; 478 #endif 479 480 HB_UShort x_ppem, y_ppem; 481 HB_16Dot16 x_scale, y_scale; 482 483 484 if ( !format ) 485 return HB_Err_Ok; 486 487 x_ppem = gpi->font->x_ppem; 488 y_ppem = gpi->font->y_ppem; 489 x_scale = gpi->font->x_scale; 490 y_scale = gpi->font->y_scale; 491 492 /* design units -> fractional pixel */ 493 494 if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT ) 495 gd->x_pos += x_scale * vr->XPlacement / 0x10000; 496 if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT ) 497 gd->y_pos += y_scale * vr->YPlacement / 0x10000; 498 if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE ) 499 gd->x_advance += x_scale * vr->XAdvance / 0x10000; 500 if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE ) 501 gd->y_advance += y_scale * vr->YAdvance / 0x10000; 502 503 if ( !gpi->dvi ) 504 { 505 /* pixel -> fractional pixel */ 506 507 if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE ) 508 { 509 _HB_OPEN_Get_Device( vr->DeviceTables[VR_X_PLACEMENT_DEVICE], x_ppem, &pixel_value ); 510 gd->x_pos += pixel_value << 6; 511 } 512 if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE ) 513 { 514 _HB_OPEN_Get_Device( vr->DeviceTables[VR_Y_PLACEMENT_DEVICE], y_ppem, &pixel_value ); 515 gd->y_pos += pixel_value << 6; 516 } 517 if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE ) 518 { 519 _HB_OPEN_Get_Device( vr->DeviceTables[VR_X_ADVANCE_DEVICE], x_ppem, &pixel_value ); 520 gd->x_advance += pixel_value << 6; 521 } 522 if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE ) 523 { 524 _HB_OPEN_Get_Device( vr->DeviceTables[VR_Y_ADVANCE_DEVICE], y_ppem, &pixel_value ); 525 gd->y_advance += pixel_value << 6; 526 } 527 } 528 529 #ifdef HB_SUPPORT_MULTIPLE_MASTER 530 /* values returned from mmfunc() are already in fractional pixels */ 531 532 if ( format & HB_GPOS_FORMAT_HAVE_X_ID_PLACEMENT ) 533 { 534 error = (gpos->mmfunc)( gpi->font, vr->XIdPlacement, 535 &value, gpos->data ); 536 if ( error ) 537 return error; 538 gd->x_pos += value; 539 } 540 if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_PLACEMENT ) 541 { 542 error = (gpos->mmfunc)( gpi->font, vr->YIdPlacement, 543 &value, gpos->data ); 544 if ( error ) 545 return error; 546 gd->y_pos += value; 547 } 548 if ( format & HB_GPOS_FORMAT_HAVE_X_ID_ADVANCE ) 549 { 550 error = (gpos->mmfunc)( gpi->font, vr->XIdAdvance, 551 &value, gpos->data ); 552 if ( error ) 553 return error; 554 gd->x_advance += value; 555 } 556 if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_ADVANCE ) 557 { 558 error = (gpos->mmfunc)( gpi->font, vr->YIdAdvance, 559 &value, gpos->data ); 560 if ( error ) 561 return error; 562 gd->y_advance += value; 563 } 564 #endif 565 566 return error; 567 } 568 569 570 /* AnchorFormat1 */ 571 /* AnchorFormat2 */ 572 /* AnchorFormat3 */ 573 /* AnchorFormat4 */ 574 575 static HB_Error Load_Anchor( HB_Anchor* an, 576 HB_Stream stream ) 577 { 578 HB_Error error; 579 580 HB_UInt cur_offset, new_offset, base_offset; 581 582 583 base_offset = FILE_Pos(); 584 585 if ( ACCESS_Frame( 2L ) ) 586 return error; 587 588 an->PosFormat = GET_UShort(); 589 590 FORGET_Frame(); 591 592 switch ( an->PosFormat ) 593 { 594 case 1: 595 if ( ACCESS_Frame( 4L ) ) 596 return error; 597 598 an->af.af1.XCoordinate = GET_Short(); 599 an->af.af1.YCoordinate = GET_Short(); 600 601 FORGET_Frame(); 602 break; 603 604 case 2: 605 if ( ACCESS_Frame( 6L ) ) 606 return error; 607 608 an->af.af2.XCoordinate = GET_Short(); 609 an->af.af2.YCoordinate = GET_Short(); 610 an->af.af2.AnchorPoint = GET_UShort(); 611 612 FORGET_Frame(); 613 break; 614 615 case 3: 616 if ( ACCESS_Frame( 6L ) ) 617 return error; 618 619 an->af.af3.XCoordinate = GET_Short(); 620 an->af.af3.YCoordinate = GET_Short(); 621 622 new_offset = GET_UShort(); 623 624 FORGET_Frame(); 625 626 if ( new_offset ) 627 { 628 if ( ALLOC_ARRAY( an->af.af3.DeviceTables, 2, HB_Device ) ) 629 return error; 630 631 an->af.af3.DeviceTables[AF3_X_DEVICE_TABLE] = 0; 632 an->af.af3.DeviceTables[AF3_Y_DEVICE_TABLE] = 0; 633 634 new_offset += base_offset; 635 636 cur_offset = FILE_Pos(); 637 if ( FILE_Seek( new_offset ) || 638 ( error = _HB_OPEN_Load_Device( &an->af.af3.DeviceTables[AF3_X_DEVICE_TABLE], 639 stream ) ) != HB_Err_Ok ) 640 goto Fail2; 641 (void)FILE_Seek( cur_offset ); 642 } 643 644 if ( ACCESS_Frame( 2L ) ) 645 goto Fail; 646 647 new_offset = GET_UShort(); 648 649 FORGET_Frame(); 650 651 if ( new_offset ) 652 { 653 if ( !an->af.af3.DeviceTables ) 654 { 655 if ( ALLOC_ARRAY( an->af.af3.DeviceTables, 2, HB_Device ) ) 656 return error; 657 658 an->af.af3.DeviceTables[AF3_X_DEVICE_TABLE] = 0; 659 an->af.af3.DeviceTables[AF3_Y_DEVICE_TABLE] = 0; 660 } 661 662 new_offset += base_offset; 663 664 cur_offset = FILE_Pos(); 665 if ( FILE_Seek( new_offset ) || 666 ( error = _HB_OPEN_Load_Device( &an->af.af3.DeviceTables[AF3_Y_DEVICE_TABLE], 667 stream ) ) != HB_Err_Ok ) 668 goto Fail; 669 (void)FILE_Seek( cur_offset ); 670 } 671 break; 672 673 case 4: 674 if ( ACCESS_Frame( 4L ) ) 675 return error; 676 677 #ifdef HB_SUPPORT_MULTIPLE_MASTER 678 an->af.af4.XIdAnchor = GET_UShort(); 679 an->af.af4.YIdAnchor = GET_UShort(); 680 #else 681 (void) GET_UShort(); 682 (void) GET_UShort(); 683 #endif 684 685 FORGET_Frame(); 686 break; 687 688 default: 689 return ERR(HB_Err_Invalid_SubTable_Format); 690 } 691 692 return HB_Err_Ok; 693 694 Fail: 695 if ( an->af.af3.DeviceTables ) 696 _HB_OPEN_Free_Device( an->af.af3.DeviceTables[AF3_X_DEVICE_TABLE] ); 697 698 Fail2: 699 FREE( an->af.af3.DeviceTables ); 700 return error; 701 } 702 703 704 static void Free_Anchor( HB_Anchor* an) 705 { 706 if ( an->PosFormat == 3 && an->af.af3.DeviceTables ) 707 { 708 _HB_OPEN_Free_Device( an->af.af3.DeviceTables[AF3_X_DEVICE_TABLE] ); 709 _HB_OPEN_Free_Device( an->af.af3.DeviceTables[AF3_Y_DEVICE_TABLE] ); 710 FREE( an->af.af3.DeviceTables ); 711 } 712 } 713 714 715 static HB_Error Get_Anchor( GPOS_Instance* gpi, 716 HB_Anchor* an, 717 HB_UShort glyph_index, 718 HB_Fixed* x_value, 719 HB_Fixed* y_value ) 720 { 721 HB_Error error = HB_Err_Ok; 722 723 #ifdef HB_SUPPORT_MULTIPLE_MASTER 724 HB_GPOSHeader* gpos = gpi->gpos; 725 #endif 726 HB_UShort ap; 727 728 HB_Short pixel_value; 729 730 HB_UShort x_ppem, y_ppem; 731 HB_16Dot16 x_scale, y_scale; 732 733 734 x_ppem = gpi->font->x_ppem; 735 y_ppem = gpi->font->y_ppem; 736 x_scale = gpi->font->x_scale; 737 y_scale = gpi->font->y_scale; 738 739 switch ( an->PosFormat ) 740 { 741 case 0: 742 /* The special case of an empty AnchorTable */ 743 default: 744 745 return HB_Err_Not_Covered; 746 747 case 1: 748 *x_value = x_scale * an->af.af1.XCoordinate / 0x10000; 749 *y_value = y_scale * an->af.af1.YCoordinate / 0x10000; 750 break; 751 752 case 2: 753 if ( !gpi->dvi ) 754 { 755 hb_uint32 n_points = 0; 756 ap = an->af.af2.AnchorPoint; 757 if (!gpi->font->klass->getPointInOutline) 758 goto no_contour_point; 759 error = gpi->font->klass->getPointInOutline(gpi->font, glyph_index, gpi->load_flags, ap, x_value, y_value, &n_points); 760 if (error) 761 return error; 762 /* if n_points is set to zero, we use the design coordinate value pair. 763 * This can happen e.g. for sbit glyphs. */ 764 if (!n_points) 765 goto no_contour_point; 766 } 767 else 768 { 769 no_contour_point: 770 *x_value = x_scale * an->af.af3.XCoordinate / 0x10000; 771 *y_value = y_scale * an->af.af3.YCoordinate / 0x10000; 772 } 773 break; 774 775 case 3: 776 if ( !gpi->dvi ) 777 { 778 _HB_OPEN_Get_Device( an->af.af3.DeviceTables[AF3_X_DEVICE_TABLE], x_ppem, &pixel_value ); 779 *x_value = pixel_value << 6; 780 _HB_OPEN_Get_Device( an->af.af3.DeviceTables[AF3_Y_DEVICE_TABLE], y_ppem, &pixel_value ); 781 *y_value = pixel_value << 6; 782 } 783 else 784 *x_value = *y_value = 0; 785 786 *x_value += x_scale * an->af.af3.XCoordinate / 0x10000; 787 *y_value += y_scale * an->af.af3.YCoordinate / 0x10000; 788 break; 789 790 case 4: 791 #ifdef HB_SUPPORT_MULTIPLE_MASTER 792 error = (gpos->mmfunc)( gpi->font, an->af.af4.XIdAnchor, 793 x_value, gpos->data ); 794 if ( error ) 795 return error; 796 797 error = (gpos->mmfunc)( gpi->font, an->af.af4.YIdAnchor, 798 y_value, gpos->data ); 799 if ( error ) 800 return error; 801 break; 802 #else 803 return ERR(HB_Err_Not_Covered); 804 #endif 805 } 806 807 return error; 808 } 809 810 811 /* MarkArray */ 812 813 static HB_Error Load_MarkArray ( HB_MarkArray* ma, 814 HB_Stream stream ) 815 { 816 HB_Error error; 817 818 HB_UShort n, m, count; 819 HB_UInt cur_offset, new_offset, base_offset; 820 821 HB_MarkRecord* mr; 822 823 824 base_offset = FILE_Pos(); 825 826 if ( ACCESS_Frame( 2L ) ) 827 return error; 828 829 count = ma->MarkCount = GET_UShort(); 830 831 FORGET_Frame(); 832 833 ma->MarkRecord = NULL; 834 835 if ( ALLOC_ARRAY( ma->MarkRecord, count, HB_MarkRecord ) ) 836 return error; 837 838 mr = ma->MarkRecord; 839 840 for ( n = 0; n < count; n++ ) 841 { 842 if ( ACCESS_Frame( 4L ) ) 843 goto Fail; 844 845 mr[n].Class = GET_UShort(); 846 new_offset = GET_UShort() + base_offset; 847 848 FORGET_Frame(); 849 850 cur_offset = FILE_Pos(); 851 if ( FILE_Seek( new_offset ) || 852 ( error = Load_Anchor( &mr[n].MarkAnchor, stream ) ) != HB_Err_Ok ) 853 goto Fail; 854 (void)FILE_Seek( cur_offset ); 855 } 856 857 return HB_Err_Ok; 858 859 Fail: 860 for ( m = 0; m < n; m++ ) 861 Free_Anchor( &mr[m].MarkAnchor ); 862 863 FREE( mr ); 864 return error; 865 } 866 867 868 static void Free_MarkArray( HB_MarkArray* ma ) 869 { 870 HB_UShort n, count; 871 872 HB_MarkRecord* mr; 873 874 875 if ( ma->MarkRecord ) 876 { 877 count = ma->MarkCount; 878 mr = ma->MarkRecord; 879 880 for ( n = 0; n < count; n++ ) 881 Free_Anchor( &mr[n].MarkAnchor ); 882 883 FREE( mr ); 884 } 885 } 886 887 888 /* LookupType 1 */ 889 890 /* SinglePosFormat1 */ 891 /* SinglePosFormat2 */ 892 893 static HB_Error Load_SinglePos( HB_GPOS_SubTable* st, 894 HB_Stream stream ) 895 { 896 HB_Error error; 897 HB_SinglePos* sp = &st->single; 898 899 HB_UShort n, m, count, format; 900 HB_UInt cur_offset, new_offset, base_offset; 901 902 HB_ValueRecord* vr; 903 904 905 base_offset = FILE_Pos(); 906 907 if ( ACCESS_Frame( 6L ) ) 908 return error; 909 910 sp->PosFormat = GET_UShort(); 911 new_offset = GET_UShort() + base_offset; 912 913 format = sp->ValueFormat = GET_UShort(); 914 915 FORGET_Frame(); 916 917 if ( !format ) 918 return ERR(HB_Err_Invalid_SubTable); 919 920 cur_offset = FILE_Pos(); 921 if ( FILE_Seek( new_offset ) || 922 ( error = _HB_OPEN_Load_Coverage( &sp->Coverage, stream ) ) != HB_Err_Ok ) 923 return error; 924 (void)FILE_Seek( cur_offset ); 925 926 switch ( sp->PosFormat ) 927 { 928 case 1: 929 error = Load_ValueRecord( &sp->spf.spf1.Value, format, 930 base_offset, stream ); 931 if ( error ) 932 goto Fail2; 933 break; 934 935 case 2: 936 if ( ACCESS_Frame( 2L ) ) 937 goto Fail2; 938 939 count = sp->spf.spf2.ValueCount = GET_UShort(); 940 941 FORGET_Frame(); 942 943 sp->spf.spf2.Value = NULL; 944 945 if ( ALLOC_ARRAY( sp->spf.spf2.Value, count, HB_ValueRecord ) ) 946 goto Fail2; 947 948 vr = sp->spf.spf2.Value; 949 950 for ( n = 0; n < count; n++ ) 951 { 952 error = Load_ValueRecord( &vr[n], format, base_offset, stream ); 953 if ( error ) 954 goto Fail1; 955 } 956 break; 957 958 default: 959 return ERR(HB_Err_Invalid_SubTable_Format); 960 } 961 962 return HB_Err_Ok; 963 964 Fail1: 965 for ( m = 0; m < n; m++ ) 966 Free_ValueRecord( &vr[m], format ); 967 968 FREE( vr ); 969 970 Fail2: 971 _HB_OPEN_Free_Coverage( &sp->Coverage ); 972 return error; 973 } 974 975 976 static void Free_SinglePos( HB_GPOS_SubTable* st ) 977 { 978 HB_UShort n, count, format; 979 HB_SinglePos* sp = &st->single; 980 981 HB_ValueRecord* v; 982 983 984 format = sp->ValueFormat; 985 986 switch ( sp->PosFormat ) 987 { 988 case 1: 989 Free_ValueRecord( &sp->spf.spf1.Value, format ); 990 break; 991 992 case 2: 993 if ( sp->spf.spf2.Value ) 994 { 995 count = sp->spf.spf2.ValueCount; 996 v = sp->spf.spf2.Value; 997 998 for ( n = 0; n < count; n++ ) 999 Free_ValueRecord( &v[n], format ); 1000 1001 FREE( v ); 1002 } 1003 break; 1004 default: 1005 break; 1006 } 1007 1008 _HB_OPEN_Free_Coverage( &sp->Coverage ); 1009 } 1010 1011 static HB_Error Lookup_SinglePos( GPOS_Instance* gpi, 1012 HB_GPOS_SubTable* st, 1013 HB_Buffer buffer, 1014 HB_UShort flags, 1015 HB_UShort context_length, 1016 int nesting_level ) 1017 { 1018 HB_UShort index, property; 1019 HB_Error error; 1020 HB_GPOSHeader* gpos = gpi->gpos; 1021 HB_SinglePos* sp = &st->single; 1022 1023 HB_UNUSED(nesting_level); 1024 1025 if ( context_length != 0xFFFF && context_length < 1 ) 1026 return HB_Err_Not_Covered; 1027 1028 if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) ) 1029 return error; 1030 1031 error = _HB_OPEN_Coverage_Index( &sp->Coverage, IN_CURGLYPH(), &index ); 1032 if ( error ) 1033 return error; 1034 1035 switch ( sp->PosFormat ) 1036 { 1037 case 1: 1038 error = Get_ValueRecord( gpi, &sp->spf.spf1.Value, 1039 sp->ValueFormat, POSITION( buffer->in_pos ) ); 1040 if ( error ) 1041 return error; 1042 break; 1043 1044 case 2: 1045 if ( index >= sp->spf.spf2.ValueCount ) 1046 return ERR(HB_Err_Invalid_SubTable); 1047 error = Get_ValueRecord( gpi, &sp->spf.spf2.Value[index], 1048 sp->ValueFormat, POSITION( buffer->in_pos ) ); 1049 if ( error ) 1050 return error; 1051 break; 1052 1053 default: 1054 return ERR(HB_Err_Invalid_SubTable); 1055 } 1056 1057 (buffer->in_pos)++; 1058 1059 return HB_Err_Ok; 1060 } 1061 1062 1063 /* LookupType 2 */ 1064 1065 /* PairSet */ 1066 1067 static HB_Error Load_PairSet ( HB_PairSet* ps, 1068 HB_UShort format1, 1069 HB_UShort format2, 1070 HB_Stream stream ) 1071 { 1072 HB_Error error; 1073 1074 HB_UShort n, m, count; 1075 HB_UInt base_offset; 1076 1077 HB_PairValueRecord* pvr; 1078 1079 1080 base_offset = FILE_Pos(); 1081 1082 if ( ACCESS_Frame( 2L ) ) 1083 return error; 1084 1085 count = ps->PairValueCount = GET_UShort(); 1086 1087 FORGET_Frame(); 1088 1089 ps->PairValueRecord = NULL; 1090 1091 if ( ALLOC_ARRAY( ps->PairValueRecord, count, HB_PairValueRecord ) ) 1092 return error; 1093 1094 pvr = ps->PairValueRecord; 1095 1096 for ( n = 0; n < count; n++ ) 1097 { 1098 if ( ACCESS_Frame( 2L ) ) 1099 goto Fail; 1100 1101 pvr[n].SecondGlyph = GET_UShort(); 1102 1103 FORGET_Frame(); 1104 1105 if ( format1 ) 1106 { 1107 error = Load_ValueRecord( &pvr[n].Value1, format1, 1108 base_offset, stream ); 1109 if ( error ) 1110 goto Fail; 1111 } 1112 if ( format2 ) 1113 { 1114 error = Load_ValueRecord( &pvr[n].Value2, format2, 1115 base_offset, stream ); 1116 if ( error ) 1117 { 1118 if ( format1 ) 1119 Free_ValueRecord( &pvr[n].Value1, format1 ); 1120 goto Fail; 1121 } 1122 } 1123 } 1124 1125 return HB_Err_Ok; 1126 1127 Fail: 1128 for ( m = 0; m < n; m++ ) 1129 { 1130 if ( format1 ) 1131 Free_ValueRecord( &pvr[m].Value1, format1 ); 1132 if ( format2 ) 1133 Free_ValueRecord( &pvr[m].Value2, format2 ); 1134 } 1135 1136 FREE( pvr ); 1137 return error; 1138 } 1139 1140 1141 static void Free_PairSet( HB_PairSet* ps, 1142 HB_UShort format1, 1143 HB_UShort format2 ) 1144 { 1145 HB_UShort n, count; 1146 1147 HB_PairValueRecord* pvr; 1148 1149 1150 if ( ps->PairValueRecord ) 1151 { 1152 count = ps->PairValueCount; 1153 pvr = ps->PairValueRecord; 1154 1155 for ( n = 0; n < count; n++ ) 1156 { 1157 if ( format1 ) 1158 Free_ValueRecord( &pvr[n].Value1, format1 ); 1159 if ( format2 ) 1160 Free_ValueRecord( &pvr[n].Value2, format2 ); 1161 } 1162 1163 FREE( pvr ); 1164 } 1165 } 1166 1167 1168 /* PairPosFormat1 */ 1169 1170 static HB_Error Load_PairPos1( HB_PairPosFormat1* ppf1, 1171 HB_UShort format1, 1172 HB_UShort format2, 1173 HB_Stream stream ) 1174 { 1175 HB_Error error; 1176 1177 HB_UShort n, m, count; 1178 HB_UInt cur_offset, new_offset, base_offset; 1179 1180 HB_PairSet* ps; 1181 1182 1183 base_offset = FILE_Pos() - 8L; 1184 1185 if ( ACCESS_Frame( 2L ) ) 1186 return error; 1187 1188 count = ppf1->PairSetCount = GET_UShort(); 1189 1190 FORGET_Frame(); 1191 1192 ppf1->PairSet = NULL; 1193 1194 if ( ALLOC_ARRAY( ppf1->PairSet, count, HB_PairSet ) ) 1195 return error; 1196 1197 ps = ppf1->PairSet; 1198 1199 for ( n = 0; n < count; n++ ) 1200 { 1201 if ( ACCESS_Frame( 2L ) ) 1202 goto Fail; 1203 1204 new_offset = GET_UShort() + base_offset; 1205 1206 FORGET_Frame(); 1207 1208 cur_offset = FILE_Pos(); 1209 if ( FILE_Seek( new_offset ) || 1210 ( error = Load_PairSet( &ps[n], format1, 1211 format2, stream ) ) != HB_Err_Ok ) 1212 goto Fail; 1213 (void)FILE_Seek( cur_offset ); 1214 } 1215 1216 return HB_Err_Ok; 1217 1218 Fail: 1219 for ( m = 0; m < n; m++ ) 1220 Free_PairSet( &ps[m], format1, format2 ); 1221 1222 FREE( ps ); 1223 return error; 1224 } 1225 1226 1227 static void Free_PairPos1( HB_PairPosFormat1* ppf1, 1228 HB_UShort format1, 1229 HB_UShort format2 ) 1230 { 1231 HB_UShort n, count; 1232 1233 HB_PairSet* ps; 1234 1235 1236 if ( ppf1->PairSet ) 1237 { 1238 count = ppf1->PairSetCount; 1239 ps = ppf1->PairSet; 1240 1241 for ( n = 0; n < count; n++ ) 1242 Free_PairSet( &ps[n], format1, format2 ); 1243 1244 FREE( ps ); 1245 } 1246 } 1247 1248 1249 /* PairPosFormat2 */ 1250 1251 static HB_Error Load_PairPos2( HB_PairPosFormat2* ppf2, 1252 HB_UShort format1, 1253 HB_UShort format2, 1254 HB_Stream stream ) 1255 { 1256 HB_Error error; 1257 1258 HB_UShort m, n, k, count1, count2; 1259 HB_UInt cur_offset, new_offset1, new_offset2, base_offset; 1260 1261 HB_Class1Record* c1r; 1262 HB_Class2Record* c2r; 1263 1264 1265 base_offset = FILE_Pos() - 8L; 1266 1267 if ( ACCESS_Frame( 8L ) ) 1268 return error; 1269 1270 new_offset1 = GET_UShort() + base_offset; 1271 new_offset2 = GET_UShort() + base_offset; 1272 1273 /* `Class1Count' and `Class2Count' are the upper limits for class 1274 values, thus we read it now to make additional safety checks. */ 1275 1276 count1 = ppf2->Class1Count = GET_UShort(); 1277 count2 = ppf2->Class2Count = GET_UShort(); 1278 1279 FORGET_Frame(); 1280 1281 cur_offset = FILE_Pos(); 1282 if ( FILE_Seek( new_offset1 ) || 1283 ( error = _HB_OPEN_Load_ClassDefinition( &ppf2->ClassDef1, count1, 1284 stream ) ) != HB_Err_Ok ) 1285 return error; 1286 if ( FILE_Seek( new_offset2 ) || 1287 ( error = _HB_OPEN_Load_ClassDefinition( &ppf2->ClassDef2, count2, 1288 stream ) ) != HB_Err_Ok ) 1289 goto Fail3; 1290 (void)FILE_Seek( cur_offset ); 1291 1292 ppf2->Class1Record = NULL; 1293 1294 if ( ALLOC_ARRAY( ppf2->Class1Record, count1, HB_Class1Record ) ) 1295 goto Fail2; 1296 1297 c1r = ppf2->Class1Record; 1298 1299 for ( m = 0; m < count1; m++ ) 1300 { 1301 c1r[m].Class2Record = NULL; 1302 1303 if ( ALLOC_ARRAY( c1r[m].Class2Record, count2, HB_Class2Record ) ) 1304 goto Fail1; 1305 1306 c2r = c1r[m].Class2Record; 1307 1308 for ( n = 0; n < count2; n++ ) 1309 { 1310 if ( format1 ) 1311 { 1312 error = Load_ValueRecord( &c2r[n].Value1, format1, 1313 base_offset, stream ); 1314 if ( error ) 1315 goto Fail0; 1316 } 1317 if ( format2 ) 1318 { 1319 error = Load_ValueRecord( &c2r[n].Value2, format2, 1320 base_offset, stream ); 1321 if ( error ) 1322 { 1323 if ( format1 ) 1324 Free_ValueRecord( &c2r[n].Value1, format1 ); 1325 goto Fail0; 1326 } 1327 } 1328 } 1329 1330 continue; 1331 1332 Fail0: 1333 for ( k = 0; k < n; k++ ) 1334 { 1335 if ( format1 ) 1336 Free_ValueRecord( &c2r[k].Value1, format1 ); 1337 if ( format2 ) 1338 Free_ValueRecord( &c2r[k].Value2, format2 ); 1339 } 1340 goto Fail1; 1341 } 1342 1343 return HB_Err_Ok; 1344 1345 Fail1: 1346 for ( k = 0; k < m; k++ ) 1347 { 1348 c2r = c1r[k].Class2Record; 1349 1350 for ( n = 0; n < count2; n++ ) 1351 { 1352 if ( format1 ) 1353 Free_ValueRecord( &c2r[n].Value1, format1 ); 1354 if ( format2 ) 1355 Free_ValueRecord( &c2r[n].Value2, format2 ); 1356 } 1357 1358 FREE( c2r ); 1359 } 1360 1361 FREE( c1r ); 1362 Fail2: 1363 1364 _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef2 ); 1365 1366 Fail3: 1367 _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef1 ); 1368 return error; 1369 } 1370 1371 1372 static void Free_PairPos2( HB_PairPosFormat2* ppf2, 1373 HB_UShort format1, 1374 HB_UShort format2) 1375 { 1376 HB_UShort m, n, count1, count2; 1377 1378 HB_Class1Record* c1r; 1379 HB_Class2Record* c2r; 1380 1381 1382 if ( ppf2->Class1Record ) 1383 { 1384 c1r = ppf2->Class1Record; 1385 count1 = ppf2->Class1Count; 1386 count2 = ppf2->Class2Count; 1387 1388 for ( m = 0; m < count1; m++ ) 1389 { 1390 c2r = c1r[m].Class2Record; 1391 1392 for ( n = 0; n < count2; n++ ) 1393 { 1394 if ( format1 ) 1395 Free_ValueRecord( &c2r[n].Value1, format1 ); 1396 if ( format2 ) 1397 Free_ValueRecord( &c2r[n].Value2, format2 ); 1398 } 1399 1400 FREE( c2r ); 1401 } 1402 1403 FREE( c1r ); 1404 1405 _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef2 ); 1406 _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef1 ); 1407 } 1408 } 1409 1410 1411 static HB_Error Load_PairPos( HB_GPOS_SubTable* st, 1412 HB_Stream stream ) 1413 { 1414 HB_Error error; 1415 HB_PairPos* pp = &st->pair; 1416 1417 HB_UShort format1, format2; 1418 HB_UInt cur_offset, new_offset, base_offset; 1419 1420 1421 base_offset = FILE_Pos(); 1422 1423 if ( ACCESS_Frame( 8L ) ) 1424 return error; 1425 1426 pp->PosFormat = GET_UShort(); 1427 new_offset = GET_UShort() + base_offset; 1428 1429 format1 = pp->ValueFormat1 = GET_UShort(); 1430 format2 = pp->ValueFormat2 = GET_UShort(); 1431 1432 FORGET_Frame(); 1433 1434 cur_offset = FILE_Pos(); 1435 if ( FILE_Seek( new_offset ) || 1436 ( error = _HB_OPEN_Load_Coverage( &pp->Coverage, stream ) ) != HB_Err_Ok ) 1437 return error; 1438 (void)FILE_Seek( cur_offset ); 1439 1440 switch ( pp->PosFormat ) 1441 { 1442 case 1: 1443 error = Load_PairPos1( &pp->ppf.ppf1, format1, format2, stream ); 1444 if ( error ) 1445 goto Fail; 1446 break; 1447 1448 case 2: 1449 error = Load_PairPos2( &pp->ppf.ppf2, format1, format2, stream ); 1450 if ( error ) 1451 goto Fail; 1452 break; 1453 1454 default: 1455 return ERR(HB_Err_Invalid_SubTable_Format); 1456 } 1457 1458 return HB_Err_Ok; 1459 1460 Fail: 1461 _HB_OPEN_Free_Coverage( &pp->Coverage ); 1462 return error; 1463 } 1464 1465 1466 static void Free_PairPos( HB_GPOS_SubTable* st ) 1467 { 1468 HB_UShort format1, format2; 1469 HB_PairPos* pp = &st->pair; 1470 1471 1472 format1 = pp->ValueFormat1; 1473 format2 = pp->ValueFormat2; 1474 1475 switch ( pp->PosFormat ) 1476 { 1477 case 1: 1478 Free_PairPos1( &pp->ppf.ppf1, format1, format2 ); 1479 break; 1480 1481 case 2: 1482 Free_PairPos2( &pp->ppf.ppf2, format1, format2 ); 1483 break; 1484 1485 default: 1486 break; 1487 } 1488 1489 _HB_OPEN_Free_Coverage( &pp->Coverage ); 1490 } 1491 1492 1493 static HB_Error Lookup_PairPos1( GPOS_Instance* gpi, 1494 HB_PairPosFormat1* ppf1, 1495 HB_Buffer buffer, 1496 HB_UInt first_pos, 1497 HB_UShort index, 1498 HB_UShort format1, 1499 HB_UShort format2 ) 1500 { 1501 HB_Error error; 1502 HB_UShort numpvr, glyph2; 1503 1504 HB_PairValueRecord* pvr; 1505 1506 1507 if ( index >= ppf1->PairSetCount ) 1508 return ERR(HB_Err_Invalid_SubTable); 1509 1510 pvr = ppf1->PairSet[index].PairValueRecord; 1511 if ( !pvr ) 1512 return ERR(HB_Err_Invalid_SubTable); 1513 1514 glyph2 = IN_CURGLYPH(); 1515 1516 for ( numpvr = ppf1->PairSet[index].PairValueCount; 1517 numpvr; 1518 numpvr--, pvr++ ) 1519 { 1520 if ( glyph2 == pvr->SecondGlyph ) 1521 { 1522 error = Get_ValueRecord( gpi, &pvr->Value1, format1, 1523 POSITION( first_pos ) ); 1524 if ( error ) 1525 return error; 1526 return Get_ValueRecord( gpi, &pvr->Value2, format2, 1527 POSITION( buffer->in_pos ) ); 1528 } 1529 } 1530 1531 return HB_Err_Not_Covered; 1532 } 1533 1534 1535 static HB_Error Lookup_PairPos2( GPOS_Instance* gpi, 1536 HB_PairPosFormat2* ppf2, 1537 HB_Buffer buffer, 1538 HB_UInt first_pos, 1539 HB_UShort format1, 1540 HB_UShort format2 ) 1541 { 1542 HB_Error error; 1543 HB_UShort cl1 = 0, cl2 = 0; /* shut compiler up */ 1544 1545 HB_Class1Record* c1r; 1546 HB_Class2Record* c2r; 1547 1548 1549 error = _HB_OPEN_Get_Class( &ppf2->ClassDef1, IN_GLYPH( first_pos ), 1550 &cl1, NULL ); 1551 if ( error && error != HB_Err_Not_Covered ) 1552 return error; 1553 error = _HB_OPEN_Get_Class( &ppf2->ClassDef2, IN_CURGLYPH(), 1554 &cl2, NULL ); 1555 if ( error && error != HB_Err_Not_Covered ) 1556 return error; 1557 1558 c1r = &ppf2->Class1Record[cl1]; 1559 if ( !c1r ) 1560 return ERR(HB_Err_Invalid_SubTable); 1561 c2r = &c1r->Class2Record[cl2]; 1562 1563 error = Get_ValueRecord( gpi, &c2r->Value1, format1, POSITION( first_pos ) ); 1564 if ( error ) 1565 return error; 1566 return Get_ValueRecord( gpi, &c2r->Value2, format2, POSITION( buffer->in_pos ) ); 1567 } 1568 1569 1570 static HB_Error Lookup_PairPos( GPOS_Instance* gpi, 1571 HB_GPOS_SubTable* st, 1572 HB_Buffer buffer, 1573 HB_UShort flags, 1574 HB_UShort context_length, 1575 int nesting_level ) 1576 { 1577 HB_Error error; 1578 HB_UShort index, property; 1579 HB_UInt first_pos; 1580 HB_GPOSHeader* gpos = gpi->gpos; 1581 HB_PairPos* pp = &st->pair; 1582 1583 HB_UNUSED(nesting_level); 1584 1585 if ( buffer->in_pos >= buffer->in_length - 1 ) 1586 return HB_Err_Not_Covered; /* Not enough glyphs in stream */ 1587 1588 if ( context_length != 0xFFFF && context_length < 2 ) 1589 return HB_Err_Not_Covered; 1590 1591 if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) ) 1592 return error; 1593 1594 error = _HB_OPEN_Coverage_Index( &pp->Coverage, IN_CURGLYPH(), &index ); 1595 if ( error ) 1596 return error; 1597 1598 /* second glyph */ 1599 1600 first_pos = buffer->in_pos; 1601 (buffer->in_pos)++; 1602 1603 while ( CHECK_Property( gpos->gdef, IN_CURITEM(), 1604 flags, &property ) ) 1605 { 1606 if ( error && error != HB_Err_Not_Covered ) 1607 return error; 1608 1609 if ( buffer->in_pos == buffer->in_length ) 1610 { 1611 buffer->in_pos = first_pos; 1612 return HB_Err_Not_Covered; 1613 } 1614 (buffer->in_pos)++; 1615 1616 } 1617 1618 switch ( pp->PosFormat ) 1619 { 1620 case 1: 1621 error = Lookup_PairPos1( gpi, &pp->ppf.ppf1, buffer, 1622 first_pos, index, 1623 pp->ValueFormat1, pp->ValueFormat2 ); 1624 break; 1625 1626 case 2: 1627 error = Lookup_PairPos2( gpi, &pp->ppf.ppf2, buffer, first_pos, 1628 pp->ValueFormat1, pp->ValueFormat2 ); 1629 break; 1630 1631 default: 1632 return ERR(HB_Err_Invalid_SubTable_Format); 1633 } 1634 1635 /* if we don't have coverage for the second glyph don't skip it for 1636 further lookups but reset in_pos back to the first_glyph and let 1637 the caller in Do_String_Lookup increment in_pos */ 1638 if ( error == HB_Err_Not_Covered ) 1639 buffer->in_pos = first_pos; 1640 1641 /* adjusting the `next' glyph */ 1642 1643 if ( pp->ValueFormat2 ) 1644 (buffer->in_pos)++; 1645 1646 return error; 1647 } 1648 1649 1650 /* LookupType 3 */ 1651 1652 /* CursivePosFormat1 */ 1653 1654 static HB_Error Load_CursivePos( HB_GPOS_SubTable* st, 1655 HB_Stream stream ) 1656 { 1657 HB_Error error; 1658 HB_CursivePos* cp = &st->cursive; 1659 1660 HB_UShort n, m, count; 1661 HB_UInt cur_offset, new_offset, base_offset; 1662 1663 HB_EntryExitRecord* eer; 1664 1665 1666 base_offset = FILE_Pos(); 1667 1668 if ( ACCESS_Frame( 4L ) ) 1669 return error; 1670 1671 cp->PosFormat = GET_UShort(); 1672 new_offset = GET_UShort() + base_offset; 1673 1674 FORGET_Frame(); 1675 1676 cur_offset = FILE_Pos(); 1677 if ( FILE_Seek( new_offset ) || 1678 ( error = _HB_OPEN_Load_Coverage( &cp->Coverage, stream ) ) != HB_Err_Ok ) 1679 return error; 1680 (void)FILE_Seek( cur_offset ); 1681 1682 if ( ACCESS_Frame( 2L ) ) 1683 goto Fail2; 1684 1685 count = cp->EntryExitCount = GET_UShort(); 1686 1687 FORGET_Frame(); 1688 1689 cp->EntryExitRecord = NULL; 1690 1691 if ( ALLOC_ARRAY( cp->EntryExitRecord, count, HB_EntryExitRecord ) ) 1692 goto Fail2; 1693 1694 eer = cp->EntryExitRecord; 1695 1696 for ( n = 0; n < count; n++ ) 1697 { 1698 HB_UInt entry_offset; 1699 1700 if ( ACCESS_Frame( 2L ) ) 1701 return error; 1702 1703 entry_offset = new_offset = GET_UShort(); 1704 1705 FORGET_Frame(); 1706 1707 if ( new_offset ) 1708 { 1709 new_offset += base_offset; 1710 1711 cur_offset = FILE_Pos(); 1712 if ( FILE_Seek( new_offset ) || 1713 ( error = Load_Anchor( &eer[n].EntryAnchor, 1714 stream ) ) != HB_Err_Ok ) 1715 goto Fail1; 1716 (void)FILE_Seek( cur_offset ); 1717 } 1718 else 1719 eer[n].EntryAnchor.PosFormat = 0; 1720 1721 if ( ACCESS_Frame( 2L ) ) 1722 return error; 1723 1724 new_offset = GET_UShort(); 1725 1726 FORGET_Frame(); 1727 1728 if ( new_offset ) 1729 { 1730 new_offset += base_offset; 1731 1732 cur_offset = FILE_Pos(); 1733 if ( FILE_Seek( new_offset ) || 1734 ( error = Load_Anchor( &eer[n].ExitAnchor, 1735 stream ) ) != HB_Err_Ok ) 1736 { 1737 if ( entry_offset ) 1738 Free_Anchor( &eer[n].EntryAnchor ); 1739 goto Fail1; 1740 } 1741 (void)FILE_Seek( cur_offset ); 1742 } 1743 else 1744 eer[n].ExitAnchor.PosFormat = 0; 1745 } 1746 1747 return HB_Err_Ok; 1748 1749 Fail1: 1750 for ( m = 0; m < n; m++ ) 1751 { 1752 Free_Anchor( &eer[m].EntryAnchor ); 1753 Free_Anchor( &eer[m].ExitAnchor ); 1754 } 1755 1756 FREE( eer ); 1757 1758 Fail2: 1759 _HB_OPEN_Free_Coverage( &cp->Coverage ); 1760 return error; 1761 } 1762 1763 1764 static void Free_CursivePos( HB_GPOS_SubTable* st ) 1765 { 1766 HB_UShort n, count; 1767 HB_CursivePos* cp = &st->cursive; 1768 1769 HB_EntryExitRecord* eer; 1770 1771 1772 if ( cp->EntryExitRecord ) 1773 { 1774 count = cp->EntryExitCount; 1775 eer = cp->EntryExitRecord; 1776 1777 for ( n = 0; n < count; n++ ) 1778 { 1779 Free_Anchor( &eer[n].EntryAnchor ); 1780 Free_Anchor( &eer[n].ExitAnchor ); 1781 } 1782 1783 FREE( eer ); 1784 } 1785 1786 _HB_OPEN_Free_Coverage( &cp->Coverage ); 1787 } 1788 1789 1790 static HB_Error Lookup_CursivePos( GPOS_Instance* gpi, 1791 HB_GPOS_SubTable* st, 1792 HB_Buffer buffer, 1793 HB_UShort flags, 1794 HB_UShort context_length, 1795 int nesting_level ) 1796 { 1797 HB_UShort index, property; 1798 HB_Error error; 1799 HB_GPOSHeader* gpos = gpi->gpos; 1800 HB_CursivePos* cp = &st->cursive; 1801 1802 HB_EntryExitRecord* eer; 1803 HB_Fixed entry_x, entry_y; 1804 HB_Fixed exit_x, exit_y; 1805 1806 HB_UNUSED(nesting_level); 1807 1808 if ( context_length != 0xFFFF && context_length < 1 ) 1809 { 1810 gpi->last = 0xFFFF; 1811 return HB_Err_Not_Covered; 1812 } 1813 1814 /* Glyphs not having the right GDEF properties will be ignored, i.e., 1815 gpi->last won't be reset (contrary to user defined properties). */ 1816 1817 if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) ) 1818 return error; 1819 1820 /* We don't handle mark glyphs here. According to Andrei, this isn't 1821 possible, but who knows... */ 1822 1823 if ( property == HB_GDEF_MARK ) 1824 { 1825 gpi->last = 0xFFFF; 1826 return HB_Err_Not_Covered; 1827 } 1828 1829 error = _HB_OPEN_Coverage_Index( &cp->Coverage, IN_CURGLYPH(), &index ); 1830 if ( error ) 1831 { 1832 gpi->last = 0xFFFF; 1833 return error; 1834 } 1835 1836 if ( index >= cp->EntryExitCount ) 1837 return ERR(HB_Err_Invalid_SubTable); 1838 1839 eer = &cp->EntryExitRecord[index]; 1840 1841 /* Now comes the messiest part of the whole OpenType 1842 specification. At first glance, cursive connections seem easy 1843 to understand, but there are pitfalls! The reason is that 1844 the specs don't mention how to compute the advance values 1845 resp. glyph offsets. I was told it would be an omission, to 1846 be fixed in the next OpenType version... Again many thanks to 1847 Andrei Burago <andreib (at) microsoft.com> for clarifications. 1848 1849 Consider the following example: 1850 1851 | xadv1 | 1852 +---------+ 1853 | | 1854 +-----+--+ 1 | 1855 | | .| | 1856 | 0+--+------+ 1857 | 2 | 1858 | | 1859 0+--------+ 1860 | xadv2 | 1861 1862 glyph1: advance width = 12 1863 anchor point = (3,1) 1864 1865 glyph2: advance width = 11 1866 anchor point = (9,4) 1867 1868 LSB is 1 for both glyphs (so the boxes drawn above are glyph 1869 bboxes). Writing direction is R2L; `0' denotes the glyph's 1870 coordinate origin. 1871 1872 Now the surprising part: The advance width of the *left* glyph 1873 (resp. of the *bottom* glyph) will be modified, no matter 1874 whether the writing direction is L2R or R2L (resp. T2B or 1875 B2T)! This assymetry is caused by the fact that the glyph's 1876 coordinate origin is always the lower left corner for all 1877 writing directions. 1878 1879 Continuing the above example, we can compute the new 1880 (horizontal) advance width of glyph2 as 1881 1882 9 - 3 = 6 , 1883 1884 and the new vertical offset of glyph2 as 1885 1886 1 - 4 = -3 . 1887 1888 1889 Vertical writing direction is far more complicated: 1890 1891 a) Assuming that we recompute the advance height of the lower glyph: 1892 1893 -- 1894 +---------+ 1895 -- | | 1896 +-----+--+ 1 | yadv1 1897 | | .| | 1898 yadv2 | 0+--+------+ -- BSB1 -- 1899 | 2 | -- -- y_offset 1900 | | 1901 BSB2 -- 0+--------+ -- 1902 -- -- 1903 1904 glyph1: advance height = 6 1905 anchor point = (3,1) 1906 1907 glyph2: advance height = 7 1908 anchor point = (9,4) 1909 1910 TSB is 1 for both glyphs; writing direction is T2B. 1911 1912 1913 BSB1 = yadv1 - (TSB1 + ymax1) 1914 BSB2 = yadv2 - (TSB2 + ymax2) 1915 y_offset = y2 - y1 1916 1917 vertical advance width of glyph2 1918 = y_offset + BSB2 - BSB1 1919 = (y2 - y1) + (yadv2 - (TSB2 + ymax2)) - (yadv1 - (TSB1 + ymax1)) 1920 = y2 - y1 + yadv2 - TSB2 - ymax2 - (yadv1 - TSB1 - ymax1) 1921 = y2 - y1 + yadv2 - TSB2 - ymax2 - yadv1 + TSB1 + ymax1 1922 1923 1924 b) Assuming that we recompute the advance height of the upper glyph: 1925 1926 -- -- 1927 +---------+ -- TSB1 1928 -- -- | | 1929 TSB2 -- +-----+--+ 1 | yadv1 ymax1 1930 | | .| | 1931 yadv2 | 0+--+------+ -- -- 1932 ymax2 | 2 | -- y_offset 1933 | | 1934 -- 0+--------+ -- 1935 -- 1936 1937 glyph1: advance height = 6 1938 anchor point = (3,1) 1939 1940 glyph2: advance height = 7 1941 anchor point = (9,4) 1942 1943 TSB is 1 for both glyphs; writing direction is T2B. 1944 1945 y_offset = y2 - y1 1946 1947 vertical advance width of glyph2 1948 = TSB1 + ymax1 + y_offset - (TSB2 + ymax2) 1949 = TSB1 + ymax1 + y2 - y1 - TSB2 - ymax2 1950 1951 1952 Comparing a) with b) shows that b) is easier to compute. I'll wait 1953 for a reply from Andrei to see what should really be implemented... 1954 1955 Since horizontal advance widths or vertical advance heights 1956 can be used alone but not together, no ambiguity occurs. */ 1957 1958 if ( gpi->last == 0xFFFF ) 1959 goto end; 1960 1961 /* Get_Anchor() returns HB_Err_Not_Covered if there is no anchor 1962 table. */ 1963 1964 error = Get_Anchor( gpi, &eer->EntryAnchor, IN_CURGLYPH(), 1965 &entry_x, &entry_y ); 1966 if ( error == HB_Err_Not_Covered ) 1967 goto end; 1968 if ( error ) 1969 return error; 1970 1971 if ( gpi->r2l ) 1972 { 1973 POSITION( buffer->in_pos )->x_advance = entry_x - gpi->anchor_x; 1974 POSITION( buffer->in_pos )->new_advance = TRUE; 1975 } 1976 else 1977 { 1978 POSITION( gpi->last )->x_advance = gpi->anchor_x - entry_x; 1979 POSITION( gpi->last )->new_advance = TRUE; 1980 } 1981 1982 if ( flags & HB_LOOKUP_FLAG_RIGHT_TO_LEFT ) 1983 { 1984 POSITION( gpi->last )->cursive_chain = gpi->last - buffer->in_pos; 1985 POSITION( gpi->last )->y_pos = entry_y - gpi->anchor_y; 1986 } 1987 else 1988 { 1989 POSITION( buffer->in_pos )->cursive_chain = buffer->in_pos - gpi->last; 1990 POSITION( buffer->in_pos )->y_pos = gpi->anchor_y - entry_y; 1991 } 1992 1993 end: 1994 error = Get_Anchor( gpi, &eer->ExitAnchor, IN_CURGLYPH(), 1995 &exit_x, &exit_y ); 1996 if ( error == HB_Err_Not_Covered ) 1997 gpi->last = 0xFFFF; 1998 else 1999 { 2000 gpi->last = buffer->in_pos; 2001 gpi->anchor_x = exit_x; 2002 gpi->anchor_y = exit_y; 2003 } 2004 if ( error ) 2005 return error; 2006 2007 (buffer->in_pos)++; 2008 2009 return HB_Err_Ok; 2010 } 2011 2012 2013 /* LookupType 4 */ 2014 2015 /* BaseArray */ 2016 2017 static HB_Error Load_BaseArray( HB_BaseArray* ba, 2018 HB_UShort num_classes, 2019 HB_Stream stream ) 2020 { 2021 HB_Error error; 2022 2023 HB_UShort m, n, count; 2024 HB_UInt cur_offset, new_offset, base_offset; 2025 2026 HB_BaseRecord *br; 2027 HB_Anchor *ban, *bans; 2028 2029 2030 base_offset = FILE_Pos(); 2031 2032 if ( ACCESS_Frame( 2L ) ) 2033 return error; 2034 2035 count = ba->BaseCount = GET_UShort(); 2036 2037 FORGET_Frame(); 2038 2039 ba->BaseRecord = NULL; 2040 2041 if ( ALLOC_ARRAY( ba->BaseRecord, count, HB_BaseRecord ) ) 2042 return error; 2043 2044 br = ba->BaseRecord; 2045 2046 bans = NULL; 2047 2048 if ( ALLOC_ARRAY( bans, count * num_classes, HB_Anchor ) ) 2049 goto Fail; 2050 2051 for ( m = 0; m < count; m++ ) 2052 { 2053 br[m].BaseAnchor = NULL; 2054 2055 ban = br[m].BaseAnchor = bans + m * num_classes; 2056 2057 for ( n = 0; n < num_classes; n++ ) 2058 { 2059 if ( ACCESS_Frame( 2L ) ) 2060 goto Fail; 2061 2062 new_offset = GET_UShort() + base_offset; 2063 2064 FORGET_Frame(); 2065 2066 if (new_offset == base_offset) { 2067 /* XXX 2068 * Doulos SIL Regular is buggy and has zero offsets here. 2069 * Skip it 2070 */ 2071 ban[n].PosFormat = 0; 2072 continue; 2073 } 2074 2075 cur_offset = FILE_Pos(); 2076 if ( FILE_Seek( new_offset ) || 2077 ( error = Load_Anchor( &ban[n], stream ) ) != HB_Err_Ok ) 2078 goto Fail; 2079 (void)FILE_Seek( cur_offset ); 2080 } 2081 } 2082 2083 return HB_Err_Ok; 2084 2085 Fail: 2086 FREE( bans ); 2087 FREE( br ); 2088 return error; 2089 } 2090 2091 2092 static void Free_BaseArray( HB_BaseArray* ba, 2093 HB_UShort num_classes ) 2094 { 2095 HB_BaseRecord *br; 2096 HB_Anchor *bans; 2097 2098 if ( ba->BaseRecord ) 2099 { 2100 br = ba->BaseRecord; 2101 2102 if ( ba->BaseCount ) 2103 { 2104 HB_UShort i, count; 2105 count = num_classes * ba->BaseCount; 2106 bans = br[0].BaseAnchor; 2107 for (i = 0; i < count; i++) 2108 Free_Anchor (&bans[i]); 2109 FREE( bans ); 2110 } 2111 2112 FREE( br ); 2113 } 2114 } 2115 2116 2117 /* MarkBasePosFormat1 */ 2118 2119 static HB_Error Load_MarkBasePos( HB_GPOS_SubTable* st, 2120 HB_Stream stream ) 2121 { 2122 HB_Error error; 2123 HB_MarkBasePos* mbp = &st->markbase; 2124 2125 HB_UInt cur_offset, new_offset, base_offset; 2126 2127 2128 base_offset = FILE_Pos(); 2129 2130 if ( ACCESS_Frame( 4L ) ) 2131 return error; 2132 2133 mbp->PosFormat = GET_UShort(); 2134 new_offset = GET_UShort() + base_offset; 2135 2136 FORGET_Frame(); 2137 2138 if (mbp->PosFormat != 1) 2139 return ERR(HB_Err_Invalid_SubTable_Format); 2140 2141 cur_offset = FILE_Pos(); 2142 if ( FILE_Seek( new_offset ) || 2143 ( error = _HB_OPEN_Load_Coverage( &mbp->MarkCoverage, stream ) ) != HB_Err_Ok ) 2144 return error; 2145 (void)FILE_Seek( cur_offset ); 2146 2147 if ( ACCESS_Frame( 2L ) ) 2148 goto Fail3; 2149 2150 new_offset = GET_UShort() + base_offset; 2151 2152 FORGET_Frame(); 2153 2154 cur_offset = FILE_Pos(); 2155 if ( FILE_Seek( new_offset ) || 2156 ( error = _HB_OPEN_Load_Coverage( &mbp->BaseCoverage, stream ) ) != HB_Err_Ok ) 2157 goto Fail3; 2158 (void)FILE_Seek( cur_offset ); 2159 2160 if ( ACCESS_Frame( 4L ) ) 2161 goto Fail2; 2162 2163 mbp->ClassCount = GET_UShort(); 2164 new_offset = GET_UShort() + base_offset; 2165 2166 FORGET_Frame(); 2167 2168 cur_offset = FILE_Pos(); 2169 if ( FILE_Seek( new_offset ) || 2170 ( error = Load_MarkArray( &mbp->MarkArray, stream ) ) != HB_Err_Ok ) 2171 goto Fail2; 2172 (void)FILE_Seek( cur_offset ); 2173 2174 if ( ACCESS_Frame( 2L ) ) 2175 goto Fail1; 2176 2177 new_offset = GET_UShort() + base_offset; 2178 2179 FORGET_Frame(); 2180 2181 cur_offset = FILE_Pos(); 2182 if ( FILE_Seek( new_offset ) || 2183 ( error = Load_BaseArray( &mbp->BaseArray, mbp->ClassCount, 2184 stream ) ) != HB_Err_Ok ) 2185 goto Fail1; 2186 2187 return HB_Err_Ok; 2188 2189 Fail1: 2190 Free_MarkArray( &mbp->MarkArray ); 2191 2192 Fail2: 2193 _HB_OPEN_Free_Coverage( &mbp->BaseCoverage ); 2194 2195 Fail3: 2196 _HB_OPEN_Free_Coverage( &mbp->MarkCoverage ); 2197 return error; 2198 } 2199 2200 2201 static void Free_MarkBasePos( HB_GPOS_SubTable* st ) 2202 { 2203 HB_MarkBasePos* mbp = &st->markbase; 2204 2205 Free_BaseArray( &mbp->BaseArray, mbp->ClassCount ); 2206 Free_MarkArray( &mbp->MarkArray ); 2207 _HB_OPEN_Free_Coverage( &mbp->BaseCoverage ); 2208 _HB_OPEN_Free_Coverage( &mbp->MarkCoverage ); 2209 } 2210 2211 2212 static HB_Error Lookup_MarkBasePos( GPOS_Instance* gpi, 2213 HB_GPOS_SubTable* st, 2214 HB_Buffer buffer, 2215 HB_UShort flags, 2216 HB_UShort context_length, 2217 int nesting_level ) 2218 { 2219 HB_UShort i, j, mark_index, base_index, property, class; 2220 HB_Fixed x_mark_value, y_mark_value, x_base_value, y_base_value; 2221 HB_Error error; 2222 HB_GPOSHeader* gpos = gpi->gpos; 2223 HB_MarkBasePos* mbp = &st->markbase; 2224 2225 HB_MarkArray* ma; 2226 HB_BaseArray* ba; 2227 HB_BaseRecord* br; 2228 HB_Anchor* mark_anchor; 2229 HB_Anchor* base_anchor; 2230 2231 HB_Position o; 2232 2233 HB_UNUSED(nesting_level); 2234 2235 if ( context_length != 0xFFFF && context_length < 1 ) 2236 return HB_Err_Not_Covered; 2237 2238 if ( flags & HB_LOOKUP_FLAG_IGNORE_BASE_GLYPHS ) 2239 return HB_Err_Not_Covered; 2240 2241 if ( CHECK_Property( gpos->gdef, IN_CURITEM(), 2242 flags, &property ) ) 2243 return error; 2244 2245 error = _HB_OPEN_Coverage_Index( &mbp->MarkCoverage, IN_CURGLYPH(), 2246 &mark_index ); 2247 if ( error ) 2248 return error; 2249 2250 /* now we search backwards for a non-mark glyph */ 2251 2252 i = 1; 2253 j = buffer->in_pos - 1; 2254 2255 while ( i <= buffer->in_pos ) 2256 { 2257 error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ), 2258 &property ); 2259 if ( error ) 2260 return error; 2261 2262 if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) ) 2263 break; 2264 2265 i++; 2266 j--; 2267 } 2268 2269 /* The following assertion is too strong -- at least for mangal.ttf. */ 2270 #if 0 2271 if ( property != HB_GDEF_BASE_GLYPH ) 2272 return HB_Err_Not_Covered; 2273 #endif 2274 2275 if ( i > buffer->in_pos ) 2276 return HB_Err_Not_Covered; 2277 2278 error = _HB_OPEN_Coverage_Index( &mbp->BaseCoverage, IN_GLYPH( j ), 2279 &base_index ); 2280 if ( error ) 2281 return error; 2282 2283 ma = &mbp->MarkArray; 2284 2285 if ( mark_index >= ma->MarkCount ) 2286 return ERR(HB_Err_Invalid_SubTable); 2287 2288 class = ma->MarkRecord[mark_index].Class; 2289 mark_anchor = &ma->MarkRecord[mark_index].MarkAnchor; 2290 2291 if ( class >= mbp->ClassCount ) 2292 return ERR(HB_Err_Invalid_SubTable); 2293 2294 ba = &mbp->BaseArray; 2295 2296 if ( base_index >= ba->BaseCount ) 2297 return ERR(HB_Err_Invalid_SubTable); 2298 2299 br = &ba->BaseRecord[base_index]; 2300 base_anchor = &br->BaseAnchor[class]; 2301 2302 error = Get_Anchor( gpi, mark_anchor, IN_CURGLYPH(), 2303 &x_mark_value, &y_mark_value ); 2304 if ( error ) 2305 return error; 2306 2307 error = Get_Anchor( gpi, base_anchor, IN_GLYPH( j ), 2308 &x_base_value, &y_base_value ); 2309 if ( error ) 2310 return error; 2311 2312 /* anchor points are not cumulative */ 2313 2314 o = POSITION( buffer->in_pos ); 2315 2316 o->x_pos = x_base_value - x_mark_value; 2317 o->y_pos = y_base_value - y_mark_value; 2318 o->x_advance = 0; 2319 o->y_advance = 0; 2320 o->back = i; 2321 2322 (buffer->in_pos)++; 2323 2324 return HB_Err_Ok; 2325 } 2326 2327 2328 /* LookupType 5 */ 2329 2330 /* LigatureAttach */ 2331 2332 static HB_Error Load_LigatureAttach( HB_LigatureAttach* lat, 2333 HB_UShort num_classes, 2334 HB_Stream stream ) 2335 { 2336 HB_Error error; 2337 2338 HB_UShort m, n, k, count; 2339 HB_UInt cur_offset, new_offset, base_offset; 2340 2341 HB_ComponentRecord* cr; 2342 HB_Anchor* lan; 2343 2344 2345 base_offset = FILE_Pos(); 2346 2347 if ( ACCESS_Frame( 2L ) ) 2348 return error; 2349 2350 count = lat->ComponentCount = GET_UShort(); 2351 2352 FORGET_Frame(); 2353 2354 lat->ComponentRecord = NULL; 2355 2356 if ( ALLOC_ARRAY( lat->ComponentRecord, count, HB_ComponentRecord ) ) 2357 return error; 2358 2359 cr = lat->ComponentRecord; 2360 2361 for ( m = 0; m < count; m++ ) 2362 { 2363 cr[m].LigatureAnchor = NULL; 2364 2365 if ( ALLOC_ARRAY( cr[m].LigatureAnchor, num_classes, HB_Anchor ) ) 2366 goto Fail; 2367 2368 lan = cr[m].LigatureAnchor; 2369 2370 for ( n = 0; n < num_classes; n++ ) 2371 { 2372 if ( ACCESS_Frame( 2L ) ) 2373 goto Fail0; 2374 2375 new_offset = GET_UShort(); 2376 2377 FORGET_Frame(); 2378 2379 if ( new_offset ) 2380 { 2381 new_offset += base_offset; 2382 2383 cur_offset = FILE_Pos(); 2384 if ( FILE_Seek( new_offset ) || 2385 ( error = Load_Anchor( &lan[n], stream ) ) != HB_Err_Ok ) 2386 goto Fail0; 2387 (void)FILE_Seek( cur_offset ); 2388 } 2389 else 2390 lan[n].PosFormat = 0; 2391 } 2392 2393 continue; 2394 Fail0: 2395 for ( k = 0; k < n; k++ ) 2396 Free_Anchor( &lan[k] ); 2397 goto Fail; 2398 } 2399 2400 return HB_Err_Ok; 2401 2402 Fail: 2403 for ( k = 0; k < m; k++ ) 2404 { 2405 lan = cr[k].LigatureAnchor; 2406 2407 for ( n = 0; n < num_classes; n++ ) 2408 Free_Anchor( &lan[n] ); 2409 2410 FREE( lan ); 2411 } 2412 2413 FREE( cr ); 2414 return error; 2415 } 2416 2417 2418 static void Free_LigatureAttach( HB_LigatureAttach* lat, 2419 HB_UShort num_classes ) 2420 { 2421 HB_UShort m, n, count; 2422 2423 HB_ComponentRecord* cr; 2424 HB_Anchor* lan; 2425 2426 2427 if ( lat->ComponentRecord ) 2428 { 2429 count = lat->ComponentCount; 2430 cr = lat->ComponentRecord; 2431 2432 for ( m = 0; m < count; m++ ) 2433 { 2434 lan = cr[m].LigatureAnchor; 2435 2436 for ( n = 0; n < num_classes; n++ ) 2437 Free_Anchor( &lan[n] ); 2438 2439 FREE( lan ); 2440 } 2441 2442 FREE( cr ); 2443 } 2444 } 2445 2446 2447 /* LigatureArray */ 2448 2449 static HB_Error Load_LigatureArray( HB_LigatureArray* la, 2450 HB_UShort num_classes, 2451 HB_Stream stream ) 2452 { 2453 HB_Error error; 2454 2455 HB_UShort n, m, count; 2456 HB_UInt cur_offset, new_offset, base_offset; 2457 2458 HB_LigatureAttach* lat; 2459 2460 2461 base_offset = FILE_Pos(); 2462 2463 if ( ACCESS_Frame( 2L ) ) 2464 return error; 2465 2466 count = la->LigatureCount = GET_UShort(); 2467 2468 FORGET_Frame(); 2469 2470 la->LigatureAttach = NULL; 2471 2472 if ( ALLOC_ARRAY( la->LigatureAttach, count, HB_LigatureAttach ) ) 2473 return error; 2474 2475 lat = la->LigatureAttach; 2476 2477 for ( n = 0; n < count; n++ ) 2478 { 2479 if ( ACCESS_Frame( 2L ) ) 2480 goto Fail; 2481 2482 new_offset = GET_UShort() + base_offset; 2483 2484 FORGET_Frame(); 2485 2486 cur_offset = FILE_Pos(); 2487 if ( FILE_Seek( new_offset ) || 2488 ( error = Load_LigatureAttach( &lat[n], num_classes, 2489 stream ) ) != HB_Err_Ok ) 2490 goto Fail; 2491 (void)FILE_Seek( cur_offset ); 2492 } 2493 2494 return HB_Err_Ok; 2495 2496 Fail: 2497 for ( m = 0; m < n; m++ ) 2498 Free_LigatureAttach( &lat[m], num_classes ); 2499 2500 FREE( lat ); 2501 return error; 2502 } 2503 2504 2505 static void Free_LigatureArray( HB_LigatureArray* la, 2506 HB_UShort num_classes ) 2507 { 2508 HB_UShort n, count; 2509 2510 HB_LigatureAttach* lat; 2511 2512 2513 if ( la->LigatureAttach ) 2514 { 2515 count = la->LigatureCount; 2516 lat = la->LigatureAttach; 2517 2518 for ( n = 0; n < count; n++ ) 2519 Free_LigatureAttach( &lat[n], num_classes ); 2520 2521 FREE( lat ); 2522 } 2523 } 2524 2525 2526 /* MarkLigPosFormat1 */ 2527 2528 static HB_Error Load_MarkLigPos( HB_GPOS_SubTable* st, 2529 HB_Stream stream ) 2530 { 2531 HB_Error error; 2532 HB_MarkLigPos* mlp = &st->marklig; 2533 2534 HB_UInt cur_offset, new_offset, base_offset; 2535 2536 2537 base_offset = FILE_Pos(); 2538 2539 if ( ACCESS_Frame( 4L ) ) 2540 return error; 2541 2542 mlp->PosFormat = GET_UShort(); 2543 new_offset = GET_UShort() + base_offset; 2544 2545 FORGET_Frame(); 2546 2547 cur_offset = FILE_Pos(); 2548 if ( FILE_Seek( new_offset ) || 2549 ( error = _HB_OPEN_Load_Coverage( &mlp->MarkCoverage, stream ) ) != HB_Err_Ok ) 2550 return error; 2551 (void)FILE_Seek( cur_offset ); 2552 2553 if ( ACCESS_Frame( 2L ) ) 2554 goto Fail3; 2555 2556 new_offset = GET_UShort() + base_offset; 2557 2558 FORGET_Frame(); 2559 2560 cur_offset = FILE_Pos(); 2561 if ( FILE_Seek( new_offset ) || 2562 ( error = _HB_OPEN_Load_Coverage( &mlp->LigatureCoverage, 2563 stream ) ) != HB_Err_Ok ) 2564 goto Fail3; 2565 (void)FILE_Seek( cur_offset ); 2566 2567 if ( ACCESS_Frame( 4L ) ) 2568 goto Fail2; 2569 2570 mlp->ClassCount = GET_UShort(); 2571 new_offset = GET_UShort() + base_offset; 2572 2573 FORGET_Frame(); 2574 2575 cur_offset = FILE_Pos(); 2576 if ( FILE_Seek( new_offset ) || 2577 ( error = Load_MarkArray( &mlp->MarkArray, stream ) ) != HB_Err_Ok ) 2578 goto Fail2; 2579 (void)FILE_Seek( cur_offset ); 2580 2581 if ( ACCESS_Frame( 2L ) ) 2582 goto Fail1; 2583 2584 new_offset = GET_UShort() + base_offset; 2585 2586 FORGET_Frame(); 2587 2588 cur_offset = FILE_Pos(); 2589 if ( FILE_Seek( new_offset ) || 2590 ( error = Load_LigatureArray( &mlp->LigatureArray, mlp->ClassCount, 2591 stream ) ) != HB_Err_Ok ) 2592 goto Fail1; 2593 2594 return HB_Err_Ok; 2595 2596 Fail1: 2597 Free_MarkArray( &mlp->MarkArray ); 2598 2599 Fail2: 2600 _HB_OPEN_Free_Coverage( &mlp->LigatureCoverage ); 2601 2602 Fail3: 2603 _HB_OPEN_Free_Coverage( &mlp->MarkCoverage ); 2604 return error; 2605 } 2606 2607 2608 static void Free_MarkLigPos( HB_GPOS_SubTable* st) 2609 { 2610 HB_MarkLigPos* mlp = &st->marklig; 2611 2612 Free_LigatureArray( &mlp->LigatureArray, mlp->ClassCount ); 2613 Free_MarkArray( &mlp->MarkArray ); 2614 _HB_OPEN_Free_Coverage( &mlp->LigatureCoverage ); 2615 _HB_OPEN_Free_Coverage( &mlp->MarkCoverage ); 2616 } 2617 2618 2619 static HB_Error Lookup_MarkLigPos( GPOS_Instance* gpi, 2620 HB_GPOS_SubTable* st, 2621 HB_Buffer buffer, 2622 HB_UShort flags, 2623 HB_UShort context_length, 2624 int nesting_level ) 2625 { 2626 HB_UShort i, j, mark_index, lig_index, property, class; 2627 HB_UShort mark_glyph; 2628 HB_Fixed x_mark_value, y_mark_value, x_lig_value, y_lig_value; 2629 HB_Error error; 2630 HB_GPOSHeader* gpos = gpi->gpos; 2631 HB_MarkLigPos* mlp = &st->marklig; 2632 2633 HB_MarkArray* ma; 2634 HB_LigatureArray* la; 2635 HB_LigatureAttach* lat; 2636 HB_ComponentRecord* cr; 2637 HB_UShort comp_index; 2638 HB_Anchor* mark_anchor; 2639 HB_Anchor* lig_anchor; 2640 2641 HB_Position o; 2642 2643 HB_UNUSED(nesting_level); 2644 2645 if ( context_length != 0xFFFF && context_length < 1 ) 2646 return HB_Err_Not_Covered; 2647 2648 if ( flags & HB_LOOKUP_FLAG_IGNORE_LIGATURES ) 2649 return HB_Err_Not_Covered; 2650 2651 mark_glyph = IN_CURGLYPH(); 2652 2653 if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) ) 2654 return error; 2655 2656 error = _HB_OPEN_Coverage_Index( &mlp->MarkCoverage, mark_glyph, &mark_index ); 2657 if ( error ) 2658 return error; 2659 2660 /* now we search backwards for a non-mark glyph */ 2661 2662 i = 1; 2663 j = buffer->in_pos - 1; 2664 2665 while ( i <= buffer->in_pos ) 2666 { 2667 error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ), 2668 &property ); 2669 if ( error ) 2670 return error; 2671 2672 if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) ) 2673 break; 2674 2675 i++; 2676 j--; 2677 } 2678 2679 /* Similar to Lookup_MarkBasePos(), I suspect that this assertion is 2680 too strong, thus it is commented out. */ 2681 #if 0 2682 if ( property != HB_GDEF_LIGATURE ) 2683 return HB_Err_Not_Covered; 2684 #endif 2685 2686 if ( i > buffer->in_pos ) 2687 return HB_Err_Not_Covered; 2688 2689 error = _HB_OPEN_Coverage_Index( &mlp->LigatureCoverage, IN_GLYPH( j ), 2690 &lig_index ); 2691 if ( error ) 2692 return error; 2693 2694 ma = &mlp->MarkArray; 2695 2696 if ( mark_index >= ma->MarkCount ) 2697 return ERR(HB_Err_Invalid_SubTable); 2698 2699 class = ma->MarkRecord[mark_index].Class; 2700 mark_anchor = &ma->MarkRecord[mark_index].MarkAnchor; 2701 2702 if ( class >= mlp->ClassCount ) 2703 return ERR(HB_Err_Invalid_SubTable); 2704 2705 la = &mlp->LigatureArray; 2706 2707 if ( lig_index >= la->LigatureCount ) 2708 return ERR(HB_Err_Invalid_SubTable); 2709 2710 lat = &la->LigatureAttach[lig_index]; 2711 2712 /* We must now check whether the ligature ID of the current mark glyph 2713 is identical to the ligature ID of the found ligature. If yes, we 2714 can directly use the component index. If not, we attach the mark 2715 glyph to the last component of the ligature. */ 2716 2717 if ( IN_LIGID( j ) == IN_LIGID( buffer->in_pos) ) 2718 { 2719 comp_index = IN_COMPONENT( buffer->in_pos ); 2720 if ( comp_index >= lat->ComponentCount ) 2721 return HB_Err_Not_Covered; 2722 } 2723 else 2724 comp_index = lat->ComponentCount - 1; 2725 2726 cr = &lat->ComponentRecord[comp_index]; 2727 lig_anchor = &cr->LigatureAnchor[class]; 2728 2729 error = Get_Anchor( gpi, mark_anchor, IN_CURGLYPH(), 2730 &x_mark_value, &y_mark_value ); 2731 if ( error ) 2732 return error; 2733 error = Get_Anchor( gpi, lig_anchor, IN_GLYPH( j ), 2734 &x_lig_value, &y_lig_value ); 2735 if ( error ) 2736 return error; 2737 2738 /* anchor points are not cumulative */ 2739 2740 o = POSITION( buffer->in_pos ); 2741 2742 o->x_pos = x_lig_value - x_mark_value; 2743 o->y_pos = y_lig_value - y_mark_value; 2744 o->x_advance = 0; 2745 o->y_advance = 0; 2746 o->back = i; 2747 2748 (buffer->in_pos)++; 2749 2750 return HB_Err_Ok; 2751 } 2752 2753 2754 /* LookupType 6 */ 2755 2756 /* Mark2Array */ 2757 2758 static HB_Error Load_Mark2Array( HB_Mark2Array* m2a, 2759 HB_UShort num_classes, 2760 HB_Stream stream ) 2761 { 2762 HB_Error error; 2763 2764 HB_UShort m, n, count; 2765 HB_UInt cur_offset, new_offset, base_offset; 2766 2767 HB_Mark2Record *m2r; 2768 HB_Anchor *m2an, *m2ans; 2769 2770 2771 base_offset = FILE_Pos(); 2772 2773 if ( ACCESS_Frame( 2L ) ) 2774 return error; 2775 2776 count = m2a->Mark2Count = GET_UShort(); 2777 2778 FORGET_Frame(); 2779 2780 m2a->Mark2Record = NULL; 2781 2782 if ( ALLOC_ARRAY( m2a->Mark2Record, count, HB_Mark2Record ) ) 2783 return error; 2784 2785 m2r = m2a->Mark2Record; 2786 2787 m2ans = NULL; 2788 2789 if ( ALLOC_ARRAY( m2ans, count * num_classes, HB_Anchor ) ) 2790 goto Fail; 2791 2792 for ( m = 0; m < count; m++ ) 2793 { 2794 m2an = m2r[m].Mark2Anchor = m2ans + m * num_classes; 2795 2796 for ( n = 0; n < num_classes; n++ ) 2797 { 2798 if ( ACCESS_Frame( 2L ) ) 2799 goto Fail; 2800 2801 new_offset = GET_UShort() + base_offset; 2802 2803 FORGET_Frame(); 2804 2805 if (new_offset == base_offset) { 2806 /* Anchor table not provided. Skip loading. 2807 * Some versions of FreeSans hit this. */ 2808 m2an[n].PosFormat = 0; 2809 continue; 2810 } 2811 2812 cur_offset = FILE_Pos(); 2813 if ( FILE_Seek( new_offset ) || 2814 ( error = Load_Anchor( &m2an[n], stream ) ) != HB_Err_Ok ) 2815 goto Fail; 2816 (void)FILE_Seek( cur_offset ); 2817 } 2818 } 2819 2820 return HB_Err_Ok; 2821 2822 Fail: 2823 FREE( m2ans ); 2824 FREE( m2r ); 2825 return error; 2826 } 2827 2828 2829 static void Free_Mark2Array( HB_Mark2Array* m2a, 2830 HB_UShort num_classes ) 2831 { 2832 HB_Mark2Record *m2r; 2833 HB_Anchor *m2ans; 2834 2835 HB_UNUSED(num_classes); 2836 2837 if ( m2a->Mark2Record ) 2838 { 2839 m2r = m2a->Mark2Record; 2840 2841 if ( m2a->Mark2Count ) 2842 { 2843 m2ans = m2r[0].Mark2Anchor; 2844 FREE( m2ans ); 2845 } 2846 2847 FREE( m2r ); 2848 } 2849 } 2850 2851 2852 /* MarkMarkPosFormat1 */ 2853 2854 static HB_Error Load_MarkMarkPos( HB_GPOS_SubTable* st, 2855 HB_Stream stream ) 2856 { 2857 HB_Error error; 2858 HB_MarkMarkPos* mmp = &st->markmark; 2859 2860 HB_UInt cur_offset, new_offset, base_offset; 2861 2862 2863 base_offset = FILE_Pos(); 2864 2865 if ( ACCESS_Frame( 4L ) ) 2866 return error; 2867 2868 mmp->PosFormat = GET_UShort(); 2869 new_offset = GET_UShort() + base_offset; 2870 2871 FORGET_Frame(); 2872 2873 cur_offset = FILE_Pos(); 2874 if ( FILE_Seek( new_offset ) || 2875 ( error = _HB_OPEN_Load_Coverage( &mmp->Mark1Coverage, 2876 stream ) ) != HB_Err_Ok ) 2877 return error; 2878 (void)FILE_Seek( cur_offset ); 2879 2880 if ( ACCESS_Frame( 2L ) ) 2881 goto Fail3; 2882 2883 new_offset = GET_UShort() + base_offset; 2884 2885 FORGET_Frame(); 2886 2887 cur_offset = FILE_Pos(); 2888 if ( FILE_Seek( new_offset ) || 2889 ( error = _HB_OPEN_Load_Coverage( &mmp->Mark2Coverage, 2890 stream ) ) != HB_Err_Ok ) 2891 goto Fail3; 2892 (void)FILE_Seek( cur_offset ); 2893 2894 if ( ACCESS_Frame( 4L ) ) 2895 goto Fail2; 2896 2897 mmp->ClassCount = GET_UShort(); 2898 new_offset = GET_UShort() + base_offset; 2899 2900 FORGET_Frame(); 2901 2902 cur_offset = FILE_Pos(); 2903 if ( FILE_Seek( new_offset ) || 2904 ( error = Load_MarkArray( &mmp->Mark1Array, stream ) ) != HB_Err_Ok ) 2905 goto Fail2; 2906 (void)FILE_Seek( cur_offset ); 2907 2908 if ( ACCESS_Frame( 2L ) ) 2909 goto Fail1; 2910 2911 new_offset = GET_UShort() + base_offset; 2912 2913 FORGET_Frame(); 2914 2915 cur_offset = FILE_Pos(); 2916 if ( FILE_Seek( new_offset ) || 2917 ( error = Load_Mark2Array( &mmp->Mark2Array, mmp->ClassCount, 2918 stream ) ) != HB_Err_Ok ) 2919 goto Fail1; 2920 2921 return HB_Err_Ok; 2922 2923 Fail1: 2924 Free_MarkArray( &mmp->Mark1Array ); 2925 2926 Fail2: 2927 _HB_OPEN_Free_Coverage( &mmp->Mark2Coverage ); 2928 2929 Fail3: 2930 _HB_OPEN_Free_Coverage( &mmp->Mark1Coverage ); 2931 return error; 2932 } 2933 2934 2935 static void Free_MarkMarkPos( HB_GPOS_SubTable* st) 2936 { 2937 HB_MarkMarkPos* mmp = &st->markmark; 2938 2939 Free_Mark2Array( &mmp->Mark2Array, mmp->ClassCount ); 2940 Free_MarkArray( &mmp->Mark1Array ); 2941 _HB_OPEN_Free_Coverage( &mmp->Mark2Coverage ); 2942 _HB_OPEN_Free_Coverage( &mmp->Mark1Coverage ); 2943 } 2944 2945 2946 static HB_Error Lookup_MarkMarkPos( GPOS_Instance* gpi, 2947 HB_GPOS_SubTable* st, 2948 HB_Buffer buffer, 2949 HB_UShort flags, 2950 HB_UShort context_length, 2951 int nesting_level ) 2952 { 2953 HB_UShort i, j, mark1_index, mark2_index, property, class; 2954 HB_Fixed x_mark1_value, y_mark1_value, 2955 x_mark2_value, y_mark2_value; 2956 HB_Error error; 2957 HB_GPOSHeader* gpos = gpi->gpos; 2958 HB_MarkMarkPos* mmp = &st->markmark; 2959 2960 HB_MarkArray* ma1; 2961 HB_Mark2Array* ma2; 2962 HB_Mark2Record* m2r; 2963 HB_Anchor* mark1_anchor; 2964 HB_Anchor* mark2_anchor; 2965 2966 HB_Position o; 2967 2968 HB_UNUSED(nesting_level); 2969 2970 if ( context_length != 0xFFFF && context_length < 1 ) 2971 return HB_Err_Not_Covered; 2972 2973 if ( flags & HB_LOOKUP_FLAG_IGNORE_MARKS ) 2974 return HB_Err_Not_Covered; 2975 2976 if ( CHECK_Property( gpos->gdef, IN_CURITEM(), 2977 flags, &property ) ) 2978 return error; 2979 2980 error = _HB_OPEN_Coverage_Index( &mmp->Mark1Coverage, IN_CURGLYPH(), 2981 &mark1_index ); 2982 if ( error ) 2983 return error; 2984 2985 /* now we search backwards for a suitable mark glyph until a non-mark 2986 glyph */ 2987 2988 if ( buffer->in_pos == 0 ) 2989 return HB_Err_Not_Covered; 2990 2991 i = 1; 2992 j = buffer->in_pos - 1; 2993 while ( i <= buffer->in_pos ) 2994 { 2995 error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ), 2996 &property ); 2997 if ( error ) 2998 return error; 2999 3000 if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) ) 3001 return HB_Err_Not_Covered; 3002 3003 if ( flags & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) 3004 { 3005 if ( property == (flags & 0xFF00) ) 3006 break; 3007 } 3008 else 3009 break; 3010 3011 i++; 3012 j--; 3013 } 3014 3015 error = _HB_OPEN_Coverage_Index( &mmp->Mark2Coverage, IN_GLYPH( j ), 3016 &mark2_index ); 3017 if ( error ) 3018 return error; 3019 3020 ma1 = &mmp->Mark1Array; 3021 3022 if ( mark1_index >= ma1->MarkCount ) 3023 return ERR(HB_Err_Invalid_SubTable); 3024 3025 class = ma1->MarkRecord[mark1_index].Class; 3026 mark1_anchor = &ma1->MarkRecord[mark1_index].MarkAnchor; 3027 3028 if ( class >= mmp->ClassCount ) 3029 return ERR(HB_Err_Invalid_SubTable); 3030 3031 ma2 = &mmp->Mark2Array; 3032 3033 if ( mark2_index >= ma2->Mark2Count ) 3034 return ERR(HB_Err_Invalid_SubTable); 3035 3036 m2r = &ma2->Mark2Record[mark2_index]; 3037 mark2_anchor = &m2r->Mark2Anchor[class]; 3038 3039 error = Get_Anchor( gpi, mark1_anchor, IN_CURGLYPH(), 3040 &x_mark1_value, &y_mark1_value ); 3041 if ( error ) 3042 return error; 3043 error = Get_Anchor( gpi, mark2_anchor, IN_GLYPH( j ), 3044 &x_mark2_value, &y_mark2_value ); 3045 if ( error ) 3046 return error; 3047 3048 /* anchor points are not cumulative */ 3049 3050 o = POSITION( buffer->in_pos ); 3051 3052 o->x_pos = x_mark2_value - x_mark1_value; 3053 o->y_pos = y_mark2_value - y_mark1_value; 3054 o->x_advance = 0; 3055 o->y_advance = 0; 3056 o->back = 1; 3057 3058 (buffer->in_pos)++; 3059 3060 return HB_Err_Ok; 3061 } 3062 3063 3064 /* Do the actual positioning for a context positioning (either format 3065 7 or 8). This is only called after we've determined that the stream 3066 matches the subrule. */ 3067 3068 static HB_Error Do_ContextPos( GPOS_Instance* gpi, 3069 HB_UShort GlyphCount, 3070 HB_UShort PosCount, 3071 HB_PosLookupRecord* pos, 3072 HB_Buffer buffer, 3073 int nesting_level ) 3074 { 3075 HB_Error error; 3076 HB_UInt i, old_pos; 3077 3078 3079 i = 0; 3080 3081 while ( i < GlyphCount ) 3082 { 3083 if ( PosCount && i == pos->SequenceIndex ) 3084 { 3085 old_pos = buffer->in_pos; 3086 3087 /* Do a positioning */ 3088 3089 error = GPOS_Do_Glyph_Lookup( gpi, pos->LookupListIndex, buffer, 3090 GlyphCount, nesting_level ); 3091 3092 if ( error ) 3093 return error; 3094 3095 pos++; 3096 PosCount--; 3097 i += buffer->in_pos - old_pos; 3098 } 3099 else 3100 { 3101 i++; 3102 (buffer->in_pos)++; 3103 } 3104 } 3105 3106 return HB_Err_Ok; 3107 } 3108 3109 3110 /* LookupType 7 */ 3111 3112 /* PosRule */ 3113 3114 static HB_Error Load_PosRule( HB_PosRule* pr, 3115 HB_Stream stream ) 3116 { 3117 HB_Error error; 3118 3119 HB_UShort n, count; 3120 HB_UShort* i; 3121 3122 HB_PosLookupRecord* plr; 3123 3124 3125 if ( ACCESS_Frame( 4L ) ) 3126 return error; 3127 3128 pr->GlyphCount = GET_UShort(); 3129 pr->PosCount = GET_UShort(); 3130 3131 FORGET_Frame(); 3132 3133 pr->Input = NULL; 3134 3135 count = pr->GlyphCount - 1; /* only GlyphCount - 1 elements */ 3136 3137 if ( ALLOC_ARRAY( pr->Input, count, HB_UShort ) ) 3138 return error; 3139 3140 i = pr->Input; 3141 3142 if ( ACCESS_Frame( count * 2L ) ) 3143 goto Fail2; 3144 3145 for ( n = 0; n < count; n++ ) 3146 i[n] = GET_UShort(); 3147 3148 FORGET_Frame(); 3149 3150 pr->PosLookupRecord = NULL; 3151 3152 count = pr->PosCount; 3153 3154 if ( ALLOC_ARRAY( pr->PosLookupRecord, count, HB_PosLookupRecord ) ) 3155 goto Fail2; 3156 3157 plr = pr->PosLookupRecord; 3158 3159 if ( ACCESS_Frame( count * 4L ) ) 3160 goto Fail1; 3161 3162 for ( n = 0; n < count; n++ ) 3163 { 3164 plr[n].SequenceIndex = GET_UShort(); 3165 plr[n].LookupListIndex = GET_UShort(); 3166 } 3167 3168 FORGET_Frame(); 3169 3170 return HB_Err_Ok; 3171 3172 Fail1: 3173 FREE( plr ); 3174 3175 Fail2: 3176 FREE( i ); 3177 return error; 3178 } 3179 3180 3181 static void Free_PosRule( HB_PosRule* pr ) 3182 { 3183 FREE( pr->PosLookupRecord ); 3184 FREE( pr->Input ); 3185 } 3186 3187 3188 /* PosRuleSet */ 3189 3190 static HB_Error Load_PosRuleSet( HB_PosRuleSet* prs, 3191 HB_Stream stream ) 3192 { 3193 HB_Error error; 3194 3195 HB_UShort n, m, count; 3196 HB_UInt cur_offset, new_offset, base_offset; 3197 3198 HB_PosRule* pr; 3199 3200 3201 base_offset = FILE_Pos(); 3202 3203 if ( ACCESS_Frame( 2L ) ) 3204 return error; 3205 3206 count = prs->PosRuleCount = GET_UShort(); 3207 3208 FORGET_Frame(); 3209 3210 prs->PosRule = NULL; 3211 3212 if ( ALLOC_ARRAY( prs->PosRule, count, HB_PosRule ) ) 3213 return error; 3214 3215 pr = prs->PosRule; 3216 3217 for ( n = 0; n < count; n++ ) 3218 { 3219 if ( ACCESS_Frame( 2L ) ) 3220 goto Fail; 3221 3222 new_offset = GET_UShort() + base_offset; 3223 3224 FORGET_Frame(); 3225 3226 cur_offset = FILE_Pos(); 3227 if ( FILE_Seek( new_offset ) || 3228 ( error = Load_PosRule( &pr[n], stream ) ) != HB_Err_Ok ) 3229 goto Fail; 3230 (void)FILE_Seek( cur_offset ); 3231 } 3232 3233 return HB_Err_Ok; 3234 3235 Fail: 3236 for ( m = 0; m < n; m++ ) 3237 Free_PosRule( &pr[m] ); 3238 3239 FREE( pr ); 3240 return error; 3241 } 3242 3243 3244 static void Free_PosRuleSet( HB_PosRuleSet* prs ) 3245 { 3246 HB_UShort n, count; 3247 3248 HB_PosRule* pr; 3249 3250 3251 if ( prs->PosRule ) 3252 { 3253 count = prs->PosRuleCount; 3254 pr = prs->PosRule; 3255 3256 for ( n = 0; n < count; n++ ) 3257 Free_PosRule( &pr[n] ); 3258 3259 FREE( pr ); 3260 } 3261 } 3262 3263 3264 /* ContextPosFormat1 */ 3265 3266 static HB_Error Load_ContextPos1( HB_ContextPosFormat1* cpf1, 3267 HB_Stream stream ) 3268 { 3269 HB_Error error; 3270 3271 HB_UShort n, m, count; 3272 HB_UInt cur_offset, new_offset, base_offset; 3273 3274 HB_PosRuleSet* prs; 3275 3276 3277 base_offset = FILE_Pos() - 2L; 3278 3279 if ( ACCESS_Frame( 2L ) ) 3280 return error; 3281 3282 new_offset = GET_UShort() + base_offset; 3283 3284 FORGET_Frame(); 3285 3286 cur_offset = FILE_Pos(); 3287 if ( FILE_Seek( new_offset ) || 3288 ( error = _HB_OPEN_Load_Coverage( &cpf1->Coverage, stream ) ) != HB_Err_Ok ) 3289 return error; 3290 (void)FILE_Seek( cur_offset ); 3291 3292 if ( ACCESS_Frame( 2L ) ) 3293 goto Fail2; 3294 3295 count = cpf1->PosRuleSetCount = GET_UShort(); 3296 3297 FORGET_Frame(); 3298 3299 cpf1->PosRuleSet = NULL; 3300 3301 if ( ALLOC_ARRAY( cpf1->PosRuleSet, count, HB_PosRuleSet ) ) 3302 goto Fail2; 3303 3304 prs = cpf1->PosRuleSet; 3305 3306 for ( n = 0; n < count; n++ ) 3307 { 3308 if ( ACCESS_Frame( 2L ) ) 3309 goto Fail1; 3310 3311 new_offset = GET_UShort() + base_offset; 3312 3313 FORGET_Frame(); 3314 3315 cur_offset = FILE_Pos(); 3316 if ( FILE_Seek( new_offset ) || 3317 ( error = Load_PosRuleSet( &prs[n], stream ) ) != HB_Err_Ok ) 3318 goto Fail1; 3319 (void)FILE_Seek( cur_offset ); 3320 } 3321 3322 return HB_Err_Ok; 3323 3324 Fail1: 3325 for ( m = 0; m < n; m++ ) 3326 Free_PosRuleSet( &prs[m] ); 3327 3328 FREE( prs ); 3329 3330 Fail2: 3331 _HB_OPEN_Free_Coverage( &cpf1->Coverage ); 3332 return error; 3333 } 3334 3335 3336 static void Free_ContextPos1( HB_ContextPosFormat1* cpf1 ) 3337 { 3338 HB_UShort n, count; 3339 3340 HB_PosRuleSet* prs; 3341 3342 3343 if ( cpf1->PosRuleSet ) 3344 { 3345 count = cpf1->PosRuleSetCount; 3346 prs = cpf1->PosRuleSet; 3347 3348 for ( n = 0; n < count; n++ ) 3349 Free_PosRuleSet( &prs[n] ); 3350 3351 FREE( prs ); 3352 } 3353 3354 _HB_OPEN_Free_Coverage( &cpf1->Coverage ); 3355 } 3356 3357 3358 /* PosClassRule */ 3359 3360 static HB_Error Load_PosClassRule( HB_ContextPosFormat2* cpf2, 3361 HB_PosClassRule* pcr, 3362 HB_Stream stream ) 3363 { 3364 HB_Error error; 3365 3366 HB_UShort n, count; 3367 3368 HB_UShort* c; 3369 HB_PosLookupRecord* plr; 3370 3371 3372 if ( ACCESS_Frame( 4L ) ) 3373 return error; 3374 3375 pcr->GlyphCount = GET_UShort(); 3376 pcr->PosCount = GET_UShort(); 3377 3378 FORGET_Frame(); 3379 3380 if ( pcr->GlyphCount > cpf2->MaxContextLength ) 3381 cpf2->MaxContextLength = pcr->GlyphCount; 3382 3383 pcr->Class = NULL; 3384 3385 count = pcr->GlyphCount - 1; /* only GlyphCount - 1 elements */ 3386 3387 if ( ALLOC_ARRAY( pcr->Class, count, HB_UShort ) ) 3388 return error; 3389 3390 c = pcr->Class; 3391 3392 if ( ACCESS_Frame( count * 2L ) ) 3393 goto Fail2; 3394 3395 for ( n = 0; n < count; n++ ) 3396 c[n] = GET_UShort(); 3397 3398 FORGET_Frame(); 3399 3400 pcr->PosLookupRecord = NULL; 3401 3402 count = pcr->PosCount; 3403 3404 if ( ALLOC_ARRAY( pcr->PosLookupRecord, count, HB_PosLookupRecord ) ) 3405 goto Fail2; 3406 3407 plr = pcr->PosLookupRecord; 3408 3409 if ( ACCESS_Frame( count * 4L ) ) 3410 goto Fail1; 3411 3412 for ( n = 0; n < count; n++ ) 3413 { 3414 plr[n].SequenceIndex = GET_UShort(); 3415 plr[n].LookupListIndex = GET_UShort(); 3416 } 3417 3418 FORGET_Frame(); 3419 3420 return HB_Err_Ok; 3421 3422 Fail1: 3423 FREE( plr ); 3424 3425 Fail2: 3426 FREE( c ); 3427 return error; 3428 } 3429 3430 3431 static void Free_PosClassRule( HB_PosClassRule* pcr ) 3432 { 3433 FREE( pcr->PosLookupRecord ); 3434 FREE( pcr->Class ); 3435 } 3436 3437 3438 /* PosClassSet */ 3439 3440 static HB_Error Load_PosClassSet( HB_ContextPosFormat2* cpf2, 3441 HB_PosClassSet* pcs, 3442 HB_Stream stream ) 3443 { 3444 HB_Error error; 3445 3446 HB_UShort n, m, count; 3447 HB_UInt cur_offset, new_offset, base_offset; 3448 3449 HB_PosClassRule* pcr; 3450 3451 3452 base_offset = FILE_Pos(); 3453 3454 if ( ACCESS_Frame( 2L ) ) 3455 return error; 3456 3457 count = pcs->PosClassRuleCount = GET_UShort(); 3458 3459 FORGET_Frame(); 3460 3461 pcs->PosClassRule = NULL; 3462 3463 if ( ALLOC_ARRAY( pcs->PosClassRule, count, HB_PosClassRule ) ) 3464 return error; 3465 3466 pcr = pcs->PosClassRule; 3467 3468 for ( n = 0; n < count; n++ ) 3469 { 3470 if ( ACCESS_Frame( 2L ) ) 3471 goto Fail; 3472 3473 new_offset = GET_UShort() + base_offset; 3474 3475 FORGET_Frame(); 3476 3477 cur_offset = FILE_Pos(); 3478 if ( FILE_Seek( new_offset ) || 3479 ( error = Load_PosClassRule( cpf2, &pcr[n], 3480 stream ) ) != HB_Err_Ok ) 3481 goto Fail; 3482 (void)FILE_Seek( cur_offset ); 3483 } 3484 3485 return HB_Err_Ok; 3486 3487 Fail: 3488 for ( m = 0; m < n; m++ ) 3489 Free_PosClassRule( &pcr[m] ); 3490 3491 FREE( pcr ); 3492 return error; 3493 } 3494 3495 3496 static void Free_PosClassSet( HB_PosClassSet* pcs ) 3497 { 3498 HB_UShort n, count; 3499 3500 HB_PosClassRule* pcr; 3501 3502 3503 if ( pcs->PosClassRule ) 3504 { 3505 count = pcs->PosClassRuleCount; 3506 pcr = pcs->PosClassRule; 3507 3508 for ( n = 0; n < count; n++ ) 3509 Free_PosClassRule( &pcr[n] ); 3510 3511 FREE( pcr ); 3512 } 3513 } 3514 3515 3516 /* ContextPosFormat2 */ 3517 3518 static HB_Error Load_ContextPos2( HB_ContextPosFormat2* cpf2, 3519 HB_Stream stream ) 3520 { 3521 HB_Error error; 3522 3523 HB_UShort n, m, count; 3524 HB_UInt cur_offset, new_offset, base_offset; 3525 3526 HB_PosClassSet* pcs; 3527 3528 3529 base_offset = FILE_Pos() - 2; 3530 3531 if ( ACCESS_Frame( 2L ) ) 3532 return error; 3533 3534 new_offset = GET_UShort() + base_offset; 3535 3536 FORGET_Frame(); 3537 3538 cur_offset = FILE_Pos(); 3539 if ( FILE_Seek( new_offset ) || 3540 ( error = _HB_OPEN_Load_Coverage( &cpf2->Coverage, stream ) ) != HB_Err_Ok ) 3541 return error; 3542 (void)FILE_Seek( cur_offset ); 3543 3544 if ( ACCESS_Frame( 4L ) ) 3545 goto Fail3; 3546 3547 new_offset = GET_UShort() + base_offset; 3548 3549 /* `PosClassSetCount' is the upper limit for class values, thus we 3550 read it now to make an additional safety check. */ 3551 3552 count = cpf2->PosClassSetCount = GET_UShort(); 3553 3554 FORGET_Frame(); 3555 3556 cur_offset = FILE_Pos(); 3557 if ( FILE_Seek( new_offset ) || 3558 ( error = _HB_OPEN_Load_ClassDefinition( &cpf2->ClassDef, count, 3559 stream ) ) != HB_Err_Ok ) 3560 goto Fail3; 3561 (void)FILE_Seek( cur_offset ); 3562 3563 cpf2->PosClassSet = NULL; 3564 cpf2->MaxContextLength = 0; 3565 3566 if ( ALLOC_ARRAY( cpf2->PosClassSet, count, HB_PosClassSet ) ) 3567 goto Fail2; 3568 3569 pcs = cpf2->PosClassSet; 3570 3571 for ( n = 0; n < count; n++ ) 3572 { 3573 if ( ACCESS_Frame( 2L ) ) 3574 goto Fail1; 3575 3576 new_offset = GET_UShort() + base_offset; 3577 3578 FORGET_Frame(); 3579 3580 if ( new_offset != base_offset ) /* not a NULL offset */ 3581 { 3582 cur_offset = FILE_Pos(); 3583 if ( FILE_Seek( new_offset ) || 3584 ( error = Load_PosClassSet( cpf2, &pcs[n], 3585 stream ) ) != HB_Err_Ok ) 3586 goto Fail1; 3587 (void)FILE_Seek( cur_offset ); 3588 } 3589 else 3590 { 3591 /* we create a PosClassSet table with no entries */ 3592 3593 cpf2->PosClassSet[n].PosClassRuleCount = 0; 3594 cpf2->PosClassSet[n].PosClassRule = NULL; 3595 } 3596 } 3597 3598 return HB_Err_Ok; 3599 3600 Fail1: 3601 for ( m = 0; m < n; n++ ) 3602 Free_PosClassSet( &pcs[m] ); 3603 3604 FREE( pcs ); 3605 3606 Fail2: 3607 _HB_OPEN_Free_ClassDefinition( &cpf2->ClassDef ); 3608 3609 Fail3: 3610 _HB_OPEN_Free_Coverage( &cpf2->Coverage ); 3611 return error; 3612 } 3613 3614 3615 static void Free_ContextPos2( HB_ContextPosFormat2* cpf2 ) 3616 { 3617 HB_UShort n, count; 3618 3619 HB_PosClassSet* pcs; 3620 3621 3622 if ( cpf2->PosClassSet ) 3623 { 3624 count = cpf2->PosClassSetCount; 3625 pcs = cpf2->PosClassSet; 3626 3627 for ( n = 0; n < count; n++ ) 3628 Free_PosClassSet( &pcs[n] ); 3629 3630 FREE( pcs ); 3631 } 3632 3633 _HB_OPEN_Free_ClassDefinition( &cpf2->ClassDef ); 3634 _HB_OPEN_Free_Coverage( &cpf2->Coverage ); 3635 } 3636 3637 3638 /* ContextPosFormat3 */ 3639 3640 static HB_Error Load_ContextPos3( HB_ContextPosFormat3* cpf3, 3641 HB_Stream stream ) 3642 { 3643 HB_Error error; 3644 3645 HB_UShort n, count; 3646 HB_UInt cur_offset, new_offset, base_offset; 3647 3648 HB_Coverage* c; 3649 HB_PosLookupRecord* plr; 3650 3651 3652 base_offset = FILE_Pos() - 2L; 3653 3654 if ( ACCESS_Frame( 4L ) ) 3655 return error; 3656 3657 cpf3->GlyphCount = GET_UShort(); 3658 cpf3->PosCount = GET_UShort(); 3659 3660 FORGET_Frame(); 3661 3662 cpf3->Coverage = NULL; 3663 3664 count = cpf3->GlyphCount; 3665 3666 if ( ALLOC_ARRAY( cpf3->Coverage, count, HB_Coverage ) ) 3667 return error; 3668 3669 c = cpf3->Coverage; 3670 3671 for ( n = 0; n < count; n++ ) 3672 { 3673 if ( ACCESS_Frame( 2L ) ) 3674 goto Fail2; 3675 3676 new_offset = GET_UShort() + base_offset; 3677 3678 FORGET_Frame(); 3679 3680 cur_offset = FILE_Pos(); 3681 if ( FILE_Seek( new_offset ) || 3682 ( error = _HB_OPEN_Load_Coverage( &c[n], stream ) ) != HB_Err_Ok ) 3683 goto Fail2; 3684 (void)FILE_Seek( cur_offset ); 3685 } 3686 3687 cpf3->PosLookupRecord = NULL; 3688 3689 count = cpf3->PosCount; 3690 3691 if ( ALLOC_ARRAY( cpf3->PosLookupRecord, count, HB_PosLookupRecord ) ) 3692 goto Fail2; 3693 3694 plr = cpf3->PosLookupRecord; 3695 3696 if ( ACCESS_Frame( count * 4L ) ) 3697 goto Fail1; 3698 3699 for ( n = 0; n < count; n++ ) 3700 { 3701 plr[n].SequenceIndex = GET_UShort(); 3702 plr[n].LookupListIndex = GET_UShort(); 3703 } 3704 3705 FORGET_Frame(); 3706 3707 return HB_Err_Ok; 3708 3709 Fail1: 3710 FREE( plr ); 3711 3712 Fail2: 3713 for ( n = 0; n < count; n++ ) 3714 _HB_OPEN_Free_Coverage( &c[n] ); 3715 3716 FREE( c ); 3717 return error; 3718 } 3719 3720 3721 static void Free_ContextPos3( HB_ContextPosFormat3* cpf3 ) 3722 { 3723 HB_UShort n, count; 3724 3725 HB_Coverage* c; 3726 3727 3728 FREE( cpf3->PosLookupRecord ); 3729 3730 if ( cpf3->Coverage ) 3731 { 3732 count = cpf3->GlyphCount; 3733 c = cpf3->Coverage; 3734 3735 for ( n = 0; n < count; n++ ) 3736 _HB_OPEN_Free_Coverage( &c[n] ); 3737 3738 FREE( c ); 3739 } 3740 } 3741 3742 3743 /* ContextPos */ 3744 3745 static HB_Error Load_ContextPos( HB_GPOS_SubTable* st, 3746 HB_Stream stream ) 3747 { 3748 HB_Error error; 3749 HB_ContextPos* cp = &st->context; 3750 3751 3752 if ( ACCESS_Frame( 2L ) ) 3753 return error; 3754 3755 cp->PosFormat = GET_UShort(); 3756 3757 FORGET_Frame(); 3758 3759 switch ( cp->PosFormat ) 3760 { 3761 case 1: 3762 return Load_ContextPos1( &cp->cpf.cpf1, stream ); 3763 3764 case 2: 3765 return Load_ContextPos2( &cp->cpf.cpf2, stream ); 3766 3767 case 3: 3768 return Load_ContextPos3( &cp->cpf.cpf3, stream ); 3769 3770 default: 3771 return ERR(HB_Err_Invalid_SubTable_Format); 3772 } 3773 3774 return HB_Err_Ok; /* never reached */ 3775 } 3776 3777 3778 static void Free_ContextPos( HB_GPOS_SubTable* st ) 3779 { 3780 HB_ContextPos* cp = &st->context; 3781 3782 switch ( cp->PosFormat ) 3783 { 3784 case 1: Free_ContextPos1( &cp->cpf.cpf1 ); break; 3785 case 2: Free_ContextPos2( &cp->cpf.cpf2 ); break; 3786 case 3: Free_ContextPos3( &cp->cpf.cpf3 ); break; 3787 default: break; 3788 } 3789 } 3790 3791 3792 static HB_Error Lookup_ContextPos1( GPOS_Instance* gpi, 3793 HB_ContextPosFormat1* cpf1, 3794 HB_Buffer buffer, 3795 HB_UShort flags, 3796 HB_UShort context_length, 3797 int nesting_level ) 3798 { 3799 HB_UShort index, property; 3800 HB_UShort i, j, k, numpr; 3801 HB_Error error; 3802 HB_GPOSHeader* gpos = gpi->gpos; 3803 3804 HB_PosRule* pr; 3805 HB_GDEFHeader* gdef; 3806 3807 3808 gdef = gpos->gdef; 3809 3810 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) 3811 return error; 3812 3813 error = _HB_OPEN_Coverage_Index( &cpf1->Coverage, IN_CURGLYPH(), &index ); 3814 if ( error ) 3815 return error; 3816 3817 pr = cpf1->PosRuleSet[index].PosRule; 3818 numpr = cpf1->PosRuleSet[index].PosRuleCount; 3819 3820 for ( k = 0; k < numpr; k++ ) 3821 { 3822 if ( context_length != 0xFFFF && context_length < pr[k].GlyphCount ) 3823 goto next_posrule; 3824 3825 if ( buffer->in_pos + pr[k].GlyphCount > buffer->in_length ) 3826 goto next_posrule; /* context is too long */ 3827 3828 for ( i = 1, j = buffer->in_pos + 1; i < pr[k].GlyphCount; i++, j++ ) 3829 { 3830 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) 3831 { 3832 if ( error && error != HB_Err_Not_Covered ) 3833 return error; 3834 3835 if ( j + pr[k].GlyphCount - i == (HB_Int)buffer->in_length ) 3836 goto next_posrule; 3837 j++; 3838 } 3839 3840 if ( IN_GLYPH( j ) != pr[k].Input[i - 1] ) 3841 goto next_posrule; 3842 } 3843 3844 return Do_ContextPos( gpi, pr[k].GlyphCount, 3845 pr[k].PosCount, pr[k].PosLookupRecord, 3846 buffer, 3847 nesting_level ); 3848 3849 next_posrule: 3850 ; 3851 } 3852 3853 return HB_Err_Not_Covered; 3854 } 3855 3856 3857 static HB_Error Lookup_ContextPos2( GPOS_Instance* gpi, 3858 HB_ContextPosFormat2* cpf2, 3859 HB_Buffer buffer, 3860 HB_UShort flags, 3861 HB_UShort context_length, 3862 int nesting_level ) 3863 { 3864 HB_UShort index, property; 3865 HB_Error error; 3866 HB_UShort i, j, k, known_classes; 3867 3868 HB_UShort* classes; 3869 HB_UShort* cl; 3870 HB_GPOSHeader* gpos = gpi->gpos; 3871 3872 HB_PosClassSet* pcs; 3873 HB_PosClassRule* pr; 3874 HB_GDEFHeader* gdef; 3875 3876 3877 gdef = gpos->gdef; 3878 3879 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) 3880 return error; 3881 3882 /* Note: The coverage table in format 2 doesn't give an index into 3883 anything. It just lets us know whether or not we need to 3884 do any lookup at all. */ 3885 3886 error = _HB_OPEN_Coverage_Index( &cpf2->Coverage, IN_CURGLYPH(), &index ); 3887 if ( error ) 3888 return error; 3889 3890 if (cpf2->MaxContextLength < 1) 3891 return HB_Err_Not_Covered; 3892 3893 if ( ALLOC_ARRAY( classes, cpf2->MaxContextLength, HB_UShort ) ) 3894 return error; 3895 3896 error = _HB_OPEN_Get_Class( &cpf2->ClassDef, IN_CURGLYPH(), 3897 &classes[0], NULL ); 3898 if ( error && error != HB_Err_Not_Covered ) 3899 goto End; 3900 known_classes = 0; 3901 3902 pcs = &cpf2->PosClassSet[classes[0]]; 3903 if ( !pcs ) 3904 { 3905 error = ERR(HB_Err_Invalid_SubTable); 3906 goto End; 3907 } 3908 3909 for ( k = 0; k < pcs->PosClassRuleCount; k++ ) 3910 { 3911 pr = &pcs->PosClassRule[k]; 3912 3913 if ( context_length != 0xFFFF && context_length < pr->GlyphCount ) 3914 goto next_posclassrule; 3915 3916 if ( buffer->in_pos + pr->GlyphCount > buffer->in_length ) 3917 goto next_posclassrule; /* context is too long */ 3918 3919 cl = pr->Class; 3920 3921 /* Start at 1 because [0] is implied */ 3922 3923 for ( i = 1, j = buffer->in_pos + 1; i < pr->GlyphCount; i++, j++ ) 3924 { 3925 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) 3926 { 3927 if ( error && error != HB_Err_Not_Covered ) 3928 goto End; 3929 3930 if ( j + pr->GlyphCount - i == (HB_Int)buffer->in_length ) 3931 goto next_posclassrule; 3932 j++; 3933 } 3934 3935 if ( i > known_classes ) 3936 { 3937 /* Keeps us from having to do this for each rule */ 3938 3939 error = _HB_OPEN_Get_Class( &cpf2->ClassDef, IN_GLYPH( j ), &classes[i], NULL ); 3940 if ( error && error != HB_Err_Not_Covered ) 3941 goto End; 3942 known_classes = i; 3943 } 3944 3945 if ( cl[i - 1] != classes[i] ) 3946 goto next_posclassrule; 3947 } 3948 3949 error = Do_ContextPos( gpi, pr->GlyphCount, 3950 pr->PosCount, pr->PosLookupRecord, 3951 buffer, 3952 nesting_level ); 3953 goto End; 3954 3955 next_posclassrule: 3956 ; 3957 } 3958 3959 error = HB_Err_Not_Covered; 3960 3961 End: 3962 FREE( classes ); 3963 return error; 3964 } 3965 3966 3967 static HB_Error Lookup_ContextPos3( GPOS_Instance* gpi, 3968 HB_ContextPosFormat3* cpf3, 3969 HB_Buffer buffer, 3970 HB_UShort flags, 3971 HB_UShort context_length, 3972 int nesting_level ) 3973 { 3974 HB_Error error; 3975 HB_UShort index, i, j, property; 3976 HB_GPOSHeader* gpos = gpi->gpos; 3977 3978 HB_Coverage* c; 3979 HB_GDEFHeader* gdef; 3980 3981 3982 gdef = gpos->gdef; 3983 3984 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) 3985 return error; 3986 3987 if ( context_length != 0xFFFF && context_length < cpf3->GlyphCount ) 3988 return HB_Err_Not_Covered; 3989 3990 if ( buffer->in_pos + cpf3->GlyphCount > buffer->in_length ) 3991 return HB_Err_Not_Covered; /* context is too long */ 3992 3993 c = cpf3->Coverage; 3994 3995 for ( i = 1, j = 1; i < cpf3->GlyphCount; i++, j++ ) 3996 { 3997 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) 3998 { 3999 if ( error && error != HB_Err_Not_Covered ) 4000 return error; 4001 4002 if ( j + cpf3->GlyphCount - i == (HB_Int)buffer->in_length ) 4003 return HB_Err_Not_Covered; 4004 j++; 4005 } 4006 4007 error = _HB_OPEN_Coverage_Index( &c[i], IN_GLYPH( j ), &index ); 4008 if ( error ) 4009 return error; 4010 } 4011 4012 return Do_ContextPos( gpi, cpf3->GlyphCount, 4013 cpf3->PosCount, cpf3->PosLookupRecord, 4014 buffer, 4015 nesting_level ); 4016 } 4017 4018 4019 static HB_Error Lookup_ContextPos( GPOS_Instance* gpi, 4020 HB_GPOS_SubTable* st, 4021 HB_Buffer buffer, 4022 HB_UShort flags, 4023 HB_UShort context_length, 4024 int nesting_level ) 4025 { 4026 HB_ContextPos* cp = &st->context; 4027 4028 switch ( cp->PosFormat ) 4029 { 4030 case 1: 4031 return Lookup_ContextPos1( gpi, &cp->cpf.cpf1, buffer, 4032 flags, context_length, nesting_level ); 4033 4034 case 2: 4035 return Lookup_ContextPos2( gpi, &cp->cpf.cpf2, buffer, 4036 flags, context_length, nesting_level ); 4037 4038 case 3: 4039 return Lookup_ContextPos3( gpi, &cp->cpf.cpf3, buffer, 4040 flags, context_length, nesting_level ); 4041 4042 default: 4043 return ERR(HB_Err_Invalid_SubTable_Format); 4044 } 4045 4046 return HB_Err_Ok; /* never reached */ 4047 } 4048 4049 4050 /* LookupType 8 */ 4051 4052 /* ChainPosRule */ 4053 4054 static HB_Error Load_ChainPosRule( HB_ChainPosRule* cpr, 4055 HB_Stream stream ) 4056 { 4057 HB_Error error; 4058 4059 HB_UShort n, count; 4060 HB_UShort* b; 4061 HB_UShort* i; 4062 HB_UShort* l; 4063 4064 HB_PosLookupRecord* plr; 4065 4066 4067 if ( ACCESS_Frame( 2L ) ) 4068 return error; 4069 4070 cpr->BacktrackGlyphCount = GET_UShort(); 4071 4072 FORGET_Frame(); 4073 4074 cpr->Backtrack = NULL; 4075 4076 count = cpr->BacktrackGlyphCount; 4077 4078 if ( ALLOC_ARRAY( cpr->Backtrack, count, HB_UShort ) ) 4079 return error; 4080 4081 b = cpr->Backtrack; 4082 4083 if ( ACCESS_Frame( count * 2L ) ) 4084 goto Fail4; 4085 4086 for ( n = 0; n < count; n++ ) 4087 b[n] = GET_UShort(); 4088 4089 FORGET_Frame(); 4090 4091 if ( ACCESS_Frame( 2L ) ) 4092 goto Fail4; 4093 4094 cpr->InputGlyphCount = GET_UShort(); 4095 4096 FORGET_Frame(); 4097 4098 cpr->Input = NULL; 4099 4100 count = cpr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */ 4101 4102 if ( ALLOC_ARRAY( cpr->Input, count, HB_UShort ) ) 4103 goto Fail4; 4104 4105 i = cpr->Input; 4106 4107 if ( ACCESS_Frame( count * 2L ) ) 4108 goto Fail3; 4109 4110 for ( n = 0; n < count; n++ ) 4111 i[n] = GET_UShort(); 4112 4113 FORGET_Frame(); 4114 4115 if ( ACCESS_Frame( 2L ) ) 4116 goto Fail3; 4117 4118 cpr->LookaheadGlyphCount = GET_UShort(); 4119 4120 FORGET_Frame(); 4121 4122 cpr->Lookahead = NULL; 4123 4124 count = cpr->LookaheadGlyphCount; 4125 4126 if ( ALLOC_ARRAY( cpr->Lookahead, count, HB_UShort ) ) 4127 goto Fail3; 4128 4129 l = cpr->Lookahead; 4130 4131 if ( ACCESS_Frame( count * 2L ) ) 4132 goto Fail2; 4133 4134 for ( n = 0; n < count; n++ ) 4135 l[n] = GET_UShort(); 4136 4137 FORGET_Frame(); 4138 4139 if ( ACCESS_Frame( 2L ) ) 4140 goto Fail2; 4141 4142 cpr->PosCount = GET_UShort(); 4143 4144 FORGET_Frame(); 4145 4146 cpr->PosLookupRecord = NULL; 4147 4148 count = cpr->PosCount; 4149 4150 if ( ALLOC_ARRAY( cpr->PosLookupRecord, count, HB_PosLookupRecord ) ) 4151 goto Fail2; 4152 4153 plr = cpr->PosLookupRecord; 4154 4155 if ( ACCESS_Frame( count * 4L ) ) 4156 goto Fail1; 4157 4158 for ( n = 0; n < count; n++ ) 4159 { 4160 plr[n].SequenceIndex = GET_UShort(); 4161 plr[n].LookupListIndex = GET_UShort(); 4162 } 4163 4164 FORGET_Frame(); 4165 4166 return HB_Err_Ok; 4167 4168 Fail1: 4169 FREE( plr ); 4170 4171 Fail2: 4172 FREE( l ); 4173 4174 Fail3: 4175 FREE( i ); 4176 4177 Fail4: 4178 FREE( b ); 4179 return error; 4180 } 4181 4182 4183 static void Free_ChainPosRule( HB_ChainPosRule* cpr ) 4184 { 4185 FREE( cpr->PosLookupRecord ); 4186 FREE( cpr->Lookahead ); 4187 FREE( cpr->Input ); 4188 FREE( cpr->Backtrack ); 4189 } 4190 4191 4192 /* ChainPosRuleSet */ 4193 4194 static HB_Error Load_ChainPosRuleSet( HB_ChainPosRuleSet* cprs, 4195 HB_Stream stream ) 4196 { 4197 HB_Error error; 4198 4199 HB_UShort n, m, count; 4200 HB_UInt cur_offset, new_offset, base_offset; 4201 4202 HB_ChainPosRule* cpr; 4203 4204 4205 base_offset = FILE_Pos(); 4206 4207 if ( ACCESS_Frame( 2L ) ) 4208 return error; 4209 4210 count = cprs->ChainPosRuleCount = GET_UShort(); 4211 4212 FORGET_Frame(); 4213 4214 cprs->ChainPosRule = NULL; 4215 4216 if ( ALLOC_ARRAY( cprs->ChainPosRule, count, HB_ChainPosRule ) ) 4217 return error; 4218 4219 cpr = cprs->ChainPosRule; 4220 4221 for ( n = 0; n < count; n++ ) 4222 { 4223 if ( ACCESS_Frame( 2L ) ) 4224 goto Fail; 4225 4226 new_offset = GET_UShort() + base_offset; 4227 4228 FORGET_Frame(); 4229 4230 cur_offset = FILE_Pos(); 4231 if ( FILE_Seek( new_offset ) || 4232 ( error = Load_ChainPosRule( &cpr[n], stream ) ) != HB_Err_Ok ) 4233 goto Fail; 4234 (void)FILE_Seek( cur_offset ); 4235 } 4236 4237 return HB_Err_Ok; 4238 4239 Fail: 4240 for ( m = 0; m < n; m++ ) 4241 Free_ChainPosRule( &cpr[m] ); 4242 4243 FREE( cpr ); 4244 return error; 4245 } 4246 4247 4248 static void Free_ChainPosRuleSet( HB_ChainPosRuleSet* cprs ) 4249 { 4250 HB_UShort n, count; 4251 4252 HB_ChainPosRule* cpr; 4253 4254 4255 if ( cprs->ChainPosRule ) 4256 { 4257 count = cprs->ChainPosRuleCount; 4258 cpr = cprs->ChainPosRule; 4259 4260 for ( n = 0; n < count; n++ ) 4261 Free_ChainPosRule( &cpr[n] ); 4262 4263 FREE( cpr ); 4264 } 4265 } 4266 4267 4268 /* ChainContextPosFormat1 */ 4269 4270 static HB_Error Load_ChainContextPos1( HB_ChainContextPosFormat1* ccpf1, 4271 HB_Stream stream ) 4272 { 4273 HB_Error error; 4274 4275 HB_UShort n, m, count; 4276 HB_UInt cur_offset, new_offset, base_offset; 4277 4278 HB_ChainPosRuleSet* cprs; 4279 4280 4281 base_offset = FILE_Pos() - 2L; 4282 4283 if ( ACCESS_Frame( 2L ) ) 4284 return error; 4285 4286 new_offset = GET_UShort() + base_offset; 4287 4288 FORGET_Frame(); 4289 4290 cur_offset = FILE_Pos(); 4291 if ( FILE_Seek( new_offset ) || 4292 ( error = _HB_OPEN_Load_Coverage( &ccpf1->Coverage, stream ) ) != HB_Err_Ok ) 4293 return error; 4294 (void)FILE_Seek( cur_offset ); 4295 4296 if ( ACCESS_Frame( 2L ) ) 4297 goto Fail2; 4298 4299 count = ccpf1->ChainPosRuleSetCount = GET_UShort(); 4300 4301 FORGET_Frame(); 4302 4303 ccpf1->ChainPosRuleSet = NULL; 4304 4305 if ( ALLOC_ARRAY( ccpf1->ChainPosRuleSet, count, HB_ChainPosRuleSet ) ) 4306 goto Fail2; 4307 4308 cprs = ccpf1->ChainPosRuleSet; 4309 4310 for ( n = 0; n < count; n++ ) 4311 { 4312 if ( ACCESS_Frame( 2L ) ) 4313 goto Fail1; 4314 4315 new_offset = GET_UShort() + base_offset; 4316 4317 FORGET_Frame(); 4318 4319 cur_offset = FILE_Pos(); 4320 if ( FILE_Seek( new_offset ) || 4321 ( error = Load_ChainPosRuleSet( &cprs[n], stream ) ) != HB_Err_Ok ) 4322 goto Fail1; 4323 (void)FILE_Seek( cur_offset ); 4324 } 4325 4326 return HB_Err_Ok; 4327 4328 Fail1: 4329 for ( m = 0; m < n; m++ ) 4330 Free_ChainPosRuleSet( &cprs[m] ); 4331 4332 FREE( cprs ); 4333 4334 Fail2: 4335 _HB_OPEN_Free_Coverage( &ccpf1->Coverage ); 4336 return error; 4337 } 4338 4339 4340 static void Free_ChainContextPos1( HB_ChainContextPosFormat1* ccpf1 ) 4341 { 4342 HB_UShort n, count; 4343 4344 HB_ChainPosRuleSet* cprs; 4345 4346 4347 if ( ccpf1->ChainPosRuleSet ) 4348 { 4349 count = ccpf1->ChainPosRuleSetCount; 4350 cprs = ccpf1->ChainPosRuleSet; 4351 4352 for ( n = 0; n < count; n++ ) 4353 Free_ChainPosRuleSet( &cprs[n] ); 4354 4355 FREE( cprs ); 4356 } 4357 4358 _HB_OPEN_Free_Coverage( &ccpf1->Coverage ); 4359 } 4360 4361 4362 /* ChainPosClassRule */ 4363 4364 static HB_Error Load_ChainPosClassRule( 4365 HB_ChainContextPosFormat2* ccpf2, 4366 HB_ChainPosClassRule* cpcr, 4367 HB_Stream stream ) 4368 { 4369 HB_Error error; 4370 4371 HB_UShort n, count; 4372 4373 HB_UShort* b; 4374 HB_UShort* i; 4375 HB_UShort* l; 4376 HB_PosLookupRecord* plr; 4377 4378 4379 if ( ACCESS_Frame( 2L ) ) 4380 return error; 4381 4382 cpcr->BacktrackGlyphCount = GET_UShort(); 4383 4384 FORGET_Frame(); 4385 4386 if ( cpcr->BacktrackGlyphCount > ccpf2->MaxBacktrackLength ) 4387 ccpf2->MaxBacktrackLength = cpcr->BacktrackGlyphCount; 4388 4389 cpcr->Backtrack = NULL; 4390 4391 count = cpcr->BacktrackGlyphCount; 4392 4393 if ( ALLOC_ARRAY( cpcr->Backtrack, count, HB_UShort ) ) 4394 return error; 4395 4396 b = cpcr->Backtrack; 4397 4398 if ( ACCESS_Frame( count * 2L ) ) 4399 goto Fail4; 4400 4401 for ( n = 0; n < count; n++ ) 4402 b[n] = GET_UShort(); 4403 4404 FORGET_Frame(); 4405 4406 if ( ACCESS_Frame( 2L ) ) 4407 goto Fail4; 4408 4409 cpcr->InputGlyphCount = GET_UShort(); 4410 4411 if ( cpcr->InputGlyphCount > ccpf2->MaxInputLength ) 4412 ccpf2->MaxInputLength = cpcr->InputGlyphCount; 4413 4414 FORGET_Frame(); 4415 4416 cpcr->Input = NULL; 4417 4418 count = cpcr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */ 4419 4420 if ( ALLOC_ARRAY( cpcr->Input, count, HB_UShort ) ) 4421 goto Fail4; 4422 4423 i = cpcr->Input; 4424 4425 if ( ACCESS_Frame( count * 2L ) ) 4426 goto Fail3; 4427 4428 for ( n = 0; n < count; n++ ) 4429 i[n] = GET_UShort(); 4430 4431 FORGET_Frame(); 4432 4433 if ( ACCESS_Frame( 2L ) ) 4434 goto Fail3; 4435 4436 cpcr->LookaheadGlyphCount = GET_UShort(); 4437 4438 FORGET_Frame(); 4439 4440 if ( cpcr->LookaheadGlyphCount > ccpf2->MaxLookaheadLength ) 4441 ccpf2->MaxLookaheadLength = cpcr->LookaheadGlyphCount; 4442 4443 cpcr->Lookahead = NULL; 4444 4445 count = cpcr->LookaheadGlyphCount; 4446 4447 if ( ALLOC_ARRAY( cpcr->Lookahead, count, HB_UShort ) ) 4448 goto Fail3; 4449 4450 l = cpcr->Lookahead; 4451 4452 if ( ACCESS_Frame( count * 2L ) ) 4453 goto Fail2; 4454 4455 for ( n = 0; n < count; n++ ) 4456 l[n] = GET_UShort(); 4457 4458 FORGET_Frame(); 4459 4460 if ( ACCESS_Frame( 2L ) ) 4461 goto Fail2; 4462 4463 cpcr->PosCount = GET_UShort(); 4464 4465 FORGET_Frame(); 4466 4467 cpcr->PosLookupRecord = NULL; 4468 4469 count = cpcr->PosCount; 4470 4471 if ( ALLOC_ARRAY( cpcr->PosLookupRecord, count, HB_PosLookupRecord ) ) 4472 goto Fail2; 4473 4474 plr = cpcr->PosLookupRecord; 4475 4476 if ( ACCESS_Frame( count * 4L ) ) 4477 goto Fail1; 4478 4479 for ( n = 0; n < count; n++ ) 4480 { 4481 plr[n].SequenceIndex = GET_UShort(); 4482 plr[n].LookupListIndex = GET_UShort(); 4483 } 4484 4485 FORGET_Frame(); 4486 4487 return HB_Err_Ok; 4488 4489 Fail1: 4490 FREE( plr ); 4491 4492 Fail2: 4493 FREE( l ); 4494 4495 Fail3: 4496 FREE( i ); 4497 4498 Fail4: 4499 FREE( b ); 4500 return error; 4501 } 4502 4503 4504 static void Free_ChainPosClassRule( HB_ChainPosClassRule* cpcr ) 4505 { 4506 FREE( cpcr->PosLookupRecord ); 4507 FREE( cpcr->Lookahead ); 4508 FREE( cpcr->Input ); 4509 FREE( cpcr->Backtrack ); 4510 } 4511 4512 4513 /* PosClassSet */ 4514 4515 static HB_Error Load_ChainPosClassSet( 4516 HB_ChainContextPosFormat2* ccpf2, 4517 HB_ChainPosClassSet* cpcs, 4518 HB_Stream stream ) 4519 { 4520 HB_Error error; 4521 4522 HB_UShort n, m, count; 4523 HB_UInt cur_offset, new_offset, base_offset; 4524 4525 HB_ChainPosClassRule* cpcr; 4526 4527 4528 base_offset = FILE_Pos(); 4529 4530 if ( ACCESS_Frame( 2L ) ) 4531 return error; 4532 4533 count = cpcs->ChainPosClassRuleCount = GET_UShort(); 4534 4535 FORGET_Frame(); 4536 4537 cpcs->ChainPosClassRule = NULL; 4538 4539 if ( ALLOC_ARRAY( cpcs->ChainPosClassRule, count, 4540 HB_ChainPosClassRule ) ) 4541 return error; 4542 4543 cpcr = cpcs->ChainPosClassRule; 4544 4545 for ( n = 0; n < count; n++ ) 4546 { 4547 if ( ACCESS_Frame( 2L ) ) 4548 goto Fail; 4549 4550 new_offset = GET_UShort() + base_offset; 4551 4552 FORGET_Frame(); 4553 4554 cur_offset = FILE_Pos(); 4555 if ( FILE_Seek( new_offset ) || 4556 ( error = Load_ChainPosClassRule( ccpf2, &cpcr[n], 4557 stream ) ) != HB_Err_Ok ) 4558 goto Fail; 4559 (void)FILE_Seek( cur_offset ); 4560 } 4561 4562 return HB_Err_Ok; 4563 4564 Fail: 4565 for ( m = 0; m < n; m++ ) 4566 Free_ChainPosClassRule( &cpcr[m] ); 4567 4568 FREE( cpcr ); 4569 return error; 4570 } 4571 4572 4573 static void Free_ChainPosClassSet( HB_ChainPosClassSet* cpcs ) 4574 { 4575 HB_UShort n, count; 4576 4577 HB_ChainPosClassRule* cpcr; 4578 4579 4580 if ( cpcs->ChainPosClassRule ) 4581 { 4582 count = cpcs->ChainPosClassRuleCount; 4583 cpcr = cpcs->ChainPosClassRule; 4584 4585 for ( n = 0; n < count; n++ ) 4586 Free_ChainPosClassRule( &cpcr[n] ); 4587 4588 FREE( cpcr ); 4589 } 4590 } 4591 4592 4593 /* ChainContextPosFormat2 */ 4594 4595 static HB_Error Load_ChainContextPos2( HB_ChainContextPosFormat2* ccpf2, 4596 HB_Stream stream ) 4597 { 4598 HB_Error error; 4599 4600 HB_UShort n, m, count; 4601 HB_UInt cur_offset, new_offset, base_offset; 4602 HB_UInt backtrack_offset, input_offset, lookahead_offset; 4603 4604 HB_ChainPosClassSet* cpcs; 4605 4606 4607 base_offset = FILE_Pos() - 2; 4608 4609 if ( ACCESS_Frame( 2L ) ) 4610 return error; 4611 4612 new_offset = GET_UShort() + base_offset; 4613 4614 FORGET_Frame(); 4615 4616 cur_offset = FILE_Pos(); 4617 if ( FILE_Seek( new_offset ) || 4618 ( error = _HB_OPEN_Load_Coverage( &ccpf2->Coverage, stream ) ) != HB_Err_Ok ) 4619 return error; 4620 (void)FILE_Seek( cur_offset ); 4621 4622 if ( ACCESS_Frame( 8L ) ) 4623 goto Fail5; 4624 4625 backtrack_offset = GET_UShort(); 4626 input_offset = GET_UShort(); 4627 lookahead_offset = GET_UShort(); 4628 4629 /* `ChainPosClassSetCount' is the upper limit for input class values, 4630 thus we read it now to make an additional safety check. No limit 4631 is known or needed for the other two class definitions */ 4632 4633 count = ccpf2->ChainPosClassSetCount = GET_UShort(); 4634 4635 FORGET_Frame(); 4636 4637 if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->BacktrackClassDef, 65535, 4638 backtrack_offset, base_offset, 4639 stream ) ) != HB_Err_Ok ) 4640 goto Fail5; 4641 if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->InputClassDef, count, 4642 input_offset, base_offset, 4643 stream ) ) != HB_Err_Ok ) 4644 goto Fail4; 4645 if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->LookaheadClassDef, 65535, 4646 lookahead_offset, base_offset, 4647 stream ) ) != HB_Err_Ok ) 4648 goto Fail3; 4649 4650 ccpf2->ChainPosClassSet = NULL; 4651 ccpf2->MaxBacktrackLength = 0; 4652 ccpf2->MaxInputLength = 0; 4653 ccpf2->MaxLookaheadLength = 0; 4654 4655 if ( ALLOC_ARRAY( ccpf2->ChainPosClassSet, count, HB_ChainPosClassSet ) ) 4656 goto Fail2; 4657 4658 cpcs = ccpf2->ChainPosClassSet; 4659 4660 for ( n = 0; n < count; n++ ) 4661 { 4662 if ( ACCESS_Frame( 2L ) ) 4663 goto Fail1; 4664 4665 new_offset = GET_UShort() + base_offset; 4666 4667 FORGET_Frame(); 4668 4669 if ( new_offset != base_offset ) /* not a NULL offset */ 4670 { 4671 cur_offset = FILE_Pos(); 4672 if ( FILE_Seek( new_offset ) || 4673 ( error = Load_ChainPosClassSet( ccpf2, &cpcs[n], 4674 stream ) ) != HB_Err_Ok ) 4675 goto Fail1; 4676 (void)FILE_Seek( cur_offset ); 4677 } 4678 else 4679 { 4680 /* we create a ChainPosClassSet table with no entries */ 4681 4682 ccpf2->ChainPosClassSet[n].ChainPosClassRuleCount = 0; 4683 ccpf2->ChainPosClassSet[n].ChainPosClassRule = NULL; 4684 } 4685 } 4686 4687 return HB_Err_Ok; 4688 4689 Fail1: 4690 for ( m = 0; m < n; m++ ) 4691 Free_ChainPosClassSet( &cpcs[m] ); 4692 4693 FREE( cpcs ); 4694 4695 Fail2: 4696 _HB_OPEN_Free_ClassDefinition( &ccpf2->LookaheadClassDef ); 4697 4698 Fail3: 4699 _HB_OPEN_Free_ClassDefinition( &ccpf2->InputClassDef ); 4700 4701 Fail4: 4702 _HB_OPEN_Free_ClassDefinition( &ccpf2->BacktrackClassDef ); 4703 4704 Fail5: 4705 _HB_OPEN_Free_Coverage( &ccpf2->Coverage ); 4706 return error; 4707 } 4708 4709 4710 static void Free_ChainContextPos2( HB_ChainContextPosFormat2* ccpf2 ) 4711 { 4712 HB_UShort n, count; 4713 4714 HB_ChainPosClassSet* cpcs; 4715 4716 4717 if ( ccpf2->ChainPosClassSet ) 4718 { 4719 count = ccpf2->ChainPosClassSetCount; 4720 cpcs = ccpf2->ChainPosClassSet; 4721 4722 for ( n = 0; n < count; n++ ) 4723 Free_ChainPosClassSet( &cpcs[n] ); 4724 4725 FREE( cpcs ); 4726 } 4727 4728 _HB_OPEN_Free_ClassDefinition( &ccpf2->LookaheadClassDef ); 4729 _HB_OPEN_Free_ClassDefinition( &ccpf2->InputClassDef ); 4730 _HB_OPEN_Free_ClassDefinition( &ccpf2->BacktrackClassDef ); 4731 4732 _HB_OPEN_Free_Coverage( &ccpf2->Coverage ); 4733 } 4734 4735 4736 /* ChainContextPosFormat3 */ 4737 4738 static HB_Error Load_ChainContextPos3( HB_ChainContextPosFormat3* ccpf3, 4739 HB_Stream stream ) 4740 { 4741 HB_Error error; 4742 4743 HB_UShort n, nb, ni, nl, m, count; 4744 HB_UShort backtrack_count, input_count, lookahead_count; 4745 HB_UInt cur_offset, new_offset, base_offset; 4746 4747 HB_Coverage* b; 4748 HB_Coverage* i; 4749 HB_Coverage* l; 4750 HB_PosLookupRecord* plr; 4751 4752 4753 base_offset = FILE_Pos() - 2L; 4754 4755 if ( ACCESS_Frame( 2L ) ) 4756 return error; 4757 4758 ccpf3->BacktrackGlyphCount = GET_UShort(); 4759 4760 FORGET_Frame(); 4761 4762 ccpf3->BacktrackCoverage = NULL; 4763 4764 backtrack_count = ccpf3->BacktrackGlyphCount; 4765 4766 if ( ALLOC_ARRAY( ccpf3->BacktrackCoverage, backtrack_count, 4767 HB_Coverage ) ) 4768 return error; 4769 4770 b = ccpf3->BacktrackCoverage; 4771 4772 for ( nb = 0; nb < backtrack_count; nb++ ) 4773 { 4774 if ( ACCESS_Frame( 2L ) ) 4775 goto Fail4; 4776 4777 new_offset = GET_UShort() + base_offset; 4778 4779 FORGET_Frame(); 4780 4781 cur_offset = FILE_Pos(); 4782 if ( FILE_Seek( new_offset ) || 4783 ( error = _HB_OPEN_Load_Coverage( &b[nb], stream ) ) != HB_Err_Ok ) 4784 goto Fail4; 4785 (void)FILE_Seek( cur_offset ); 4786 } 4787 4788 if ( ACCESS_Frame( 2L ) ) 4789 goto Fail4; 4790 4791 ccpf3->InputGlyphCount = GET_UShort(); 4792 4793 FORGET_Frame(); 4794 4795 ccpf3->InputCoverage = NULL; 4796 4797 input_count = ccpf3->InputGlyphCount; 4798 4799 if ( ALLOC_ARRAY( ccpf3->InputCoverage, input_count, HB_Coverage ) ) 4800 goto Fail4; 4801 4802 i = ccpf3->InputCoverage; 4803 4804 for ( ni = 0; ni < input_count; ni++ ) 4805 { 4806 if ( ACCESS_Frame( 2L ) ) 4807 goto Fail3; 4808 4809 new_offset = GET_UShort() + base_offset; 4810 4811 FORGET_Frame(); 4812 4813 cur_offset = FILE_Pos(); 4814 if ( FILE_Seek( new_offset ) || 4815 ( error = _HB_OPEN_Load_Coverage( &i[ni], stream ) ) != HB_Err_Ok ) 4816 goto Fail3; 4817 (void)FILE_Seek( cur_offset ); 4818 } 4819 4820 if ( ACCESS_Frame( 2L ) ) 4821 goto Fail3; 4822 4823 ccpf3->LookaheadGlyphCount = GET_UShort(); 4824 4825 FORGET_Frame(); 4826 4827 ccpf3->LookaheadCoverage = NULL; 4828 4829 lookahead_count = ccpf3->LookaheadGlyphCount; 4830 4831 if ( ALLOC_ARRAY( ccpf3->LookaheadCoverage, lookahead_count, 4832 HB_Coverage ) ) 4833 goto Fail3; 4834 4835 l = ccpf3->LookaheadCoverage; 4836 4837 for ( nl = 0; nl < lookahead_count; nl++ ) 4838 { 4839 if ( ACCESS_Frame( 2L ) ) 4840 goto Fail2; 4841 4842 new_offset = GET_UShort() + base_offset; 4843 4844 FORGET_Frame(); 4845 4846 cur_offset = FILE_Pos(); 4847 if ( FILE_Seek( new_offset ) || 4848 ( error = _HB_OPEN_Load_Coverage( &l[nl], stream ) ) != HB_Err_Ok ) 4849 goto Fail2; 4850 (void)FILE_Seek( cur_offset ); 4851 } 4852 4853 if ( ACCESS_Frame( 2L ) ) 4854 goto Fail2; 4855 4856 ccpf3->PosCount = GET_UShort(); 4857 4858 FORGET_Frame(); 4859 4860 ccpf3->PosLookupRecord = NULL; 4861 4862 count = ccpf3->PosCount; 4863 4864 if ( ALLOC_ARRAY( ccpf3->PosLookupRecord, count, HB_PosLookupRecord ) ) 4865 goto Fail2; 4866 4867 plr = ccpf3->PosLookupRecord; 4868 4869 if ( ACCESS_Frame( count * 4L ) ) 4870 goto Fail1; 4871 4872 for ( n = 0; n < count; n++ ) 4873 { 4874 plr[n].SequenceIndex = GET_UShort(); 4875 plr[n].LookupListIndex = GET_UShort(); 4876 } 4877 4878 FORGET_Frame(); 4879 4880 return HB_Err_Ok; 4881 4882 Fail1: 4883 FREE( plr ); 4884 4885 Fail2: 4886 for ( m = 0; m < nl; m++ ) 4887 _HB_OPEN_Free_Coverage( &l[m] ); 4888 4889 FREE( l ); 4890 4891 Fail3: 4892 for ( m = 0; m < ni; m++ ) 4893 _HB_OPEN_Free_Coverage( &i[m] ); 4894 4895 FREE( i ); 4896 4897 Fail4: 4898 for ( m = 0; m < nb; m++ ) 4899 _HB_OPEN_Free_Coverage( &b[m] ); 4900 4901 FREE( b ); 4902 return error; 4903 } 4904 4905 4906 static void Free_ChainContextPos3( HB_ChainContextPosFormat3* ccpf3 ) 4907 { 4908 HB_UShort n, count; 4909 4910 HB_Coverage* c; 4911 4912 4913 FREE( ccpf3->PosLookupRecord ); 4914 4915 if ( ccpf3->LookaheadCoverage ) 4916 { 4917 count = ccpf3->LookaheadGlyphCount; 4918 c = ccpf3->LookaheadCoverage; 4919 4920 for ( n = 0; n < count; n++ ) 4921 _HB_OPEN_Free_Coverage( &c[n] ); 4922 4923 FREE( c ); 4924 } 4925 4926 if ( ccpf3->InputCoverage ) 4927 { 4928 count = ccpf3->InputGlyphCount; 4929 c = ccpf3->InputCoverage; 4930 4931 for ( n = 0; n < count; n++ ) 4932 _HB_OPEN_Free_Coverage( &c[n] ); 4933 4934 FREE( c ); 4935 } 4936 4937 if ( ccpf3->BacktrackCoverage ) 4938 { 4939 count = ccpf3->BacktrackGlyphCount; 4940 c = ccpf3->BacktrackCoverage; 4941 4942 for ( n = 0; n < count; n++ ) 4943 _HB_OPEN_Free_Coverage( &c[n] ); 4944 4945 FREE( c ); 4946 } 4947 } 4948 4949 4950 /* ChainContextPos */ 4951 4952 static HB_Error Load_ChainContextPos( HB_GPOS_SubTable* st, 4953 HB_Stream stream ) 4954 { 4955 HB_Error error; 4956 HB_ChainContextPos* ccp = &st->chain; 4957 4958 4959 if ( ACCESS_Frame( 2L ) ) 4960 return error; 4961 4962 ccp->PosFormat = GET_UShort(); 4963 4964 FORGET_Frame(); 4965 4966 switch ( ccp->PosFormat ) 4967 { 4968 case 1: 4969 return Load_ChainContextPos1( &ccp->ccpf.ccpf1, stream ); 4970 4971 case 2: 4972 return Load_ChainContextPos2( &ccp->ccpf.ccpf2, stream ); 4973 4974 case 3: 4975 return Load_ChainContextPos3( &ccp->ccpf.ccpf3, stream ); 4976 4977 default: 4978 return ERR(HB_Err_Invalid_SubTable_Format); 4979 } 4980 4981 return HB_Err_Ok; /* never reached */ 4982 } 4983 4984 4985 static void Free_ChainContextPos( HB_GPOS_SubTable* st ) 4986 { 4987 HB_ChainContextPos* ccp = &st->chain; 4988 4989 switch ( ccp->PosFormat ) 4990 { 4991 case 1: Free_ChainContextPos1( &ccp->ccpf.ccpf1 ); break; 4992 case 2: Free_ChainContextPos2( &ccp->ccpf.ccpf2 ); break; 4993 case 3: Free_ChainContextPos3( &ccp->ccpf.ccpf3 ); break; 4994 default: break; 4995 } 4996 } 4997 4998 4999 static HB_Error Lookup_ChainContextPos1( 5000 GPOS_Instance* gpi, 5001 HB_ChainContextPosFormat1* ccpf1, 5002 HB_Buffer buffer, 5003 HB_UShort flags, 5004 HB_UShort context_length, 5005 int nesting_level ) 5006 { 5007 HB_UShort index, property; 5008 HB_UShort i, j, k, num_cpr; 5009 HB_UShort bgc, igc, lgc; 5010 HB_Error error; 5011 HB_GPOSHeader* gpos = gpi->gpos; 5012 5013 HB_ChainPosRule* cpr; 5014 HB_ChainPosRule curr_cpr; 5015 HB_GDEFHeader* gdef; 5016 5017 5018 gdef = gpos->gdef; 5019 5020 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) 5021 return error; 5022 5023 error = _HB_OPEN_Coverage_Index( &ccpf1->Coverage, IN_CURGLYPH(), &index ); 5024 if ( error ) 5025 return error; 5026 5027 cpr = ccpf1->ChainPosRuleSet[index].ChainPosRule; 5028 num_cpr = ccpf1->ChainPosRuleSet[index].ChainPosRuleCount; 5029 5030 for ( k = 0; k < num_cpr; k++ ) 5031 { 5032 curr_cpr = cpr[k]; 5033 bgc = curr_cpr.BacktrackGlyphCount; 5034 igc = curr_cpr.InputGlyphCount; 5035 lgc = curr_cpr.LookaheadGlyphCount; 5036 5037 if ( context_length != 0xFFFF && context_length < igc ) 5038 goto next_chainposrule; 5039 5040 /* check whether context is too long; it is a first guess only */ 5041 5042 if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length ) 5043 goto next_chainposrule; 5044 5045 if ( bgc ) 5046 { 5047 /* Since we don't know in advance the number of glyphs to inspect, 5048 we search backwards for matches in the backtrack glyph array */ 5049 5050 for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- ) 5051 { 5052 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) 5053 { 5054 if ( error && error != HB_Err_Not_Covered ) 5055 return error; 5056 5057 if ( j + 1 == bgc - i ) 5058 goto next_chainposrule; 5059 j--; 5060 } 5061 5062 /* In OpenType 1.3, it is undefined whether the offsets of 5063 backtrack glyphs is in logical order or not. Version 1.4 5064 will clarify this: 5065 5066 Logical order - a b c d e f g h i j 5067 i 5068 Input offsets - 0 1 5069 Backtrack offsets - 3 2 1 0 5070 Lookahead offsets - 0 1 2 3 */ 5071 5072 if ( IN_GLYPH( j ) != curr_cpr.Backtrack[i] ) 5073 goto next_chainposrule; 5074 } 5075 } 5076 5077 /* Start at 1 because [0] is implied */ 5078 5079 for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ ) 5080 { 5081 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) 5082 { 5083 if ( error && error != HB_Err_Not_Covered ) 5084 return error; 5085 5086 if ( j + igc - i + lgc == (HB_Int)buffer->in_length ) 5087 goto next_chainposrule; 5088 j++; 5089 } 5090 5091 if ( IN_GLYPH( j ) != curr_cpr.Input[i - 1] ) 5092 goto next_chainposrule; 5093 } 5094 5095 /* we are starting to check for lookahead glyphs right after the 5096 last context glyph */ 5097 5098 for ( i = 0; i < lgc; i++, j++ ) 5099 { 5100 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) 5101 { 5102 if ( error && error != HB_Err_Not_Covered ) 5103 return error; 5104 5105 if ( j + lgc - i == (HB_Int)buffer->in_length ) 5106 goto next_chainposrule; 5107 j++; 5108 } 5109 5110 if ( IN_GLYPH( j ) != curr_cpr.Lookahead[i] ) 5111 goto next_chainposrule; 5112 } 5113 5114 return Do_ContextPos( gpi, igc, 5115 curr_cpr.PosCount, 5116 curr_cpr.PosLookupRecord, 5117 buffer, 5118 nesting_level ); 5119 5120 next_chainposrule: 5121 ; 5122 } 5123 5124 return HB_Err_Not_Covered; 5125 } 5126 5127 5128 static HB_Error Lookup_ChainContextPos2( 5129 GPOS_Instance* gpi, 5130 HB_ChainContextPosFormat2* ccpf2, 5131 HB_Buffer buffer, 5132 HB_UShort flags, 5133 HB_UShort context_length, 5134 int nesting_level ) 5135 { 5136 HB_UShort index, property; 5137 HB_Error error; 5138 HB_UShort i, j, k; 5139 HB_UShort bgc, igc, lgc; 5140 HB_UShort known_backtrack_classes, 5141 known_input_classes, 5142 known_lookahead_classes; 5143 5144 HB_UShort* backtrack_classes; 5145 HB_UShort* input_classes; 5146 HB_UShort* lookahead_classes; 5147 5148 HB_UShort* bc; 5149 HB_UShort* ic; 5150 HB_UShort* lc; 5151 HB_GPOSHeader* gpos = gpi->gpos; 5152 5153 HB_ChainPosClassSet* cpcs; 5154 HB_ChainPosClassRule cpcr; 5155 HB_GDEFHeader* gdef; 5156 5157 5158 gdef = gpos->gdef; 5159 5160 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) 5161 return error; 5162 5163 /* Note: The coverage table in format 2 doesn't give an index into 5164 anything. It just lets us know whether or not we need to 5165 do any lookup at all. */ 5166 5167 error = _HB_OPEN_Coverage_Index( &ccpf2->Coverage, IN_CURGLYPH(), &index ); 5168 if ( error ) 5169 return error; 5170 5171 if ( ALLOC_ARRAY( backtrack_classes, ccpf2->MaxBacktrackLength, HB_UShort ) ) 5172 return error; 5173 known_backtrack_classes = 0; 5174 5175 if (ccpf2->MaxInputLength < 1) 5176 return HB_Err_Not_Covered; 5177 5178 if ( ALLOC_ARRAY( input_classes, ccpf2->MaxInputLength, HB_UShort ) ) 5179 goto End3; 5180 known_input_classes = 1; 5181 5182 if ( ALLOC_ARRAY( lookahead_classes, ccpf2->MaxLookaheadLength, HB_UShort ) ) 5183 goto End2; 5184 known_lookahead_classes = 0; 5185 5186 error = _HB_OPEN_Get_Class( &ccpf2->InputClassDef, IN_CURGLYPH(), 5187 &input_classes[0], NULL ); 5188 if ( error && error != HB_Err_Not_Covered ) 5189 goto End1; 5190 5191 cpcs = &ccpf2->ChainPosClassSet[input_classes[0]]; 5192 if ( !cpcs ) 5193 { 5194 error = ERR(HB_Err_Invalid_SubTable); 5195 goto End1; 5196 } 5197 5198 for ( k = 0; k < cpcs->ChainPosClassRuleCount; k++ ) 5199 { 5200 cpcr = cpcs->ChainPosClassRule[k]; 5201 bgc = cpcr.BacktrackGlyphCount; 5202 igc = cpcr.InputGlyphCount; 5203 lgc = cpcr.LookaheadGlyphCount; 5204 5205 if ( context_length != 0xFFFF && context_length < igc ) 5206 goto next_chainposclassrule; 5207 5208 /* check whether context is too long; it is a first guess only */ 5209 5210 if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length ) 5211 goto next_chainposclassrule; 5212 5213 if ( bgc ) 5214 { 5215 /* Since we don't know in advance the number of glyphs to inspect, 5216 we search backwards for matches in the backtrack glyph array. 5217 Note that `known_backtrack_classes' starts at index 0. */ 5218 5219 bc = cpcr.Backtrack; 5220 5221 for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- ) 5222 { 5223 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) 5224 { 5225 if ( error && error != HB_Err_Not_Covered ) 5226 goto End1; 5227 5228 if ( j + 1 == bgc - i ) 5229 goto next_chainposclassrule; 5230 j++; 5231 } 5232 5233 if ( i >= known_backtrack_classes ) 5234 { 5235 /* Keeps us from having to do this for each rule */ 5236 5237 error = _HB_OPEN_Get_Class( &ccpf2->BacktrackClassDef, IN_GLYPH( j ), 5238 &backtrack_classes[i], NULL ); 5239 if ( error && error != HB_Err_Not_Covered ) 5240 goto End1; 5241 known_backtrack_classes = i; 5242 } 5243 5244 if ( bc[i] != backtrack_classes[i] ) 5245 goto next_chainposclassrule; 5246 } 5247 } 5248 5249 ic = cpcr.Input; 5250 5251 /* Start at 1 because [0] is implied */ 5252 5253 for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ ) 5254 { 5255 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) 5256 { 5257 if ( error && error != HB_Err_Not_Covered ) 5258 goto End1; 5259 5260 if ( j + igc - i + lgc == (HB_Int)buffer->in_length ) 5261 goto next_chainposclassrule; 5262 j++; 5263 } 5264 5265 if ( i >= known_input_classes ) 5266 { 5267 error = _HB_OPEN_Get_Class( &ccpf2->InputClassDef, IN_GLYPH( j ), 5268 &input_classes[i], NULL ); 5269 if ( error && error != HB_Err_Not_Covered ) 5270 goto End1; 5271 known_input_classes = i; 5272 } 5273 5274 if ( ic[i - 1] != input_classes[i] ) 5275 goto next_chainposclassrule; 5276 } 5277 5278 /* we are starting to check for lookahead glyphs right after the 5279 last context glyph */ 5280 5281 lc = cpcr.Lookahead; 5282 5283 for ( i = 0; i < lgc; i++, j++ ) 5284 { 5285 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) 5286 { 5287 if ( error && error != HB_Err_Not_Covered ) 5288 goto End1; 5289 5290 if ( j + lgc - i == (HB_Int)buffer->in_length ) 5291 goto next_chainposclassrule; 5292 j++; 5293 } 5294 5295 if ( i >= known_lookahead_classes ) 5296 { 5297 error = _HB_OPEN_Get_Class( &ccpf2->LookaheadClassDef, IN_GLYPH( j ), 5298 &lookahead_classes[i], NULL ); 5299 if ( error && error != HB_Err_Not_Covered ) 5300 goto End1; 5301 known_lookahead_classes = i; 5302 } 5303 5304 if ( lc[i] != lookahead_classes[i] ) 5305 goto next_chainposclassrule; 5306 } 5307 5308 error = Do_ContextPos( gpi, igc, 5309 cpcr.PosCount, 5310 cpcr.PosLookupRecord, 5311 buffer, 5312 nesting_level ); 5313 goto End1; 5314 5315 next_chainposclassrule: 5316 ; 5317 } 5318 5319 error = HB_Err_Not_Covered; 5320 5321 End1: 5322 FREE( lookahead_classes ); 5323 5324 End2: 5325 FREE( input_classes ); 5326 5327 End3: 5328 FREE( backtrack_classes ); 5329 return error; 5330 } 5331 5332 5333 static HB_Error Lookup_ChainContextPos3( 5334 GPOS_Instance* gpi, 5335 HB_ChainContextPosFormat3* ccpf3, 5336 HB_Buffer buffer, 5337 HB_UShort flags, 5338 HB_UShort context_length, 5339 int nesting_level ) 5340 { 5341 HB_UShort index, i, j, property; 5342 HB_UShort bgc, igc, lgc; 5343 HB_Error error; 5344 HB_GPOSHeader* gpos = gpi->gpos; 5345 5346 HB_Coverage* bc; 5347 HB_Coverage* ic; 5348 HB_Coverage* lc; 5349 HB_GDEFHeader* gdef; 5350 5351 5352 gdef = gpos->gdef; 5353 5354 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) 5355 return error; 5356 5357 bgc = ccpf3->BacktrackGlyphCount; 5358 igc = ccpf3->InputGlyphCount; 5359 lgc = ccpf3->LookaheadGlyphCount; 5360 5361 if ( context_length != 0xFFFF && context_length < igc ) 5362 return HB_Err_Not_Covered; 5363 5364 /* check whether context is too long; it is a first guess only */ 5365 5366 if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length ) 5367 return HB_Err_Not_Covered; 5368 5369 if ( bgc ) 5370 { 5371 /* Since we don't know in advance the number of glyphs to inspect, 5372 we search backwards for matches in the backtrack glyph array */ 5373 5374 bc = ccpf3->BacktrackCoverage; 5375 5376 for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- ) 5377 { 5378 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) 5379 { 5380 if ( error && error != HB_Err_Not_Covered ) 5381 return error; 5382 5383 if ( j + 1 == bgc - i ) 5384 return HB_Err_Not_Covered; 5385 j--; 5386 } 5387 5388 error = _HB_OPEN_Coverage_Index( &bc[i], IN_GLYPH( j ), &index ); 5389 if ( error ) 5390 return error; 5391 } 5392 } 5393 5394 ic = ccpf3->InputCoverage; 5395 5396 for ( i = 0, j = buffer->in_pos; i < igc; i++, j++ ) 5397 { 5398 /* We already called CHECK_Property for IN_GLYPH ( buffer->in_pos ) */ 5399 while ( j > buffer->in_pos && CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) 5400 { 5401 if ( error && error != HB_Err_Not_Covered ) 5402 return error; 5403 5404 if ( j + igc - i + lgc == (HB_Int)buffer->in_length ) 5405 return HB_Err_Not_Covered; 5406 j++; 5407 } 5408 5409 error = _HB_OPEN_Coverage_Index( &ic[i], IN_GLYPH( j ), &index ); 5410 if ( error ) 5411 return error; 5412 } 5413 5414 /* we are starting to check for lookahead glyphs right after the 5415 last context glyph */ 5416 5417 lc = ccpf3->LookaheadCoverage; 5418 5419 for ( i = 0; i < lgc; i++, j++ ) 5420 { 5421 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) 5422 { 5423 if ( error && error != HB_Err_Not_Covered ) 5424 return error; 5425 5426 if ( j + lgc - i == (HB_Int)buffer->in_length ) 5427 return HB_Err_Not_Covered; 5428 j++; 5429 } 5430 5431 error = _HB_OPEN_Coverage_Index( &lc[i], IN_GLYPH( j ), &index ); 5432 if ( error ) 5433 return error; 5434 } 5435 5436 return Do_ContextPos( gpi, igc, 5437 ccpf3->PosCount, 5438 ccpf3->PosLookupRecord, 5439 buffer, 5440 nesting_level ); 5441 } 5442 5443 5444 static HB_Error Lookup_ChainContextPos( 5445 GPOS_Instance* gpi, 5446 HB_GPOS_SubTable* st, 5447 HB_Buffer buffer, 5448 HB_UShort flags, 5449 HB_UShort context_length, 5450 int nesting_level ) 5451 { 5452 HB_ChainContextPos* ccp = &st->chain; 5453 5454 switch ( ccp->PosFormat ) 5455 { 5456 case 1: 5457 return Lookup_ChainContextPos1( gpi, &ccp->ccpf.ccpf1, buffer, 5458 flags, context_length, 5459 nesting_level ); 5460 5461 case 2: 5462 return Lookup_ChainContextPos2( gpi, &ccp->ccpf.ccpf2, buffer, 5463 flags, context_length, 5464 nesting_level ); 5465 5466 case 3: 5467 return Lookup_ChainContextPos3( gpi, &ccp->ccpf.ccpf3, buffer, 5468 flags, context_length, 5469 nesting_level ); 5470 5471 default: 5472 return ERR(HB_Err_Invalid_SubTable_Format); 5473 } 5474 5475 return HB_Err_Ok; /* never reached */ 5476 } 5477 5478 5479 5480 /*********** 5481 * GPOS API 5482 ***********/ 5483 5484 5485 5486 HB_Error HB_GPOS_Select_Script( HB_GPOSHeader* gpos, 5487 HB_UInt script_tag, 5488 HB_UShort* script_index ) 5489 { 5490 HB_UShort n; 5491 5492 HB_ScriptList* sl; 5493 HB_ScriptRecord* sr; 5494 5495 5496 if ( !gpos || !script_index ) 5497 return ERR(HB_Err_Invalid_Argument); 5498 5499 sl = &gpos->ScriptList; 5500 sr = sl->ScriptRecord; 5501 5502 for ( n = 0; n < sl->ScriptCount; n++ ) 5503 if ( script_tag == sr[n].ScriptTag ) 5504 { 5505 *script_index = n; 5506 5507 return HB_Err_Ok; 5508 } 5509 5510 return HB_Err_Not_Covered; 5511 } 5512 5513 5514 5515 HB_Error HB_GPOS_Select_Language( HB_GPOSHeader* gpos, 5516 HB_UInt language_tag, 5517 HB_UShort script_index, 5518 HB_UShort* language_index, 5519 HB_UShort* req_feature_index ) 5520 { 5521 HB_UShort n; 5522 5523 HB_ScriptList* sl; 5524 HB_ScriptRecord* sr; 5525 HB_ScriptTable* s; 5526 HB_LangSysRecord* lsr; 5527 5528 5529 if ( !gpos || !language_index || !req_feature_index ) 5530 return ERR(HB_Err_Invalid_Argument); 5531 5532 sl = &gpos->ScriptList; 5533 sr = sl->ScriptRecord; 5534 5535 if ( script_index >= sl->ScriptCount ) 5536 return ERR(HB_Err_Invalid_Argument); 5537 5538 s = &sr[script_index].Script; 5539 lsr = s->LangSysRecord; 5540 5541 for ( n = 0; n < s->LangSysCount; n++ ) 5542 if ( language_tag == lsr[n].LangSysTag ) 5543 { 5544 *language_index = n; 5545 *req_feature_index = lsr[n].LangSys.ReqFeatureIndex; 5546 5547 return HB_Err_Ok; 5548 } 5549 5550 return HB_Err_Not_Covered; 5551 } 5552 5553 5554 /* selecting 0xFFFF for language_index asks for the values of the 5555 default language (DefaultLangSys) */ 5556 5557 5558 HB_Error HB_GPOS_Select_Feature( HB_GPOSHeader* gpos, 5559 HB_UInt feature_tag, 5560 HB_UShort script_index, 5561 HB_UShort language_index, 5562 HB_UShort* feature_index ) 5563 { 5564 HB_UShort n; 5565 5566 HB_ScriptList* sl; 5567 HB_ScriptRecord* sr; 5568 HB_ScriptTable* s; 5569 HB_LangSysRecord* lsr; 5570 HB_LangSys* ls; 5571 HB_UShort* fi; 5572 5573 HB_FeatureList* fl; 5574 HB_FeatureRecord* fr; 5575 5576 5577 if ( !gpos || !feature_index ) 5578 return ERR(HB_Err_Invalid_Argument); 5579 5580 sl = &gpos->ScriptList; 5581 sr = sl->ScriptRecord; 5582 5583 fl = &gpos->FeatureList; 5584 fr = fl->FeatureRecord; 5585 5586 if ( script_index >= sl->ScriptCount ) 5587 return ERR(HB_Err_Invalid_Argument); 5588 5589 s = &sr[script_index].Script; 5590 lsr = s->LangSysRecord; 5591 5592 if ( language_index == 0xFFFF ) 5593 ls = &s->DefaultLangSys; 5594 else 5595 { 5596 if ( language_index >= s->LangSysCount ) 5597 return ERR(HB_Err_Invalid_Argument); 5598 5599 ls = &lsr[language_index].LangSys; 5600 } 5601 5602 fi = ls->FeatureIndex; 5603 5604 for ( n = 0; n < ls->FeatureCount; n++ ) 5605 { 5606 if ( fi[n] >= fl->FeatureCount ) 5607 return ERR(HB_Err_Invalid_SubTable_Format); 5608 5609 if ( feature_tag == fr[fi[n]].FeatureTag ) 5610 { 5611 *feature_index = fi[n]; 5612 5613 return HB_Err_Ok; 5614 } 5615 } 5616 5617 return HB_Err_Not_Covered; 5618 } 5619 5620 5621 /* The next three functions return a null-terminated list */ 5622 5623 5624 HB_Error HB_GPOS_Query_Scripts( HB_GPOSHeader* gpos, 5625 HB_UInt** script_tag_list ) 5626 { 5627 HB_Error error; 5628 HB_UShort n; 5629 HB_UInt* stl; 5630 5631 HB_ScriptList* sl; 5632 HB_ScriptRecord* sr; 5633 5634 5635 if ( !gpos || !script_tag_list ) 5636 return ERR(HB_Err_Invalid_Argument); 5637 5638 sl = &gpos->ScriptList; 5639 sr = sl->ScriptRecord; 5640 5641 if ( ALLOC_ARRAY( stl, sl->ScriptCount + 1, HB_UInt ) ) 5642 return error; 5643 5644 for ( n = 0; n < sl->ScriptCount; n++ ) 5645 stl[n] = sr[n].ScriptTag; 5646 stl[n] = 0; 5647 5648 *script_tag_list = stl; 5649 5650 return HB_Err_Ok; 5651 } 5652 5653 5654 5655 HB_Error HB_GPOS_Query_Languages( HB_GPOSHeader* gpos, 5656 HB_UShort script_index, 5657 HB_UInt** language_tag_list ) 5658 { 5659 HB_Error error; 5660 HB_UShort n; 5661 HB_UInt* ltl; 5662 5663 HB_ScriptList* sl; 5664 HB_ScriptRecord* sr; 5665 HB_ScriptTable* s; 5666 HB_LangSysRecord* lsr; 5667 5668 5669 if ( !gpos || !language_tag_list ) 5670 return ERR(HB_Err_Invalid_Argument); 5671 5672 sl = &gpos->ScriptList; 5673 sr = sl->ScriptRecord; 5674 5675 if ( script_index >= sl->ScriptCount ) 5676 return ERR(HB_Err_Invalid_Argument); 5677 5678 s = &sr[script_index].Script; 5679 lsr = s->LangSysRecord; 5680 5681 if ( ALLOC_ARRAY( ltl, s->LangSysCount + 1, HB_UInt ) ) 5682 return error; 5683 5684 for ( n = 0; n < s->LangSysCount; n++ ) 5685 ltl[n] = lsr[n].LangSysTag; 5686 ltl[n] = 0; 5687 5688 *language_tag_list = ltl; 5689 5690 return HB_Err_Ok; 5691 } 5692 5693 5694 /* selecting 0xFFFF for language_index asks for the values of the 5695 default language (DefaultLangSys) */ 5696 5697 5698 HB_Error HB_GPOS_Query_Features( HB_GPOSHeader* gpos, 5699 HB_UShort script_index, 5700 HB_UShort language_index, 5701 HB_UInt** feature_tag_list ) 5702 { 5703 HB_UShort n; 5704 HB_Error error; 5705 HB_UInt* ftl; 5706 5707 HB_ScriptList* sl; 5708 HB_ScriptRecord* sr; 5709 HB_ScriptTable* s; 5710 HB_LangSysRecord* lsr; 5711 HB_LangSys* ls; 5712 HB_UShort* fi; 5713 5714 HB_FeatureList* fl; 5715 HB_FeatureRecord* fr; 5716 5717 5718 if ( !gpos || !feature_tag_list ) 5719 return ERR(HB_Err_Invalid_Argument); 5720 5721 sl = &gpos->ScriptList; 5722 sr = sl->ScriptRecord; 5723 5724 fl = &gpos->FeatureList; 5725 fr = fl->FeatureRecord; 5726 5727 if ( script_index >= sl->ScriptCount ) 5728 return ERR(HB_Err_Invalid_Argument); 5729 5730 s = &sr[script_index].Script; 5731 lsr = s->LangSysRecord; 5732 5733 if ( language_index == 0xFFFF ) 5734 ls = &s->DefaultLangSys; 5735 else 5736 { 5737 if ( language_index >= s->LangSysCount ) 5738 return ERR(HB_Err_Invalid_Argument); 5739 5740 ls = &lsr[language_index].LangSys; 5741 } 5742 5743 fi = ls->FeatureIndex; 5744 5745 if ( ALLOC_ARRAY( ftl, ls->FeatureCount + 1, HB_UInt ) ) 5746 return error; 5747 5748 for ( n = 0; n < ls->FeatureCount; n++ ) 5749 { 5750 if ( fi[n] >= fl->FeatureCount ) 5751 { 5752 FREE( ftl ); 5753 return ERR(HB_Err_Invalid_SubTable_Format); 5754 } 5755 ftl[n] = fr[fi[n]].FeatureTag; 5756 } 5757 ftl[n] = 0; 5758 5759 *feature_tag_list = ftl; 5760 5761 return HB_Err_Ok; 5762 } 5763 5764 5765 /* Do an individual subtable lookup. Returns HB_Err_Ok if positioning 5766 has been done, or HB_Err_Not_Covered if not. */ 5767 static HB_Error GPOS_Do_Glyph_Lookup( GPOS_Instance* gpi, 5768 HB_UShort lookup_index, 5769 HB_Buffer buffer, 5770 HB_UShort context_length, 5771 int nesting_level ) 5772 { 5773 HB_Error error = HB_Err_Not_Covered; 5774 HB_UShort i, flags, lookup_count; 5775 HB_GPOSHeader* gpos = gpi->gpos; 5776 HB_Lookup* lo; 5777 int lookup_type; 5778 5779 5780 nesting_level++; 5781 5782 if ( nesting_level > HB_MAX_NESTING_LEVEL ) 5783 return ERR(HB_Err_Not_Covered); /* ERR() call intended */ 5784 5785 lookup_count = gpos->LookupList.LookupCount; 5786 if (lookup_index >= lookup_count) 5787 return error; 5788 5789 lo = &gpos->LookupList.Lookup[lookup_index]; 5790 flags = lo->LookupFlag; 5791 lookup_type = lo->LookupType; 5792 5793 for ( i = 0; i < lo->SubTableCount; i++ ) 5794 { 5795 HB_GPOS_SubTable *st = &lo->SubTable[i].st.gpos; 5796 5797 switch (lookup_type) { 5798 case HB_GPOS_LOOKUP_SINGLE: 5799 error = Lookup_SinglePos ( gpi, st, buffer, flags, context_length, nesting_level ); break; 5800 case HB_GPOS_LOOKUP_PAIR: 5801 error = Lookup_PairPos ( gpi, st, buffer, flags, context_length, nesting_level ); break; 5802 case HB_GPOS_LOOKUP_CURSIVE: 5803 error = Lookup_CursivePos ( gpi, st, buffer, flags, context_length, nesting_level ); break; 5804 case HB_GPOS_LOOKUP_MARKBASE: 5805 error = Lookup_MarkBasePos ( gpi, st, buffer, flags, context_length, nesting_level ); break; 5806 case HB_GPOS_LOOKUP_MARKLIG: 5807 error = Lookup_MarkLigPos ( gpi, st, buffer, flags, context_length, nesting_level ); break; 5808 case HB_GPOS_LOOKUP_MARKMARK: 5809 error = Lookup_MarkMarkPos ( gpi, st, buffer, flags, context_length, nesting_level ); break; 5810 case HB_GPOS_LOOKUP_CONTEXT: 5811 error = Lookup_ContextPos ( gpi, st, buffer, flags, context_length, nesting_level ); break; 5812 case HB_GPOS_LOOKUP_CHAIN: 5813 error = Lookup_ChainContextPos ( gpi, st, buffer, flags, context_length, nesting_level ); break; 5814 /*case HB_GPOS_LOOKUP_EXTENSION: 5815 error = Lookup_ExtensionPos ( gpi, st, buffer, flags, context_length, nesting_level ); break;*/ 5816 default: 5817 error = HB_Err_Not_Covered; 5818 } 5819 5820 /* Check whether we have a successful positioning or an error other 5821 than HB_Err_Not_Covered */ 5822 if ( error != HB_Err_Not_Covered ) 5823 return error; 5824 } 5825 5826 return HB_Err_Not_Covered; 5827 } 5828 5829 5830 HB_INTERNAL HB_Error 5831 _HB_GPOS_Load_SubTable( HB_GPOS_SubTable* st, 5832 HB_Stream stream, 5833 HB_UShort lookup_type ) 5834 { 5835 switch ( lookup_type ) { 5836 case HB_GPOS_LOOKUP_SINGLE: return Load_SinglePos ( st, stream ); 5837 case HB_GPOS_LOOKUP_PAIR: return Load_PairPos ( st, stream ); 5838 case HB_GPOS_LOOKUP_CURSIVE: return Load_CursivePos ( st, stream ); 5839 case HB_GPOS_LOOKUP_MARKBASE: return Load_MarkBasePos ( st, stream ); 5840 case HB_GPOS_LOOKUP_MARKLIG: return Load_MarkLigPos ( st, stream ); 5841 case HB_GPOS_LOOKUP_MARKMARK: return Load_MarkMarkPos ( st, stream ); 5842 case HB_GPOS_LOOKUP_CONTEXT: return Load_ContextPos ( st, stream ); 5843 case HB_GPOS_LOOKUP_CHAIN: return Load_ChainContextPos ( st, stream ); 5844 /*case HB_GPOS_LOOKUP_EXTENSION: return Load_ExtensionPos ( st, stream );*/ 5845 default: return ERR(HB_Err_Invalid_SubTable_Format); 5846 } 5847 } 5848 5849 5850 HB_INTERNAL void 5851 _HB_GPOS_Free_SubTable( HB_GPOS_SubTable* st, 5852 HB_UShort lookup_type ) 5853 { 5854 switch ( lookup_type ) { 5855 case HB_GPOS_LOOKUP_SINGLE: Free_SinglePos ( st ); return; 5856 case HB_GPOS_LOOKUP_PAIR: Free_PairPos ( st ); return; 5857 case HB_GPOS_LOOKUP_CURSIVE: Free_CursivePos ( st ); return; 5858 case HB_GPOS_LOOKUP_MARKBASE: Free_MarkBasePos ( st ); return; 5859 case HB_GPOS_LOOKUP_MARKLIG: Free_MarkLigPos ( st ); return; 5860 case HB_GPOS_LOOKUP_MARKMARK: Free_MarkMarkPos ( st ); return; 5861 case HB_GPOS_LOOKUP_CONTEXT: Free_ContextPos ( st ); return; 5862 case HB_GPOS_LOOKUP_CHAIN: Free_ChainContextPos ( st ); return; 5863 /*case HB_GPOS_LOOKUP_EXTENSION: Free_ExtensionPos ( st ); return;*/ 5864 default: return; 5865 } 5866 } 5867 5868 5869 /* apply one lookup to the input string object */ 5870 5871 static HB_Error GPOS_Do_String_Lookup( GPOS_Instance* gpi, 5872 HB_UShort lookup_index, 5873 HB_Buffer buffer ) 5874 { 5875 HB_Error error, retError = HB_Err_Not_Covered; 5876 HB_GPOSHeader* gpos = gpi->gpos; 5877 5878 HB_UInt* properties = gpos->LookupList.Properties; 5879 5880 const int nesting_level = 0; 5881 /* 0xFFFF indicates that we don't have a context length yet */ 5882 const HB_UShort context_length = 0xFFFF; 5883 5884 5885 gpi->last = 0xFFFF; /* no last valid glyph for cursive pos. */ 5886 5887 buffer->in_pos = 0; 5888 while ( buffer->in_pos < buffer->in_length ) 5889 { 5890 if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] ) 5891 { 5892 /* Note that the connection between mark and base glyphs hold 5893 exactly one (string) lookup. For example, it would be possible 5894 that in the first lookup, mark glyph X is attached to base 5895 glyph A, and in the next lookup it is attached to base glyph B. 5896 It is up to the font designer to provide meaningful lookups and 5897 lookup order. */ 5898 5899 error = GPOS_Do_Glyph_Lookup( gpi, lookup_index, buffer, context_length, nesting_level ); 5900 if ( error && error != HB_Err_Not_Covered ) 5901 return error; 5902 } 5903 else 5904 { 5905 /* Contrary to properties defined in GDEF, user-defined properties 5906 will always stop a possible cursive positioning. */ 5907 gpi->last = 0xFFFF; 5908 5909 error = HB_Err_Not_Covered; 5910 } 5911 5912 if ( error == HB_Err_Not_Covered ) 5913 (buffer->in_pos)++; 5914 else 5915 retError = error; 5916 } 5917 5918 return retError; 5919 } 5920 5921 5922 static HB_Error Position_CursiveChain ( HB_Buffer buffer ) 5923 { 5924 HB_UInt i, j; 5925 HB_Position positions = buffer->positions; 5926 5927 /* First handle all left-to-right connections */ 5928 for (j = 0; j < buffer->in_length; j++) 5929 { 5930 if (positions[j].cursive_chain > 0) 5931 positions[j].y_pos += positions[j - positions[j].cursive_chain].y_pos; 5932 } 5933 5934 /* Then handle all right-to-left connections */ 5935 for (i = buffer->in_length; i > 0; i--) 5936 { 5937 j = i - 1; 5938 5939 if (positions[j].cursive_chain < 0) 5940 positions[j].y_pos += positions[j - positions[j].cursive_chain].y_pos; 5941 } 5942 5943 return HB_Err_Ok; 5944 } 5945 5946 5947 HB_Error HB_GPOS_Add_Feature( HB_GPOSHeader* gpos, 5948 HB_UShort feature_index, 5949 HB_UInt property ) 5950 { 5951 HB_UShort i; 5952 5953 HB_Feature feature; 5954 HB_UInt* properties; 5955 HB_UShort* index; 5956 HB_UShort lookup_count; 5957 5958 /* Each feature can only be added once */ 5959 5960 if ( !gpos || 5961 feature_index >= gpos->FeatureList.FeatureCount || 5962 gpos->FeatureList.ApplyCount == gpos->FeatureList.FeatureCount ) 5963 return ERR(HB_Err_Invalid_Argument); 5964 5965 gpos->FeatureList.ApplyOrder[gpos->FeatureList.ApplyCount++] = feature_index; 5966 5967 properties = gpos->LookupList.Properties; 5968 5969 feature = gpos->FeatureList.FeatureRecord[feature_index].Feature; 5970 index = feature.LookupListIndex; 5971 lookup_count = gpos->LookupList.LookupCount; 5972 5973 for ( i = 0; i < feature.LookupListCount; i++ ) 5974 { 5975 HB_UShort lookup_index = index[i]; 5976 if (lookup_index < lookup_count) 5977 properties[lookup_index] |= property; 5978 } 5979 5980 return HB_Err_Ok; 5981 } 5982 5983 5984 5985 HB_Error HB_GPOS_Clear_Features( HB_GPOSHeader* gpos ) 5986 { 5987 HB_UShort i; 5988 5989 HB_UInt* properties; 5990 5991 5992 if ( !gpos ) 5993 return ERR(HB_Err_Invalid_Argument); 5994 5995 gpos->FeatureList.ApplyCount = 0; 5996 5997 properties = gpos->LookupList.Properties; 5998 5999 for ( i = 0; i < gpos->LookupList.LookupCount; i++ ) 6000 properties[i] = 0; 6001 6002 return HB_Err_Ok; 6003 } 6004 6005 #ifdef HB_SUPPORT_MULTIPLE_MASTER 6006 HB_Error HB_GPOS_Register_MM_Function( HB_GPOSHeader* gpos, 6007 HB_MMFunction mmfunc, 6008 void* data ) 6009 { 6010 if ( !gpos ) 6011 return ERR(HB_Err_Invalid_Argument); 6012 6013 gpos->mmfunc = mmfunc; 6014 gpos->data = data; 6015 6016 return HB_Err_Ok; 6017 } 6018 #endif 6019 6020 /* If `dvi' is TRUE, glyph contour points for anchor points and device 6021 tables are ignored -- you will get device independent values. */ 6022 6023 6024 HB_Error HB_GPOS_Apply_String( HB_Font font, 6025 HB_GPOSHeader* gpos, 6026 HB_UShort load_flags, 6027 HB_Buffer buffer, 6028 HB_Bool dvi, 6029 HB_Bool r2l ) 6030 { 6031 HB_Error error, retError = HB_Err_Not_Covered; 6032 GPOS_Instance gpi; 6033 int i, j, lookup_count, num_features; 6034 6035 if ( !font || !gpos || !buffer ) 6036 return ERR(HB_Err_Invalid_Argument); 6037 6038 if ( buffer->in_length == 0 ) 6039 return HB_Err_Not_Covered; 6040 6041 gpi.font = font; 6042 gpi.gpos = gpos; 6043 gpi.load_flags = load_flags; 6044 gpi.r2l = r2l; 6045 gpi.dvi = dvi; 6046 6047 lookup_count = gpos->LookupList.LookupCount; 6048 num_features = gpos->FeatureList.ApplyCount; 6049 6050 if ( num_features ) 6051 { 6052 error = _hb_buffer_clear_positions( buffer ); 6053 if ( error ) 6054 return error; 6055 } 6056 6057 for ( i = 0; i < num_features; i++ ) 6058 { 6059 HB_UShort feature_index = gpos->FeatureList.ApplyOrder[i]; 6060 HB_Feature feature = gpos->FeatureList.FeatureRecord[feature_index].Feature; 6061 6062 for ( j = 0; j < feature.LookupListCount; j++ ) 6063 { 6064 HB_UShort lookup_index = feature.LookupListIndex[j]; 6065 6066 /* Skip nonexistant lookups */ 6067 if (lookup_index >= lookup_count) 6068 continue; 6069 6070 error = GPOS_Do_String_Lookup( &gpi, lookup_index, buffer ); 6071 if ( error ) 6072 { 6073 if ( error != HB_Err_Not_Covered ) 6074 return error; 6075 } 6076 else 6077 retError = error; 6078 } 6079 } 6080 6081 if ( num_features ) 6082 { 6083 error = Position_CursiveChain ( buffer ); 6084 if ( error ) 6085 return error; 6086 } 6087 6088 return retError; 6089 } 6090 6091 /* END */ 6092