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 if ( i > buffer->in_pos ) 3016 return HB_Err_Not_Covered; 3017 3018 error = _HB_OPEN_Coverage_Index( &mmp->Mark2Coverage, IN_GLYPH( j ), 3019 &mark2_index ); 3020 if ( error ) 3021 return error; 3022 3023 ma1 = &mmp->Mark1Array; 3024 3025 if ( mark1_index >= ma1->MarkCount ) 3026 return ERR(HB_Err_Invalid_SubTable); 3027 3028 class = ma1->MarkRecord[mark1_index].Class; 3029 mark1_anchor = &ma1->MarkRecord[mark1_index].MarkAnchor; 3030 3031 if ( class >= mmp->ClassCount ) 3032 return ERR(HB_Err_Invalid_SubTable); 3033 3034 ma2 = &mmp->Mark2Array; 3035 3036 if ( mark2_index >= ma2->Mark2Count ) 3037 return ERR(HB_Err_Invalid_SubTable); 3038 3039 m2r = &ma2->Mark2Record[mark2_index]; 3040 mark2_anchor = &m2r->Mark2Anchor[class]; 3041 3042 error = Get_Anchor( gpi, mark1_anchor, IN_CURGLYPH(), 3043 &x_mark1_value, &y_mark1_value ); 3044 if ( error ) 3045 return error; 3046 error = Get_Anchor( gpi, mark2_anchor, IN_GLYPH( j ), 3047 &x_mark2_value, &y_mark2_value ); 3048 if ( error ) 3049 return error; 3050 3051 /* anchor points are not cumulative */ 3052 3053 o = POSITION( buffer->in_pos ); 3054 3055 o->x_pos = x_mark2_value - x_mark1_value; 3056 o->y_pos = y_mark2_value - y_mark1_value; 3057 o->x_advance = 0; 3058 o->y_advance = 0; 3059 o->back = 1; 3060 3061 (buffer->in_pos)++; 3062 3063 return HB_Err_Ok; 3064 } 3065 3066 3067 /* Do the actual positioning for a context positioning (either format 3068 7 or 8). This is only called after we've determined that the stream 3069 matches the subrule. */ 3070 3071 static HB_Error Do_ContextPos( GPOS_Instance* gpi, 3072 HB_UShort GlyphCount, 3073 HB_UShort PosCount, 3074 HB_PosLookupRecord* pos, 3075 HB_Buffer buffer, 3076 int nesting_level ) 3077 { 3078 HB_Error error; 3079 HB_UInt i, old_pos; 3080 3081 3082 i = 0; 3083 3084 while ( i < GlyphCount ) 3085 { 3086 if ( PosCount && i == pos->SequenceIndex ) 3087 { 3088 old_pos = buffer->in_pos; 3089 3090 /* Do a positioning */ 3091 3092 error = GPOS_Do_Glyph_Lookup( gpi, pos->LookupListIndex, buffer, 3093 GlyphCount, nesting_level ); 3094 3095 if ( error ) 3096 return error; 3097 3098 pos++; 3099 PosCount--; 3100 i += buffer->in_pos - old_pos; 3101 } 3102 else 3103 { 3104 i++; 3105 (buffer->in_pos)++; 3106 } 3107 } 3108 3109 return HB_Err_Ok; 3110 } 3111 3112 3113 /* LookupType 7 */ 3114 3115 /* PosRule */ 3116 3117 static HB_Error Load_PosRule( HB_PosRule* pr, 3118 HB_Stream stream ) 3119 { 3120 HB_Error error; 3121 3122 HB_UShort n, count; 3123 HB_UShort* i; 3124 3125 HB_PosLookupRecord* plr; 3126 3127 3128 if ( ACCESS_Frame( 4L ) ) 3129 return error; 3130 3131 pr->GlyphCount = GET_UShort(); 3132 pr->PosCount = GET_UShort(); 3133 3134 FORGET_Frame(); 3135 3136 pr->Input = NULL; 3137 3138 count = pr->GlyphCount - 1; /* only GlyphCount - 1 elements */ 3139 3140 if ( ALLOC_ARRAY( pr->Input, count, HB_UShort ) ) 3141 return error; 3142 3143 i = pr->Input; 3144 3145 if ( ACCESS_Frame( count * 2L ) ) 3146 goto Fail2; 3147 3148 for ( n = 0; n < count; n++ ) 3149 i[n] = GET_UShort(); 3150 3151 FORGET_Frame(); 3152 3153 pr->PosLookupRecord = NULL; 3154 3155 count = pr->PosCount; 3156 3157 if ( ALLOC_ARRAY( pr->PosLookupRecord, count, HB_PosLookupRecord ) ) 3158 goto Fail2; 3159 3160 plr = pr->PosLookupRecord; 3161 3162 if ( ACCESS_Frame( count * 4L ) ) 3163 goto Fail1; 3164 3165 for ( n = 0; n < count; n++ ) 3166 { 3167 plr[n].SequenceIndex = GET_UShort(); 3168 plr[n].LookupListIndex = GET_UShort(); 3169 } 3170 3171 FORGET_Frame(); 3172 3173 return HB_Err_Ok; 3174 3175 Fail1: 3176 FREE( plr ); 3177 3178 Fail2: 3179 FREE( i ); 3180 return error; 3181 } 3182 3183 3184 static void Free_PosRule( HB_PosRule* pr ) 3185 { 3186 FREE( pr->PosLookupRecord ); 3187 FREE( pr->Input ); 3188 } 3189 3190 3191 /* PosRuleSet */ 3192 3193 static HB_Error Load_PosRuleSet( HB_PosRuleSet* prs, 3194 HB_Stream stream ) 3195 { 3196 HB_Error error; 3197 3198 HB_UShort n, m, count; 3199 HB_UInt cur_offset, new_offset, base_offset; 3200 3201 HB_PosRule* pr; 3202 3203 3204 base_offset = FILE_Pos(); 3205 3206 if ( ACCESS_Frame( 2L ) ) 3207 return error; 3208 3209 count = prs->PosRuleCount = GET_UShort(); 3210 3211 FORGET_Frame(); 3212 3213 prs->PosRule = NULL; 3214 3215 if ( ALLOC_ARRAY( prs->PosRule, count, HB_PosRule ) ) 3216 return error; 3217 3218 pr = prs->PosRule; 3219 3220 for ( n = 0; n < count; n++ ) 3221 { 3222 if ( ACCESS_Frame( 2L ) ) 3223 goto Fail; 3224 3225 new_offset = GET_UShort() + base_offset; 3226 3227 FORGET_Frame(); 3228 3229 cur_offset = FILE_Pos(); 3230 if ( FILE_Seek( new_offset ) || 3231 ( error = Load_PosRule( &pr[n], stream ) ) != HB_Err_Ok ) 3232 goto Fail; 3233 (void)FILE_Seek( cur_offset ); 3234 } 3235 3236 return HB_Err_Ok; 3237 3238 Fail: 3239 for ( m = 0; m < n; m++ ) 3240 Free_PosRule( &pr[m] ); 3241 3242 FREE( pr ); 3243 return error; 3244 } 3245 3246 3247 static void Free_PosRuleSet( HB_PosRuleSet* prs ) 3248 { 3249 HB_UShort n, count; 3250 3251 HB_PosRule* pr; 3252 3253 3254 if ( prs->PosRule ) 3255 { 3256 count = prs->PosRuleCount; 3257 pr = prs->PosRule; 3258 3259 for ( n = 0; n < count; n++ ) 3260 Free_PosRule( &pr[n] ); 3261 3262 FREE( pr ); 3263 } 3264 } 3265 3266 3267 /* ContextPosFormat1 */ 3268 3269 static HB_Error Load_ContextPos1( HB_ContextPosFormat1* cpf1, 3270 HB_Stream stream ) 3271 { 3272 HB_Error error; 3273 3274 HB_UShort n, m, count; 3275 HB_UInt cur_offset, new_offset, base_offset; 3276 3277 HB_PosRuleSet* prs; 3278 3279 3280 base_offset = FILE_Pos() - 2L; 3281 3282 if ( ACCESS_Frame( 2L ) ) 3283 return error; 3284 3285 new_offset = GET_UShort() + base_offset; 3286 3287 FORGET_Frame(); 3288 3289 cur_offset = FILE_Pos(); 3290 if ( FILE_Seek( new_offset ) || 3291 ( error = _HB_OPEN_Load_Coverage( &cpf1->Coverage, stream ) ) != HB_Err_Ok ) 3292 return error; 3293 (void)FILE_Seek( cur_offset ); 3294 3295 if ( ACCESS_Frame( 2L ) ) 3296 goto Fail2; 3297 3298 count = cpf1->PosRuleSetCount = GET_UShort(); 3299 3300 FORGET_Frame(); 3301 3302 cpf1->PosRuleSet = NULL; 3303 3304 if ( ALLOC_ARRAY( cpf1->PosRuleSet, count, HB_PosRuleSet ) ) 3305 goto Fail2; 3306 3307 prs = cpf1->PosRuleSet; 3308 3309 for ( n = 0; n < count; n++ ) 3310 { 3311 if ( ACCESS_Frame( 2L ) ) 3312 goto Fail1; 3313 3314 new_offset = GET_UShort() + base_offset; 3315 3316 FORGET_Frame(); 3317 3318 cur_offset = FILE_Pos(); 3319 if ( FILE_Seek( new_offset ) || 3320 ( error = Load_PosRuleSet( &prs[n], stream ) ) != HB_Err_Ok ) 3321 goto Fail1; 3322 (void)FILE_Seek( cur_offset ); 3323 } 3324 3325 return HB_Err_Ok; 3326 3327 Fail1: 3328 for ( m = 0; m < n; m++ ) 3329 Free_PosRuleSet( &prs[m] ); 3330 3331 FREE( prs ); 3332 3333 Fail2: 3334 _HB_OPEN_Free_Coverage( &cpf1->Coverage ); 3335 return error; 3336 } 3337 3338 3339 static void Free_ContextPos1( HB_ContextPosFormat1* cpf1 ) 3340 { 3341 HB_UShort n, count; 3342 3343 HB_PosRuleSet* prs; 3344 3345 3346 if ( cpf1->PosRuleSet ) 3347 { 3348 count = cpf1->PosRuleSetCount; 3349 prs = cpf1->PosRuleSet; 3350 3351 for ( n = 0; n < count; n++ ) 3352 Free_PosRuleSet( &prs[n] ); 3353 3354 FREE( prs ); 3355 } 3356 3357 _HB_OPEN_Free_Coverage( &cpf1->Coverage ); 3358 } 3359 3360 3361 /* PosClassRule */ 3362 3363 static HB_Error Load_PosClassRule( HB_ContextPosFormat2* cpf2, 3364 HB_PosClassRule* pcr, 3365 HB_Stream stream ) 3366 { 3367 HB_Error error; 3368 3369 HB_UShort n, count; 3370 3371 HB_UShort* c; 3372 HB_PosLookupRecord* plr; 3373 3374 3375 if ( ACCESS_Frame( 4L ) ) 3376 return error; 3377 3378 pcr->GlyphCount = GET_UShort(); 3379 pcr->PosCount = GET_UShort(); 3380 3381 FORGET_Frame(); 3382 3383 if ( pcr->GlyphCount > cpf2->MaxContextLength ) 3384 cpf2->MaxContextLength = pcr->GlyphCount; 3385 3386 pcr->Class = NULL; 3387 3388 count = pcr->GlyphCount - 1; /* only GlyphCount - 1 elements */ 3389 3390 if ( ALLOC_ARRAY( pcr->Class, count, HB_UShort ) ) 3391 return error; 3392 3393 c = pcr->Class; 3394 3395 if ( ACCESS_Frame( count * 2L ) ) 3396 goto Fail2; 3397 3398 for ( n = 0; n < count; n++ ) 3399 c[n] = GET_UShort(); 3400 3401 FORGET_Frame(); 3402 3403 pcr->PosLookupRecord = NULL; 3404 3405 count = pcr->PosCount; 3406 3407 if ( ALLOC_ARRAY( pcr->PosLookupRecord, count, HB_PosLookupRecord ) ) 3408 goto Fail2; 3409 3410 plr = pcr->PosLookupRecord; 3411 3412 if ( ACCESS_Frame( count * 4L ) ) 3413 goto Fail1; 3414 3415 for ( n = 0; n < count; n++ ) 3416 { 3417 plr[n].SequenceIndex = GET_UShort(); 3418 plr[n].LookupListIndex = GET_UShort(); 3419 } 3420 3421 FORGET_Frame(); 3422 3423 return HB_Err_Ok; 3424 3425 Fail1: 3426 FREE( plr ); 3427 3428 Fail2: 3429 FREE( c ); 3430 return error; 3431 } 3432 3433 3434 static void Free_PosClassRule( HB_PosClassRule* pcr ) 3435 { 3436 FREE( pcr->PosLookupRecord ); 3437 FREE( pcr->Class ); 3438 } 3439 3440 3441 /* PosClassSet */ 3442 3443 static HB_Error Load_PosClassSet( HB_ContextPosFormat2* cpf2, 3444 HB_PosClassSet* pcs, 3445 HB_Stream stream ) 3446 { 3447 HB_Error error; 3448 3449 HB_UShort n, m, count; 3450 HB_UInt cur_offset, new_offset, base_offset; 3451 3452 HB_PosClassRule* pcr; 3453 3454 3455 base_offset = FILE_Pos(); 3456 3457 if ( ACCESS_Frame( 2L ) ) 3458 return error; 3459 3460 count = pcs->PosClassRuleCount = GET_UShort(); 3461 3462 FORGET_Frame(); 3463 3464 pcs->PosClassRule = NULL; 3465 3466 if ( ALLOC_ARRAY( pcs->PosClassRule, count, HB_PosClassRule ) ) 3467 return error; 3468 3469 pcr = pcs->PosClassRule; 3470 3471 for ( n = 0; n < count; n++ ) 3472 { 3473 if ( ACCESS_Frame( 2L ) ) 3474 goto Fail; 3475 3476 new_offset = GET_UShort() + base_offset; 3477 3478 FORGET_Frame(); 3479 3480 cur_offset = FILE_Pos(); 3481 if ( FILE_Seek( new_offset ) || 3482 ( error = Load_PosClassRule( cpf2, &pcr[n], 3483 stream ) ) != HB_Err_Ok ) 3484 goto Fail; 3485 (void)FILE_Seek( cur_offset ); 3486 } 3487 3488 return HB_Err_Ok; 3489 3490 Fail: 3491 for ( m = 0; m < n; m++ ) 3492 Free_PosClassRule( &pcr[m] ); 3493 3494 FREE( pcr ); 3495 return error; 3496 } 3497 3498 3499 static void Free_PosClassSet( HB_PosClassSet* pcs ) 3500 { 3501 HB_UShort n, count; 3502 3503 HB_PosClassRule* pcr; 3504 3505 3506 if ( pcs->PosClassRule ) 3507 { 3508 count = pcs->PosClassRuleCount; 3509 pcr = pcs->PosClassRule; 3510 3511 for ( n = 0; n < count; n++ ) 3512 Free_PosClassRule( &pcr[n] ); 3513 3514 FREE( pcr ); 3515 } 3516 } 3517 3518 3519 /* ContextPosFormat2 */ 3520 3521 static HB_Error Load_ContextPos2( HB_ContextPosFormat2* cpf2, 3522 HB_Stream stream ) 3523 { 3524 HB_Error error; 3525 3526 HB_UShort n, m, count; 3527 HB_UInt cur_offset, new_offset, base_offset; 3528 3529 HB_PosClassSet* pcs; 3530 3531 3532 base_offset = FILE_Pos() - 2; 3533 3534 if ( ACCESS_Frame( 2L ) ) 3535 return error; 3536 3537 new_offset = GET_UShort() + base_offset; 3538 3539 FORGET_Frame(); 3540 3541 cur_offset = FILE_Pos(); 3542 if ( FILE_Seek( new_offset ) || 3543 ( error = _HB_OPEN_Load_Coverage( &cpf2->Coverage, stream ) ) != HB_Err_Ok ) 3544 return error; 3545 (void)FILE_Seek( cur_offset ); 3546 3547 if ( ACCESS_Frame( 4L ) ) 3548 goto Fail3; 3549 3550 new_offset = GET_UShort() + base_offset; 3551 3552 /* `PosClassSetCount' is the upper limit for class values, thus we 3553 read it now to make an additional safety check. */ 3554 3555 count = cpf2->PosClassSetCount = GET_UShort(); 3556 3557 FORGET_Frame(); 3558 3559 cur_offset = FILE_Pos(); 3560 if ( FILE_Seek( new_offset ) || 3561 ( error = _HB_OPEN_Load_ClassDefinition( &cpf2->ClassDef, count, 3562 stream ) ) != HB_Err_Ok ) 3563 goto Fail3; 3564 (void)FILE_Seek( cur_offset ); 3565 3566 cpf2->PosClassSet = NULL; 3567 cpf2->MaxContextLength = 0; 3568 3569 if ( ALLOC_ARRAY( cpf2->PosClassSet, count, HB_PosClassSet ) ) 3570 goto Fail2; 3571 3572 pcs = cpf2->PosClassSet; 3573 3574 for ( n = 0; n < count; n++ ) 3575 { 3576 if ( ACCESS_Frame( 2L ) ) 3577 goto Fail1; 3578 3579 new_offset = GET_UShort() + base_offset; 3580 3581 FORGET_Frame(); 3582 3583 if ( new_offset != base_offset ) /* not a NULL offset */ 3584 { 3585 cur_offset = FILE_Pos(); 3586 if ( FILE_Seek( new_offset ) || 3587 ( error = Load_PosClassSet( cpf2, &pcs[n], 3588 stream ) ) != HB_Err_Ok ) 3589 goto Fail1; 3590 (void)FILE_Seek( cur_offset ); 3591 } 3592 else 3593 { 3594 /* we create a PosClassSet table with no entries */ 3595 3596 cpf2->PosClassSet[n].PosClassRuleCount = 0; 3597 cpf2->PosClassSet[n].PosClassRule = NULL; 3598 } 3599 } 3600 3601 return HB_Err_Ok; 3602 3603 Fail1: 3604 for ( m = 0; m < n; n++ ) 3605 Free_PosClassSet( &pcs[m] ); 3606 3607 FREE( pcs ); 3608 3609 Fail2: 3610 _HB_OPEN_Free_ClassDefinition( &cpf2->ClassDef ); 3611 3612 Fail3: 3613 _HB_OPEN_Free_Coverage( &cpf2->Coverage ); 3614 return error; 3615 } 3616 3617 3618 static void Free_ContextPos2( HB_ContextPosFormat2* cpf2 ) 3619 { 3620 HB_UShort n, count; 3621 3622 HB_PosClassSet* pcs; 3623 3624 3625 if ( cpf2->PosClassSet ) 3626 { 3627 count = cpf2->PosClassSetCount; 3628 pcs = cpf2->PosClassSet; 3629 3630 for ( n = 0; n < count; n++ ) 3631 Free_PosClassSet( &pcs[n] ); 3632 3633 FREE( pcs ); 3634 } 3635 3636 _HB_OPEN_Free_ClassDefinition( &cpf2->ClassDef ); 3637 _HB_OPEN_Free_Coverage( &cpf2->Coverage ); 3638 } 3639 3640 3641 /* ContextPosFormat3 */ 3642 3643 static HB_Error Load_ContextPos3( HB_ContextPosFormat3* cpf3, 3644 HB_Stream stream ) 3645 { 3646 HB_Error error; 3647 3648 HB_UShort n, count; 3649 HB_UInt cur_offset, new_offset, base_offset; 3650 3651 HB_Coverage* c; 3652 HB_PosLookupRecord* plr; 3653 3654 3655 base_offset = FILE_Pos() - 2L; 3656 3657 if ( ACCESS_Frame( 4L ) ) 3658 return error; 3659 3660 cpf3->GlyphCount = GET_UShort(); 3661 cpf3->PosCount = GET_UShort(); 3662 3663 FORGET_Frame(); 3664 3665 cpf3->Coverage = NULL; 3666 3667 count = cpf3->GlyphCount; 3668 3669 if ( ALLOC_ARRAY( cpf3->Coverage, count, HB_Coverage ) ) 3670 return error; 3671 3672 c = cpf3->Coverage; 3673 3674 for ( n = 0; n < count; n++ ) 3675 { 3676 if ( ACCESS_Frame( 2L ) ) 3677 goto Fail2; 3678 3679 new_offset = GET_UShort() + base_offset; 3680 3681 FORGET_Frame(); 3682 3683 cur_offset = FILE_Pos(); 3684 if ( FILE_Seek( new_offset ) || 3685 ( error = _HB_OPEN_Load_Coverage( &c[n], stream ) ) != HB_Err_Ok ) 3686 goto Fail2; 3687 (void)FILE_Seek( cur_offset ); 3688 } 3689 3690 cpf3->PosLookupRecord = NULL; 3691 3692 count = cpf3->PosCount; 3693 3694 if ( ALLOC_ARRAY( cpf3->PosLookupRecord, count, HB_PosLookupRecord ) ) 3695 goto Fail2; 3696 3697 plr = cpf3->PosLookupRecord; 3698 3699 if ( ACCESS_Frame( count * 4L ) ) 3700 goto Fail1; 3701 3702 for ( n = 0; n < count; n++ ) 3703 { 3704 plr[n].SequenceIndex = GET_UShort(); 3705 plr[n].LookupListIndex = GET_UShort(); 3706 } 3707 3708 FORGET_Frame(); 3709 3710 return HB_Err_Ok; 3711 3712 Fail1: 3713 FREE( plr ); 3714 3715 Fail2: 3716 for ( n = 0; n < count; n++ ) 3717 _HB_OPEN_Free_Coverage( &c[n] ); 3718 3719 FREE( c ); 3720 return error; 3721 } 3722 3723 3724 static void Free_ContextPos3( HB_ContextPosFormat3* cpf3 ) 3725 { 3726 HB_UShort n, count; 3727 3728 HB_Coverage* c; 3729 3730 3731 FREE( cpf3->PosLookupRecord ); 3732 3733 if ( cpf3->Coverage ) 3734 { 3735 count = cpf3->GlyphCount; 3736 c = cpf3->Coverage; 3737 3738 for ( n = 0; n < count; n++ ) 3739 _HB_OPEN_Free_Coverage( &c[n] ); 3740 3741 FREE( c ); 3742 } 3743 } 3744 3745 3746 /* ContextPos */ 3747 3748 static HB_Error Load_ContextPos( HB_GPOS_SubTable* st, 3749 HB_Stream stream ) 3750 { 3751 HB_Error error; 3752 HB_ContextPos* cp = &st->context; 3753 3754 3755 if ( ACCESS_Frame( 2L ) ) 3756 return error; 3757 3758 cp->PosFormat = GET_UShort(); 3759 3760 FORGET_Frame(); 3761 3762 switch ( cp->PosFormat ) 3763 { 3764 case 1: 3765 return Load_ContextPos1( &cp->cpf.cpf1, stream ); 3766 3767 case 2: 3768 return Load_ContextPos2( &cp->cpf.cpf2, stream ); 3769 3770 case 3: 3771 return Load_ContextPos3( &cp->cpf.cpf3, stream ); 3772 3773 default: 3774 return ERR(HB_Err_Invalid_SubTable_Format); 3775 } 3776 3777 return HB_Err_Ok; /* never reached */ 3778 } 3779 3780 3781 static void Free_ContextPos( HB_GPOS_SubTable* st ) 3782 { 3783 HB_ContextPos* cp = &st->context; 3784 3785 switch ( cp->PosFormat ) 3786 { 3787 case 1: Free_ContextPos1( &cp->cpf.cpf1 ); break; 3788 case 2: Free_ContextPos2( &cp->cpf.cpf2 ); break; 3789 case 3: Free_ContextPos3( &cp->cpf.cpf3 ); break; 3790 default: break; 3791 } 3792 } 3793 3794 3795 static HB_Error Lookup_ContextPos1( GPOS_Instance* gpi, 3796 HB_ContextPosFormat1* cpf1, 3797 HB_Buffer buffer, 3798 HB_UShort flags, 3799 HB_UShort context_length, 3800 int nesting_level ) 3801 { 3802 HB_UShort index, property; 3803 HB_UShort i, j, k, numpr; 3804 HB_Error error; 3805 HB_GPOSHeader* gpos = gpi->gpos; 3806 3807 HB_PosRule* pr; 3808 HB_GDEFHeader* gdef; 3809 3810 3811 gdef = gpos->gdef; 3812 3813 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) 3814 return error; 3815 3816 error = _HB_OPEN_Coverage_Index( &cpf1->Coverage, IN_CURGLYPH(), &index ); 3817 if ( error ) 3818 return error; 3819 3820 pr = cpf1->PosRuleSet[index].PosRule; 3821 numpr = cpf1->PosRuleSet[index].PosRuleCount; 3822 3823 for ( k = 0; k < numpr; k++ ) 3824 { 3825 if ( context_length != 0xFFFF && context_length < pr[k].GlyphCount ) 3826 goto next_posrule; 3827 3828 if ( buffer->in_pos + pr[k].GlyphCount > buffer->in_length ) 3829 goto next_posrule; /* context is too long */ 3830 3831 for ( i = 1, j = buffer->in_pos + 1; i < pr[k].GlyphCount; i++, j++ ) 3832 { 3833 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) 3834 { 3835 if ( error && error != HB_Err_Not_Covered ) 3836 return error; 3837 3838 if ( j + pr[k].GlyphCount - i == (HB_Int)buffer->in_length ) 3839 goto next_posrule; 3840 j++; 3841 } 3842 3843 if ( IN_GLYPH( j ) != pr[k].Input[i - 1] ) 3844 goto next_posrule; 3845 } 3846 3847 return Do_ContextPos( gpi, pr[k].GlyphCount, 3848 pr[k].PosCount, pr[k].PosLookupRecord, 3849 buffer, 3850 nesting_level ); 3851 3852 next_posrule: 3853 ; 3854 } 3855 3856 return HB_Err_Not_Covered; 3857 } 3858 3859 3860 static HB_Error Lookup_ContextPos2( GPOS_Instance* gpi, 3861 HB_ContextPosFormat2* cpf2, 3862 HB_Buffer buffer, 3863 HB_UShort flags, 3864 HB_UShort context_length, 3865 int nesting_level ) 3866 { 3867 HB_UShort index, property; 3868 HB_Error error; 3869 HB_UShort i, j, k, known_classes; 3870 3871 HB_UShort* classes; 3872 HB_UShort* cl; 3873 HB_GPOSHeader* gpos = gpi->gpos; 3874 3875 HB_PosClassSet* pcs; 3876 HB_PosClassRule* pr; 3877 HB_GDEFHeader* gdef; 3878 3879 3880 gdef = gpos->gdef; 3881 3882 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) 3883 return error; 3884 3885 /* Note: The coverage table in format 2 doesn't give an index into 3886 anything. It just lets us know whether or not we need to 3887 do any lookup at all. */ 3888 3889 error = _HB_OPEN_Coverage_Index( &cpf2->Coverage, IN_CURGLYPH(), &index ); 3890 if ( error ) 3891 return error; 3892 3893 if (cpf2->MaxContextLength < 1) 3894 return HB_Err_Not_Covered; 3895 3896 if ( ALLOC_ARRAY( classes, cpf2->MaxContextLength, HB_UShort ) ) 3897 return error; 3898 3899 error = _HB_OPEN_Get_Class( &cpf2->ClassDef, IN_CURGLYPH(), 3900 &classes[0], NULL ); 3901 if ( error && error != HB_Err_Not_Covered ) 3902 goto End; 3903 known_classes = 0; 3904 3905 pcs = &cpf2->PosClassSet[classes[0]]; 3906 if ( !pcs ) 3907 { 3908 error = ERR(HB_Err_Invalid_SubTable); 3909 goto End; 3910 } 3911 3912 for ( k = 0; k < pcs->PosClassRuleCount; k++ ) 3913 { 3914 pr = &pcs->PosClassRule[k]; 3915 3916 if ( context_length != 0xFFFF && context_length < pr->GlyphCount ) 3917 goto next_posclassrule; 3918 3919 if ( buffer->in_pos + pr->GlyphCount > buffer->in_length ) 3920 goto next_posclassrule; /* context is too long */ 3921 3922 cl = pr->Class; 3923 3924 /* Start at 1 because [0] is implied */ 3925 3926 for ( i = 1, j = buffer->in_pos + 1; i < pr->GlyphCount; i++, j++ ) 3927 { 3928 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) 3929 { 3930 if ( error && error != HB_Err_Not_Covered ) 3931 goto End; 3932 3933 if ( j + pr->GlyphCount - i == (HB_Int)buffer->in_length ) 3934 goto next_posclassrule; 3935 j++; 3936 } 3937 3938 if ( i > known_classes ) 3939 { 3940 /* Keeps us from having to do this for each rule */ 3941 3942 error = _HB_OPEN_Get_Class( &cpf2->ClassDef, IN_GLYPH( j ), &classes[i], NULL ); 3943 if ( error && error != HB_Err_Not_Covered ) 3944 goto End; 3945 known_classes = i; 3946 } 3947 3948 if ( cl[i - 1] != classes[i] ) 3949 goto next_posclassrule; 3950 } 3951 3952 error = Do_ContextPos( gpi, pr->GlyphCount, 3953 pr->PosCount, pr->PosLookupRecord, 3954 buffer, 3955 nesting_level ); 3956 goto End; 3957 3958 next_posclassrule: 3959 ; 3960 } 3961 3962 error = HB_Err_Not_Covered; 3963 3964 End: 3965 FREE( classes ); 3966 return error; 3967 } 3968 3969 3970 static HB_Error Lookup_ContextPos3( GPOS_Instance* gpi, 3971 HB_ContextPosFormat3* cpf3, 3972 HB_Buffer buffer, 3973 HB_UShort flags, 3974 HB_UShort context_length, 3975 int nesting_level ) 3976 { 3977 HB_Error error; 3978 HB_UShort index, i, j, property; 3979 HB_GPOSHeader* gpos = gpi->gpos; 3980 3981 HB_Coverage* c; 3982 HB_GDEFHeader* gdef; 3983 3984 3985 gdef = gpos->gdef; 3986 3987 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) 3988 return error; 3989 3990 if ( context_length != 0xFFFF && context_length < cpf3->GlyphCount ) 3991 return HB_Err_Not_Covered; 3992 3993 if ( buffer->in_pos + cpf3->GlyphCount > buffer->in_length ) 3994 return HB_Err_Not_Covered; /* context is too long */ 3995 3996 c = cpf3->Coverage; 3997 3998 for ( i = 1, j = 1; i < cpf3->GlyphCount; i++, j++ ) 3999 { 4000 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) 4001 { 4002 if ( error && error != HB_Err_Not_Covered ) 4003 return error; 4004 4005 if ( j + cpf3->GlyphCount - i == (HB_Int)buffer->in_length ) 4006 return HB_Err_Not_Covered; 4007 j++; 4008 } 4009 4010 error = _HB_OPEN_Coverage_Index( &c[i], IN_GLYPH( j ), &index ); 4011 if ( error ) 4012 return error; 4013 } 4014 4015 return Do_ContextPos( gpi, cpf3->GlyphCount, 4016 cpf3->PosCount, cpf3->PosLookupRecord, 4017 buffer, 4018 nesting_level ); 4019 } 4020 4021 4022 static HB_Error Lookup_ContextPos( GPOS_Instance* gpi, 4023 HB_GPOS_SubTable* st, 4024 HB_Buffer buffer, 4025 HB_UShort flags, 4026 HB_UShort context_length, 4027 int nesting_level ) 4028 { 4029 HB_ContextPos* cp = &st->context; 4030 4031 switch ( cp->PosFormat ) 4032 { 4033 case 1: 4034 return Lookup_ContextPos1( gpi, &cp->cpf.cpf1, buffer, 4035 flags, context_length, nesting_level ); 4036 4037 case 2: 4038 return Lookup_ContextPos2( gpi, &cp->cpf.cpf2, buffer, 4039 flags, context_length, nesting_level ); 4040 4041 case 3: 4042 return Lookup_ContextPos3( gpi, &cp->cpf.cpf3, buffer, 4043 flags, context_length, nesting_level ); 4044 4045 default: 4046 return ERR(HB_Err_Invalid_SubTable_Format); 4047 } 4048 4049 return HB_Err_Ok; /* never reached */ 4050 } 4051 4052 4053 /* LookupType 8 */ 4054 4055 /* ChainPosRule */ 4056 4057 static HB_Error Load_ChainPosRule( HB_ChainPosRule* cpr, 4058 HB_Stream stream ) 4059 { 4060 HB_Error error; 4061 4062 HB_UShort n, count; 4063 HB_UShort* b; 4064 HB_UShort* i; 4065 HB_UShort* l; 4066 4067 HB_PosLookupRecord* plr; 4068 4069 4070 if ( ACCESS_Frame( 2L ) ) 4071 return error; 4072 4073 cpr->BacktrackGlyphCount = GET_UShort(); 4074 4075 FORGET_Frame(); 4076 4077 cpr->Backtrack = NULL; 4078 4079 count = cpr->BacktrackGlyphCount; 4080 4081 if ( ALLOC_ARRAY( cpr->Backtrack, count, HB_UShort ) ) 4082 return error; 4083 4084 b = cpr->Backtrack; 4085 4086 if ( ACCESS_Frame( count * 2L ) ) 4087 goto Fail4; 4088 4089 for ( n = 0; n < count; n++ ) 4090 b[n] = GET_UShort(); 4091 4092 FORGET_Frame(); 4093 4094 if ( ACCESS_Frame( 2L ) ) 4095 goto Fail4; 4096 4097 cpr->InputGlyphCount = GET_UShort(); 4098 4099 FORGET_Frame(); 4100 4101 cpr->Input = NULL; 4102 4103 count = cpr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */ 4104 4105 if ( ALLOC_ARRAY( cpr->Input, count, HB_UShort ) ) 4106 goto Fail4; 4107 4108 i = cpr->Input; 4109 4110 if ( ACCESS_Frame( count * 2L ) ) 4111 goto Fail3; 4112 4113 for ( n = 0; n < count; n++ ) 4114 i[n] = GET_UShort(); 4115 4116 FORGET_Frame(); 4117 4118 if ( ACCESS_Frame( 2L ) ) 4119 goto Fail3; 4120 4121 cpr->LookaheadGlyphCount = GET_UShort(); 4122 4123 FORGET_Frame(); 4124 4125 cpr->Lookahead = NULL; 4126 4127 count = cpr->LookaheadGlyphCount; 4128 4129 if ( ALLOC_ARRAY( cpr->Lookahead, count, HB_UShort ) ) 4130 goto Fail3; 4131 4132 l = cpr->Lookahead; 4133 4134 if ( ACCESS_Frame( count * 2L ) ) 4135 goto Fail2; 4136 4137 for ( n = 0; n < count; n++ ) 4138 l[n] = GET_UShort(); 4139 4140 FORGET_Frame(); 4141 4142 if ( ACCESS_Frame( 2L ) ) 4143 goto Fail2; 4144 4145 cpr->PosCount = GET_UShort(); 4146 4147 FORGET_Frame(); 4148 4149 cpr->PosLookupRecord = NULL; 4150 4151 count = cpr->PosCount; 4152 4153 if ( ALLOC_ARRAY( cpr->PosLookupRecord, count, HB_PosLookupRecord ) ) 4154 goto Fail2; 4155 4156 plr = cpr->PosLookupRecord; 4157 4158 if ( ACCESS_Frame( count * 4L ) ) 4159 goto Fail1; 4160 4161 for ( n = 0; n < count; n++ ) 4162 { 4163 plr[n].SequenceIndex = GET_UShort(); 4164 plr[n].LookupListIndex = GET_UShort(); 4165 } 4166 4167 FORGET_Frame(); 4168 4169 return HB_Err_Ok; 4170 4171 Fail1: 4172 FREE( plr ); 4173 4174 Fail2: 4175 FREE( l ); 4176 4177 Fail3: 4178 FREE( i ); 4179 4180 Fail4: 4181 FREE( b ); 4182 return error; 4183 } 4184 4185 4186 static void Free_ChainPosRule( HB_ChainPosRule* cpr ) 4187 { 4188 FREE( cpr->PosLookupRecord ); 4189 FREE( cpr->Lookahead ); 4190 FREE( cpr->Input ); 4191 FREE( cpr->Backtrack ); 4192 } 4193 4194 4195 /* ChainPosRuleSet */ 4196 4197 static HB_Error Load_ChainPosRuleSet( HB_ChainPosRuleSet* cprs, 4198 HB_Stream stream ) 4199 { 4200 HB_Error error; 4201 4202 HB_UShort n, m, count; 4203 HB_UInt cur_offset, new_offset, base_offset; 4204 4205 HB_ChainPosRule* cpr; 4206 4207 4208 base_offset = FILE_Pos(); 4209 4210 if ( ACCESS_Frame( 2L ) ) 4211 return error; 4212 4213 count = cprs->ChainPosRuleCount = GET_UShort(); 4214 4215 FORGET_Frame(); 4216 4217 cprs->ChainPosRule = NULL; 4218 4219 if ( ALLOC_ARRAY( cprs->ChainPosRule, count, HB_ChainPosRule ) ) 4220 return error; 4221 4222 cpr = cprs->ChainPosRule; 4223 4224 for ( n = 0; n < count; n++ ) 4225 { 4226 if ( ACCESS_Frame( 2L ) ) 4227 goto Fail; 4228 4229 new_offset = GET_UShort() + base_offset; 4230 4231 FORGET_Frame(); 4232 4233 cur_offset = FILE_Pos(); 4234 if ( FILE_Seek( new_offset ) || 4235 ( error = Load_ChainPosRule( &cpr[n], stream ) ) != HB_Err_Ok ) 4236 goto Fail; 4237 (void)FILE_Seek( cur_offset ); 4238 } 4239 4240 return HB_Err_Ok; 4241 4242 Fail: 4243 for ( m = 0; m < n; m++ ) 4244 Free_ChainPosRule( &cpr[m] ); 4245 4246 FREE( cpr ); 4247 return error; 4248 } 4249 4250 4251 static void Free_ChainPosRuleSet( HB_ChainPosRuleSet* cprs ) 4252 { 4253 HB_UShort n, count; 4254 4255 HB_ChainPosRule* cpr; 4256 4257 4258 if ( cprs->ChainPosRule ) 4259 { 4260 count = cprs->ChainPosRuleCount; 4261 cpr = cprs->ChainPosRule; 4262 4263 for ( n = 0; n < count; n++ ) 4264 Free_ChainPosRule( &cpr[n] ); 4265 4266 FREE( cpr ); 4267 } 4268 } 4269 4270 4271 /* ChainContextPosFormat1 */ 4272 4273 static HB_Error Load_ChainContextPos1( HB_ChainContextPosFormat1* ccpf1, 4274 HB_Stream stream ) 4275 { 4276 HB_Error error; 4277 4278 HB_UShort n, m, count; 4279 HB_UInt cur_offset, new_offset, base_offset; 4280 4281 HB_ChainPosRuleSet* cprs; 4282 4283 4284 base_offset = FILE_Pos() - 2L; 4285 4286 if ( ACCESS_Frame( 2L ) ) 4287 return error; 4288 4289 new_offset = GET_UShort() + base_offset; 4290 4291 FORGET_Frame(); 4292 4293 cur_offset = FILE_Pos(); 4294 if ( FILE_Seek( new_offset ) || 4295 ( error = _HB_OPEN_Load_Coverage( &ccpf1->Coverage, stream ) ) != HB_Err_Ok ) 4296 return error; 4297 (void)FILE_Seek( cur_offset ); 4298 4299 if ( ACCESS_Frame( 2L ) ) 4300 goto Fail2; 4301 4302 count = ccpf1->ChainPosRuleSetCount = GET_UShort(); 4303 4304 FORGET_Frame(); 4305 4306 ccpf1->ChainPosRuleSet = NULL; 4307 4308 if ( ALLOC_ARRAY( ccpf1->ChainPosRuleSet, count, HB_ChainPosRuleSet ) ) 4309 goto Fail2; 4310 4311 cprs = ccpf1->ChainPosRuleSet; 4312 4313 for ( n = 0; n < count; n++ ) 4314 { 4315 if ( ACCESS_Frame( 2L ) ) 4316 goto Fail1; 4317 4318 new_offset = GET_UShort() + base_offset; 4319 4320 FORGET_Frame(); 4321 4322 cur_offset = FILE_Pos(); 4323 if ( FILE_Seek( new_offset ) || 4324 ( error = Load_ChainPosRuleSet( &cprs[n], stream ) ) != HB_Err_Ok ) 4325 goto Fail1; 4326 (void)FILE_Seek( cur_offset ); 4327 } 4328 4329 return HB_Err_Ok; 4330 4331 Fail1: 4332 for ( m = 0; m < n; m++ ) 4333 Free_ChainPosRuleSet( &cprs[m] ); 4334 4335 FREE( cprs ); 4336 4337 Fail2: 4338 _HB_OPEN_Free_Coverage( &ccpf1->Coverage ); 4339 return error; 4340 } 4341 4342 4343 static void Free_ChainContextPos1( HB_ChainContextPosFormat1* ccpf1 ) 4344 { 4345 HB_UShort n, count; 4346 4347 HB_ChainPosRuleSet* cprs; 4348 4349 4350 if ( ccpf1->ChainPosRuleSet ) 4351 { 4352 count = ccpf1->ChainPosRuleSetCount; 4353 cprs = ccpf1->ChainPosRuleSet; 4354 4355 for ( n = 0; n < count; n++ ) 4356 Free_ChainPosRuleSet( &cprs[n] ); 4357 4358 FREE( cprs ); 4359 } 4360 4361 _HB_OPEN_Free_Coverage( &ccpf1->Coverage ); 4362 } 4363 4364 4365 /* ChainPosClassRule */ 4366 4367 static HB_Error Load_ChainPosClassRule( 4368 HB_ChainContextPosFormat2* ccpf2, 4369 HB_ChainPosClassRule* cpcr, 4370 HB_Stream stream ) 4371 { 4372 HB_Error error; 4373 4374 HB_UShort n, count; 4375 4376 HB_UShort* b; 4377 HB_UShort* i; 4378 HB_UShort* l; 4379 HB_PosLookupRecord* plr; 4380 4381 4382 if ( ACCESS_Frame( 2L ) ) 4383 return error; 4384 4385 cpcr->BacktrackGlyphCount = GET_UShort(); 4386 4387 FORGET_Frame(); 4388 4389 if ( cpcr->BacktrackGlyphCount > ccpf2->MaxBacktrackLength ) 4390 ccpf2->MaxBacktrackLength = cpcr->BacktrackGlyphCount; 4391 4392 cpcr->Backtrack = NULL; 4393 4394 count = cpcr->BacktrackGlyphCount; 4395 4396 if ( ALLOC_ARRAY( cpcr->Backtrack, count, HB_UShort ) ) 4397 return error; 4398 4399 b = cpcr->Backtrack; 4400 4401 if ( ACCESS_Frame( count * 2L ) ) 4402 goto Fail4; 4403 4404 for ( n = 0; n < count; n++ ) 4405 b[n] = GET_UShort(); 4406 4407 FORGET_Frame(); 4408 4409 if ( ACCESS_Frame( 2L ) ) 4410 goto Fail4; 4411 4412 cpcr->InputGlyphCount = GET_UShort(); 4413 4414 if ( cpcr->InputGlyphCount > ccpf2->MaxInputLength ) 4415 ccpf2->MaxInputLength = cpcr->InputGlyphCount; 4416 4417 FORGET_Frame(); 4418 4419 cpcr->Input = NULL; 4420 4421 count = cpcr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */ 4422 4423 if ( ALLOC_ARRAY( cpcr->Input, count, HB_UShort ) ) 4424 goto Fail4; 4425 4426 i = cpcr->Input; 4427 4428 if ( ACCESS_Frame( count * 2L ) ) 4429 goto Fail3; 4430 4431 for ( n = 0; n < count; n++ ) 4432 i[n] = GET_UShort(); 4433 4434 FORGET_Frame(); 4435 4436 if ( ACCESS_Frame( 2L ) ) 4437 goto Fail3; 4438 4439 cpcr->LookaheadGlyphCount = GET_UShort(); 4440 4441 FORGET_Frame(); 4442 4443 if ( cpcr->LookaheadGlyphCount > ccpf2->MaxLookaheadLength ) 4444 ccpf2->MaxLookaheadLength = cpcr->LookaheadGlyphCount; 4445 4446 cpcr->Lookahead = NULL; 4447 4448 count = cpcr->LookaheadGlyphCount; 4449 4450 if ( ALLOC_ARRAY( cpcr->Lookahead, count, HB_UShort ) ) 4451 goto Fail3; 4452 4453 l = cpcr->Lookahead; 4454 4455 if ( ACCESS_Frame( count * 2L ) ) 4456 goto Fail2; 4457 4458 for ( n = 0; n < count; n++ ) 4459 l[n] = GET_UShort(); 4460 4461 FORGET_Frame(); 4462 4463 if ( ACCESS_Frame( 2L ) ) 4464 goto Fail2; 4465 4466 cpcr->PosCount = GET_UShort(); 4467 4468 FORGET_Frame(); 4469 4470 cpcr->PosLookupRecord = NULL; 4471 4472 count = cpcr->PosCount; 4473 4474 if ( ALLOC_ARRAY( cpcr->PosLookupRecord, count, HB_PosLookupRecord ) ) 4475 goto Fail2; 4476 4477 plr = cpcr->PosLookupRecord; 4478 4479 if ( ACCESS_Frame( count * 4L ) ) 4480 goto Fail1; 4481 4482 for ( n = 0; n < count; n++ ) 4483 { 4484 plr[n].SequenceIndex = GET_UShort(); 4485 plr[n].LookupListIndex = GET_UShort(); 4486 } 4487 4488 FORGET_Frame(); 4489 4490 return HB_Err_Ok; 4491 4492 Fail1: 4493 FREE( plr ); 4494 4495 Fail2: 4496 FREE( l ); 4497 4498 Fail3: 4499 FREE( i ); 4500 4501 Fail4: 4502 FREE( b ); 4503 return error; 4504 } 4505 4506 4507 static void Free_ChainPosClassRule( HB_ChainPosClassRule* cpcr ) 4508 { 4509 FREE( cpcr->PosLookupRecord ); 4510 FREE( cpcr->Lookahead ); 4511 FREE( cpcr->Input ); 4512 FREE( cpcr->Backtrack ); 4513 } 4514 4515 4516 /* PosClassSet */ 4517 4518 static HB_Error Load_ChainPosClassSet( 4519 HB_ChainContextPosFormat2* ccpf2, 4520 HB_ChainPosClassSet* cpcs, 4521 HB_Stream stream ) 4522 { 4523 HB_Error error; 4524 4525 HB_UShort n, m, count; 4526 HB_UInt cur_offset, new_offset, base_offset; 4527 4528 HB_ChainPosClassRule* cpcr; 4529 4530 4531 base_offset = FILE_Pos(); 4532 4533 if ( ACCESS_Frame( 2L ) ) 4534 return error; 4535 4536 count = cpcs->ChainPosClassRuleCount = GET_UShort(); 4537 4538 FORGET_Frame(); 4539 4540 cpcs->ChainPosClassRule = NULL; 4541 4542 if ( ALLOC_ARRAY( cpcs->ChainPosClassRule, count, 4543 HB_ChainPosClassRule ) ) 4544 return error; 4545 4546 cpcr = cpcs->ChainPosClassRule; 4547 4548 for ( n = 0; n < count; n++ ) 4549 { 4550 if ( ACCESS_Frame( 2L ) ) 4551 goto Fail; 4552 4553 new_offset = GET_UShort() + base_offset; 4554 4555 FORGET_Frame(); 4556 4557 cur_offset = FILE_Pos(); 4558 if ( FILE_Seek( new_offset ) || 4559 ( error = Load_ChainPosClassRule( ccpf2, &cpcr[n], 4560 stream ) ) != HB_Err_Ok ) 4561 goto Fail; 4562 (void)FILE_Seek( cur_offset ); 4563 } 4564 4565 return HB_Err_Ok; 4566 4567 Fail: 4568 for ( m = 0; m < n; m++ ) 4569 Free_ChainPosClassRule( &cpcr[m] ); 4570 4571 FREE( cpcr ); 4572 return error; 4573 } 4574 4575 4576 static void Free_ChainPosClassSet( HB_ChainPosClassSet* cpcs ) 4577 { 4578 HB_UShort n, count; 4579 4580 HB_ChainPosClassRule* cpcr; 4581 4582 4583 if ( cpcs->ChainPosClassRule ) 4584 { 4585 count = cpcs->ChainPosClassRuleCount; 4586 cpcr = cpcs->ChainPosClassRule; 4587 4588 for ( n = 0; n < count; n++ ) 4589 Free_ChainPosClassRule( &cpcr[n] ); 4590 4591 FREE( cpcr ); 4592 } 4593 } 4594 4595 4596 /* ChainContextPosFormat2 */ 4597 4598 static HB_Error Load_ChainContextPos2( HB_ChainContextPosFormat2* ccpf2, 4599 HB_Stream stream ) 4600 { 4601 HB_Error error; 4602 4603 HB_UShort n, m, count; 4604 HB_UInt cur_offset, new_offset, base_offset; 4605 HB_UInt backtrack_offset, input_offset, lookahead_offset; 4606 4607 HB_ChainPosClassSet* cpcs; 4608 4609 4610 base_offset = FILE_Pos() - 2; 4611 4612 if ( ACCESS_Frame( 2L ) ) 4613 return error; 4614 4615 new_offset = GET_UShort() + base_offset; 4616 4617 FORGET_Frame(); 4618 4619 cur_offset = FILE_Pos(); 4620 if ( FILE_Seek( new_offset ) || 4621 ( error = _HB_OPEN_Load_Coverage( &ccpf2->Coverage, stream ) ) != HB_Err_Ok ) 4622 return error; 4623 (void)FILE_Seek( cur_offset ); 4624 4625 if ( ACCESS_Frame( 8L ) ) 4626 goto Fail5; 4627 4628 backtrack_offset = GET_UShort(); 4629 input_offset = GET_UShort(); 4630 lookahead_offset = GET_UShort(); 4631 4632 /* `ChainPosClassSetCount' is the upper limit for input class values, 4633 thus we read it now to make an additional safety check. No limit 4634 is known or needed for the other two class definitions */ 4635 4636 count = ccpf2->ChainPosClassSetCount = GET_UShort(); 4637 4638 FORGET_Frame(); 4639 4640 if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->BacktrackClassDef, 65535, 4641 backtrack_offset, base_offset, 4642 stream ) ) != HB_Err_Ok ) 4643 goto Fail5; 4644 if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->InputClassDef, count, 4645 input_offset, base_offset, 4646 stream ) ) != HB_Err_Ok ) 4647 goto Fail4; 4648 if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->LookaheadClassDef, 65535, 4649 lookahead_offset, base_offset, 4650 stream ) ) != HB_Err_Ok ) 4651 goto Fail3; 4652 4653 ccpf2->ChainPosClassSet = NULL; 4654 ccpf2->MaxBacktrackLength = 0; 4655 ccpf2->MaxInputLength = 0; 4656 ccpf2->MaxLookaheadLength = 0; 4657 4658 if ( ALLOC_ARRAY( ccpf2->ChainPosClassSet, count, HB_ChainPosClassSet ) ) 4659 goto Fail2; 4660 4661 cpcs = ccpf2->ChainPosClassSet; 4662 4663 for ( n = 0; n < count; n++ ) 4664 { 4665 if ( ACCESS_Frame( 2L ) ) 4666 goto Fail1; 4667 4668 new_offset = GET_UShort() + base_offset; 4669 4670 FORGET_Frame(); 4671 4672 if ( new_offset != base_offset ) /* not a NULL offset */ 4673 { 4674 cur_offset = FILE_Pos(); 4675 if ( FILE_Seek( new_offset ) || 4676 ( error = Load_ChainPosClassSet( ccpf2, &cpcs[n], 4677 stream ) ) != HB_Err_Ok ) 4678 goto Fail1; 4679 (void)FILE_Seek( cur_offset ); 4680 } 4681 else 4682 { 4683 /* we create a ChainPosClassSet table with no entries */ 4684 4685 ccpf2->ChainPosClassSet[n].ChainPosClassRuleCount = 0; 4686 ccpf2->ChainPosClassSet[n].ChainPosClassRule = NULL; 4687 } 4688 } 4689 4690 return HB_Err_Ok; 4691 4692 Fail1: 4693 for ( m = 0; m < n; m++ ) 4694 Free_ChainPosClassSet( &cpcs[m] ); 4695 4696 FREE( cpcs ); 4697 4698 Fail2: 4699 _HB_OPEN_Free_ClassDefinition( &ccpf2->LookaheadClassDef ); 4700 4701 Fail3: 4702 _HB_OPEN_Free_ClassDefinition( &ccpf2->InputClassDef ); 4703 4704 Fail4: 4705 _HB_OPEN_Free_ClassDefinition( &ccpf2->BacktrackClassDef ); 4706 4707 Fail5: 4708 _HB_OPEN_Free_Coverage( &ccpf2->Coverage ); 4709 return error; 4710 } 4711 4712 4713 static void Free_ChainContextPos2( HB_ChainContextPosFormat2* ccpf2 ) 4714 { 4715 HB_UShort n, count; 4716 4717 HB_ChainPosClassSet* cpcs; 4718 4719 4720 if ( ccpf2->ChainPosClassSet ) 4721 { 4722 count = ccpf2->ChainPosClassSetCount; 4723 cpcs = ccpf2->ChainPosClassSet; 4724 4725 for ( n = 0; n < count; n++ ) 4726 Free_ChainPosClassSet( &cpcs[n] ); 4727 4728 FREE( cpcs ); 4729 } 4730 4731 _HB_OPEN_Free_ClassDefinition( &ccpf2->LookaheadClassDef ); 4732 _HB_OPEN_Free_ClassDefinition( &ccpf2->InputClassDef ); 4733 _HB_OPEN_Free_ClassDefinition( &ccpf2->BacktrackClassDef ); 4734 4735 _HB_OPEN_Free_Coverage( &ccpf2->Coverage ); 4736 } 4737 4738 4739 /* ChainContextPosFormat3 */ 4740 4741 static HB_Error Load_ChainContextPos3( HB_ChainContextPosFormat3* ccpf3, 4742 HB_Stream stream ) 4743 { 4744 HB_Error error; 4745 4746 HB_UShort n, nb, ni, nl, m, count; 4747 HB_UShort backtrack_count, input_count, lookahead_count; 4748 HB_UInt cur_offset, new_offset, base_offset; 4749 4750 HB_Coverage* b; 4751 HB_Coverage* i; 4752 HB_Coverage* l; 4753 HB_PosLookupRecord* plr; 4754 4755 4756 base_offset = FILE_Pos() - 2L; 4757 4758 if ( ACCESS_Frame( 2L ) ) 4759 return error; 4760 4761 ccpf3->BacktrackGlyphCount = GET_UShort(); 4762 4763 FORGET_Frame(); 4764 4765 ccpf3->BacktrackCoverage = NULL; 4766 4767 backtrack_count = ccpf3->BacktrackGlyphCount; 4768 4769 if ( ALLOC_ARRAY( ccpf3->BacktrackCoverage, backtrack_count, 4770 HB_Coverage ) ) 4771 return error; 4772 4773 b = ccpf3->BacktrackCoverage; 4774 4775 for ( nb = 0; nb < backtrack_count; nb++ ) 4776 { 4777 if ( ACCESS_Frame( 2L ) ) 4778 goto Fail4; 4779 4780 new_offset = GET_UShort() + base_offset; 4781 4782 FORGET_Frame(); 4783 4784 cur_offset = FILE_Pos(); 4785 if ( FILE_Seek( new_offset ) || 4786 ( error = _HB_OPEN_Load_Coverage( &b[nb], stream ) ) != HB_Err_Ok ) 4787 goto Fail4; 4788 (void)FILE_Seek( cur_offset ); 4789 } 4790 4791 if ( ACCESS_Frame( 2L ) ) 4792 goto Fail4; 4793 4794 ccpf3->InputGlyphCount = GET_UShort(); 4795 4796 FORGET_Frame(); 4797 4798 ccpf3->InputCoverage = NULL; 4799 4800 input_count = ccpf3->InputGlyphCount; 4801 4802 if ( ALLOC_ARRAY( ccpf3->InputCoverage, input_count, HB_Coverage ) ) 4803 goto Fail4; 4804 4805 i = ccpf3->InputCoverage; 4806 4807 for ( ni = 0; ni < input_count; ni++ ) 4808 { 4809 if ( ACCESS_Frame( 2L ) ) 4810 goto Fail3; 4811 4812 new_offset = GET_UShort() + base_offset; 4813 4814 FORGET_Frame(); 4815 4816 cur_offset = FILE_Pos(); 4817 if ( FILE_Seek( new_offset ) || 4818 ( error = _HB_OPEN_Load_Coverage( &i[ni], stream ) ) != HB_Err_Ok ) 4819 goto Fail3; 4820 (void)FILE_Seek( cur_offset ); 4821 } 4822 4823 if ( ACCESS_Frame( 2L ) ) 4824 goto Fail3; 4825 4826 ccpf3->LookaheadGlyphCount = GET_UShort(); 4827 4828 FORGET_Frame(); 4829 4830 ccpf3->LookaheadCoverage = NULL; 4831 4832 lookahead_count = ccpf3->LookaheadGlyphCount; 4833 4834 if ( ALLOC_ARRAY( ccpf3->LookaheadCoverage, lookahead_count, 4835 HB_Coverage ) ) 4836 goto Fail3; 4837 4838 l = ccpf3->LookaheadCoverage; 4839 4840 for ( nl = 0; nl < lookahead_count; nl++ ) 4841 { 4842 if ( ACCESS_Frame( 2L ) ) 4843 goto Fail2; 4844 4845 new_offset = GET_UShort() + base_offset; 4846 4847 FORGET_Frame(); 4848 4849 cur_offset = FILE_Pos(); 4850 if ( FILE_Seek( new_offset ) || 4851 ( error = _HB_OPEN_Load_Coverage( &l[nl], stream ) ) != HB_Err_Ok ) 4852 goto Fail2; 4853 (void)FILE_Seek( cur_offset ); 4854 } 4855 4856 if ( ACCESS_Frame( 2L ) ) 4857 goto Fail2; 4858 4859 ccpf3->PosCount = GET_UShort(); 4860 4861 FORGET_Frame(); 4862 4863 ccpf3->PosLookupRecord = NULL; 4864 4865 count = ccpf3->PosCount; 4866 4867 if ( ALLOC_ARRAY( ccpf3->PosLookupRecord, count, HB_PosLookupRecord ) ) 4868 goto Fail2; 4869 4870 plr = ccpf3->PosLookupRecord; 4871 4872 if ( ACCESS_Frame( count * 4L ) ) 4873 goto Fail1; 4874 4875 for ( n = 0; n < count; n++ ) 4876 { 4877 plr[n].SequenceIndex = GET_UShort(); 4878 plr[n].LookupListIndex = GET_UShort(); 4879 } 4880 4881 FORGET_Frame(); 4882 4883 return HB_Err_Ok; 4884 4885 Fail1: 4886 FREE( plr ); 4887 4888 Fail2: 4889 for ( m = 0; m < nl; m++ ) 4890 _HB_OPEN_Free_Coverage( &l[m] ); 4891 4892 FREE( l ); 4893 4894 Fail3: 4895 for ( m = 0; m < ni; m++ ) 4896 _HB_OPEN_Free_Coverage( &i[m] ); 4897 4898 FREE( i ); 4899 4900 Fail4: 4901 for ( m = 0; m < nb; m++ ) 4902 _HB_OPEN_Free_Coverage( &b[m] ); 4903 4904 FREE( b ); 4905 return error; 4906 } 4907 4908 4909 static void Free_ChainContextPos3( HB_ChainContextPosFormat3* ccpf3 ) 4910 { 4911 HB_UShort n, count; 4912 4913 HB_Coverage* c; 4914 4915 4916 FREE( ccpf3->PosLookupRecord ); 4917 4918 if ( ccpf3->LookaheadCoverage ) 4919 { 4920 count = ccpf3->LookaheadGlyphCount; 4921 c = ccpf3->LookaheadCoverage; 4922 4923 for ( n = 0; n < count; n++ ) 4924 _HB_OPEN_Free_Coverage( &c[n] ); 4925 4926 FREE( c ); 4927 } 4928 4929 if ( ccpf3->InputCoverage ) 4930 { 4931 count = ccpf3->InputGlyphCount; 4932 c = ccpf3->InputCoverage; 4933 4934 for ( n = 0; n < count; n++ ) 4935 _HB_OPEN_Free_Coverage( &c[n] ); 4936 4937 FREE( c ); 4938 } 4939 4940 if ( ccpf3->BacktrackCoverage ) 4941 { 4942 count = ccpf3->BacktrackGlyphCount; 4943 c = ccpf3->BacktrackCoverage; 4944 4945 for ( n = 0; n < count; n++ ) 4946 _HB_OPEN_Free_Coverage( &c[n] ); 4947 4948 FREE( c ); 4949 } 4950 } 4951 4952 4953 /* ChainContextPos */ 4954 4955 static HB_Error Load_ChainContextPos( HB_GPOS_SubTable* st, 4956 HB_Stream stream ) 4957 { 4958 HB_Error error; 4959 HB_ChainContextPos* ccp = &st->chain; 4960 4961 4962 if ( ACCESS_Frame( 2L ) ) 4963 return error; 4964 4965 ccp->PosFormat = GET_UShort(); 4966 4967 FORGET_Frame(); 4968 4969 switch ( ccp->PosFormat ) 4970 { 4971 case 1: 4972 return Load_ChainContextPos1( &ccp->ccpf.ccpf1, stream ); 4973 4974 case 2: 4975 return Load_ChainContextPos2( &ccp->ccpf.ccpf2, stream ); 4976 4977 case 3: 4978 return Load_ChainContextPos3( &ccp->ccpf.ccpf3, stream ); 4979 4980 default: 4981 return ERR(HB_Err_Invalid_SubTable_Format); 4982 } 4983 4984 return HB_Err_Ok; /* never reached */ 4985 } 4986 4987 4988 static void Free_ChainContextPos( HB_GPOS_SubTable* st ) 4989 { 4990 HB_ChainContextPos* ccp = &st->chain; 4991 4992 switch ( ccp->PosFormat ) 4993 { 4994 case 1: Free_ChainContextPos1( &ccp->ccpf.ccpf1 ); break; 4995 case 2: Free_ChainContextPos2( &ccp->ccpf.ccpf2 ); break; 4996 case 3: Free_ChainContextPos3( &ccp->ccpf.ccpf3 ); break; 4997 default: break; 4998 } 4999 } 5000 5001 5002 static HB_Error Lookup_ChainContextPos1( 5003 GPOS_Instance* gpi, 5004 HB_ChainContextPosFormat1* ccpf1, 5005 HB_Buffer buffer, 5006 HB_UShort flags, 5007 HB_UShort context_length, 5008 int nesting_level ) 5009 { 5010 HB_UShort index, property; 5011 HB_UShort i, j, k, num_cpr; 5012 HB_UShort bgc, igc, lgc; 5013 HB_Error error; 5014 HB_GPOSHeader* gpos = gpi->gpos; 5015 5016 HB_ChainPosRule* cpr; 5017 HB_ChainPosRule curr_cpr; 5018 HB_GDEFHeader* gdef; 5019 5020 5021 gdef = gpos->gdef; 5022 5023 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) 5024 return error; 5025 5026 error = _HB_OPEN_Coverage_Index( &ccpf1->Coverage, IN_CURGLYPH(), &index ); 5027 if ( error ) 5028 return error; 5029 5030 cpr = ccpf1->ChainPosRuleSet[index].ChainPosRule; 5031 num_cpr = ccpf1->ChainPosRuleSet[index].ChainPosRuleCount; 5032 5033 for ( k = 0; k < num_cpr; k++ ) 5034 { 5035 curr_cpr = cpr[k]; 5036 bgc = curr_cpr.BacktrackGlyphCount; 5037 igc = curr_cpr.InputGlyphCount; 5038 lgc = curr_cpr.LookaheadGlyphCount; 5039 5040 if ( context_length != 0xFFFF && context_length < igc ) 5041 goto next_chainposrule; 5042 5043 /* check whether context is too long; it is a first guess only */ 5044 5045 if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length ) 5046 goto next_chainposrule; 5047 5048 if ( bgc ) 5049 { 5050 /* Since we don't know in advance the number of glyphs to inspect, 5051 we search backwards for matches in the backtrack glyph array */ 5052 5053 for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- ) 5054 { 5055 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) 5056 { 5057 if ( error && error != HB_Err_Not_Covered ) 5058 return error; 5059 5060 if ( j + 1 == bgc - i ) 5061 goto next_chainposrule; 5062 j--; 5063 } 5064 5065 /* In OpenType 1.3, it is undefined whether the offsets of 5066 backtrack glyphs is in logical order or not. Version 1.4 5067 will clarify this: 5068 5069 Logical order - a b c d e f g h i j 5070 i 5071 Input offsets - 0 1 5072 Backtrack offsets - 3 2 1 0 5073 Lookahead offsets - 0 1 2 3 */ 5074 5075 if ( IN_GLYPH( j ) != curr_cpr.Backtrack[i] ) 5076 goto next_chainposrule; 5077 } 5078 } 5079 5080 /* Start at 1 because [0] is implied */ 5081 5082 for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ ) 5083 { 5084 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) 5085 { 5086 if ( error && error != HB_Err_Not_Covered ) 5087 return error; 5088 5089 if ( j + igc - i + lgc == (HB_Int)buffer->in_length ) 5090 goto next_chainposrule; 5091 j++; 5092 } 5093 5094 if ( IN_GLYPH( j ) != curr_cpr.Input[i - 1] ) 5095 goto next_chainposrule; 5096 } 5097 5098 /* we are starting to check for lookahead glyphs right after the 5099 last context glyph */ 5100 5101 for ( i = 0; i < lgc; i++, j++ ) 5102 { 5103 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) 5104 { 5105 if ( error && error != HB_Err_Not_Covered ) 5106 return error; 5107 5108 if ( j + lgc - i == (HB_Int)buffer->in_length ) 5109 goto next_chainposrule; 5110 j++; 5111 } 5112 5113 if ( IN_GLYPH( j ) != curr_cpr.Lookahead[i] ) 5114 goto next_chainposrule; 5115 } 5116 5117 return Do_ContextPos( gpi, igc, 5118 curr_cpr.PosCount, 5119 curr_cpr.PosLookupRecord, 5120 buffer, 5121 nesting_level ); 5122 5123 next_chainposrule: 5124 ; 5125 } 5126 5127 return HB_Err_Not_Covered; 5128 } 5129 5130 5131 static HB_Error Lookup_ChainContextPos2( 5132 GPOS_Instance* gpi, 5133 HB_ChainContextPosFormat2* ccpf2, 5134 HB_Buffer buffer, 5135 HB_UShort flags, 5136 HB_UShort context_length, 5137 int nesting_level ) 5138 { 5139 HB_UShort index, property; 5140 HB_Error error; 5141 HB_UShort i, j, k; 5142 HB_UShort bgc, igc, lgc; 5143 HB_UShort known_backtrack_classes, 5144 known_input_classes, 5145 known_lookahead_classes; 5146 5147 HB_UShort* backtrack_classes; 5148 HB_UShort* input_classes; 5149 HB_UShort* lookahead_classes; 5150 5151 HB_UShort* bc; 5152 HB_UShort* ic; 5153 HB_UShort* lc; 5154 HB_GPOSHeader* gpos = gpi->gpos; 5155 5156 HB_ChainPosClassSet* cpcs; 5157 HB_ChainPosClassRule cpcr; 5158 HB_GDEFHeader* gdef; 5159 5160 5161 gdef = gpos->gdef; 5162 5163 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) 5164 return error; 5165 5166 /* Note: The coverage table in format 2 doesn't give an index into 5167 anything. It just lets us know whether or not we need to 5168 do any lookup at all. */ 5169 5170 error = _HB_OPEN_Coverage_Index( &ccpf2->Coverage, IN_CURGLYPH(), &index ); 5171 if ( error ) 5172 return error; 5173 5174 if (ccpf2->MaxInputLength < 1) 5175 return HB_Err_Not_Covered; 5176 5177 if ( ALLOC_ARRAY( backtrack_classes, ccpf2->MaxBacktrackLength, HB_UShort ) ) 5178 return error; 5179 known_backtrack_classes = 0; 5180 5181 if ( ALLOC_ARRAY( input_classes, ccpf2->MaxInputLength, HB_UShort ) ) 5182 goto End3; 5183 known_input_classes = 1; 5184 5185 if ( ALLOC_ARRAY( lookahead_classes, ccpf2->MaxLookaheadLength, HB_UShort ) ) 5186 goto End2; 5187 known_lookahead_classes = 0; 5188 5189 error = _HB_OPEN_Get_Class( &ccpf2->InputClassDef, IN_CURGLYPH(), 5190 &input_classes[0], NULL ); 5191 if ( error && error != HB_Err_Not_Covered ) 5192 goto End1; 5193 5194 cpcs = &ccpf2->ChainPosClassSet[input_classes[0]]; 5195 if ( !cpcs ) 5196 { 5197 error = ERR(HB_Err_Invalid_SubTable); 5198 goto End1; 5199 } 5200 5201 for ( k = 0; k < cpcs->ChainPosClassRuleCount; k++ ) 5202 { 5203 cpcr = cpcs->ChainPosClassRule[k]; 5204 bgc = cpcr.BacktrackGlyphCount; 5205 igc = cpcr.InputGlyphCount; 5206 lgc = cpcr.LookaheadGlyphCount; 5207 5208 if ( context_length != 0xFFFF && context_length < igc ) 5209 goto next_chainposclassrule; 5210 5211 /* check whether context is too long; it is a first guess only */ 5212 5213 if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length ) 5214 goto next_chainposclassrule; 5215 5216 if ( bgc ) 5217 { 5218 /* Since we don't know in advance the number of glyphs to inspect, 5219 we search backwards for matches in the backtrack glyph array. 5220 Note that `known_backtrack_classes' starts at index 0. */ 5221 5222 bc = cpcr.Backtrack; 5223 5224 for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- ) 5225 { 5226 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) 5227 { 5228 if ( error && error != HB_Err_Not_Covered ) 5229 goto End1; 5230 5231 if ( j + 1 == bgc - i ) 5232 goto next_chainposclassrule; 5233 j++; 5234 } 5235 5236 if ( i >= known_backtrack_classes ) 5237 { 5238 /* Keeps us from having to do this for each rule */ 5239 5240 error = _HB_OPEN_Get_Class( &ccpf2->BacktrackClassDef, IN_GLYPH( j ), 5241 &backtrack_classes[i], NULL ); 5242 if ( error && error != HB_Err_Not_Covered ) 5243 goto End1; 5244 known_backtrack_classes = i; 5245 } 5246 5247 if ( bc[i] != backtrack_classes[i] ) 5248 goto next_chainposclassrule; 5249 } 5250 } 5251 5252 ic = cpcr.Input; 5253 5254 /* Start at 1 because [0] is implied */ 5255 5256 for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ ) 5257 { 5258 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) 5259 { 5260 if ( error && error != HB_Err_Not_Covered ) 5261 goto End1; 5262 5263 if ( j + igc - i + lgc == (HB_Int)buffer->in_length ) 5264 goto next_chainposclassrule; 5265 j++; 5266 } 5267 5268 if ( i >= known_input_classes ) 5269 { 5270 error = _HB_OPEN_Get_Class( &ccpf2->InputClassDef, IN_GLYPH( j ), 5271 &input_classes[i], NULL ); 5272 if ( error && error != HB_Err_Not_Covered ) 5273 goto End1; 5274 known_input_classes = i; 5275 } 5276 5277 if ( ic[i - 1] != input_classes[i] ) 5278 goto next_chainposclassrule; 5279 } 5280 5281 /* we are starting to check for lookahead glyphs right after the 5282 last context glyph */ 5283 5284 lc = cpcr.Lookahead; 5285 5286 for ( i = 0; i < lgc; i++, j++ ) 5287 { 5288 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) 5289 { 5290 if ( error && error != HB_Err_Not_Covered ) 5291 goto End1; 5292 5293 if ( j + lgc - i == (HB_Int)buffer->in_length ) 5294 goto next_chainposclassrule; 5295 j++; 5296 } 5297 5298 if ( i >= known_lookahead_classes ) 5299 { 5300 error = _HB_OPEN_Get_Class( &ccpf2->LookaheadClassDef, IN_GLYPH( j ), 5301 &lookahead_classes[i], NULL ); 5302 if ( error && error != HB_Err_Not_Covered ) 5303 goto End1; 5304 known_lookahead_classes = i; 5305 } 5306 5307 if ( lc[i] != lookahead_classes[i] ) 5308 goto next_chainposclassrule; 5309 } 5310 5311 error = Do_ContextPos( gpi, igc, 5312 cpcr.PosCount, 5313 cpcr.PosLookupRecord, 5314 buffer, 5315 nesting_level ); 5316 goto End1; 5317 5318 next_chainposclassrule: 5319 ; 5320 } 5321 5322 error = HB_Err_Not_Covered; 5323 5324 End1: 5325 FREE( lookahead_classes ); 5326 5327 End2: 5328 FREE( input_classes ); 5329 5330 End3: 5331 FREE( backtrack_classes ); 5332 return error; 5333 } 5334 5335 5336 static HB_Error Lookup_ChainContextPos3( 5337 GPOS_Instance* gpi, 5338 HB_ChainContextPosFormat3* ccpf3, 5339 HB_Buffer buffer, 5340 HB_UShort flags, 5341 HB_UShort context_length, 5342 int nesting_level ) 5343 { 5344 HB_UShort index, i, j, property; 5345 HB_UShort bgc, igc, lgc; 5346 HB_Error error; 5347 HB_GPOSHeader* gpos = gpi->gpos; 5348 5349 HB_Coverage* bc; 5350 HB_Coverage* ic; 5351 HB_Coverage* lc; 5352 HB_GDEFHeader* gdef; 5353 5354 5355 gdef = gpos->gdef; 5356 5357 if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) 5358 return error; 5359 5360 bgc = ccpf3->BacktrackGlyphCount; 5361 igc = ccpf3->InputGlyphCount; 5362 lgc = ccpf3->LookaheadGlyphCount; 5363 5364 if ( context_length != 0xFFFF && context_length < igc ) 5365 return HB_Err_Not_Covered; 5366 5367 /* check whether context is too long; it is a first guess only */ 5368 5369 if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length ) 5370 return HB_Err_Not_Covered; 5371 5372 if ( bgc ) 5373 { 5374 /* Since we don't know in advance the number of glyphs to inspect, 5375 we search backwards for matches in the backtrack glyph array */ 5376 5377 bc = ccpf3->BacktrackCoverage; 5378 5379 for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- ) 5380 { 5381 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) 5382 { 5383 if ( error && error != HB_Err_Not_Covered ) 5384 return error; 5385 5386 if ( j + 1 == bgc - i ) 5387 return HB_Err_Not_Covered; 5388 j--; 5389 } 5390 5391 error = _HB_OPEN_Coverage_Index( &bc[i], IN_GLYPH( j ), &index ); 5392 if ( error ) 5393 return error; 5394 } 5395 } 5396 5397 ic = ccpf3->InputCoverage; 5398 5399 for ( i = 0, j = buffer->in_pos; i < igc; i++, j++ ) 5400 { 5401 /* We already called CHECK_Property for IN_GLYPH ( buffer->in_pos ) */ 5402 while ( j > buffer->in_pos && CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) 5403 { 5404 if ( error && error != HB_Err_Not_Covered ) 5405 return error; 5406 5407 if ( j + igc - i + lgc == (HB_Int)buffer->in_length ) 5408 return HB_Err_Not_Covered; 5409 j++; 5410 } 5411 5412 error = _HB_OPEN_Coverage_Index( &ic[i], IN_GLYPH( j ), &index ); 5413 if ( error ) 5414 return error; 5415 } 5416 5417 /* we are starting to check for lookahead glyphs right after the 5418 last context glyph */ 5419 5420 lc = ccpf3->LookaheadCoverage; 5421 5422 for ( i = 0; i < lgc; i++, j++ ) 5423 { 5424 while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) 5425 { 5426 if ( error && error != HB_Err_Not_Covered ) 5427 return error; 5428 5429 if ( j + lgc - i == (HB_Int)buffer->in_length ) 5430 return HB_Err_Not_Covered; 5431 j++; 5432 } 5433 5434 error = _HB_OPEN_Coverage_Index( &lc[i], IN_GLYPH( j ), &index ); 5435 if ( error ) 5436 return error; 5437 } 5438 5439 return Do_ContextPos( gpi, igc, 5440 ccpf3->PosCount, 5441 ccpf3->PosLookupRecord, 5442 buffer, 5443 nesting_level ); 5444 } 5445 5446 5447 static HB_Error Lookup_ChainContextPos( 5448 GPOS_Instance* gpi, 5449 HB_GPOS_SubTable* st, 5450 HB_Buffer buffer, 5451 HB_UShort flags, 5452 HB_UShort context_length, 5453 int nesting_level ) 5454 { 5455 HB_ChainContextPos* ccp = &st->chain; 5456 5457 switch ( ccp->PosFormat ) 5458 { 5459 case 1: 5460 return Lookup_ChainContextPos1( gpi, &ccp->ccpf.ccpf1, buffer, 5461 flags, context_length, 5462 nesting_level ); 5463 5464 case 2: 5465 return Lookup_ChainContextPos2( gpi, &ccp->ccpf.ccpf2, buffer, 5466 flags, context_length, 5467 nesting_level ); 5468 5469 case 3: 5470 return Lookup_ChainContextPos3( gpi, &ccp->ccpf.ccpf3, buffer, 5471 flags, context_length, 5472 nesting_level ); 5473 5474 default: 5475 return ERR(HB_Err_Invalid_SubTable_Format); 5476 } 5477 5478 return HB_Err_Ok; /* never reached */ 5479 } 5480 5481 5482 5483 /*********** 5484 * GPOS API 5485 ***********/ 5486 5487 5488 5489 HB_Error HB_GPOS_Select_Script( HB_GPOSHeader* gpos, 5490 HB_UInt script_tag, 5491 HB_UShort* script_index ) 5492 { 5493 HB_UShort n; 5494 5495 HB_ScriptList* sl; 5496 HB_ScriptRecord* sr; 5497 5498 5499 if ( !gpos || !script_index ) 5500 return ERR(HB_Err_Invalid_Argument); 5501 5502 sl = &gpos->ScriptList; 5503 sr = sl->ScriptRecord; 5504 5505 for ( n = 0; n < sl->ScriptCount; n++ ) 5506 if ( script_tag == sr[n].ScriptTag ) 5507 { 5508 *script_index = n; 5509 5510 return HB_Err_Ok; 5511 } 5512 5513 return HB_Err_Not_Covered; 5514 } 5515 5516 5517 5518 HB_Error HB_GPOS_Select_Language( HB_GPOSHeader* gpos, 5519 HB_UInt language_tag, 5520 HB_UShort script_index, 5521 HB_UShort* language_index, 5522 HB_UShort* req_feature_index ) 5523 { 5524 HB_UShort n; 5525 5526 HB_ScriptList* sl; 5527 HB_ScriptRecord* sr; 5528 HB_ScriptTable* s; 5529 HB_LangSysRecord* lsr; 5530 5531 5532 if ( !gpos || !language_index || !req_feature_index ) 5533 return ERR(HB_Err_Invalid_Argument); 5534 5535 sl = &gpos->ScriptList; 5536 sr = sl->ScriptRecord; 5537 5538 if ( script_index >= sl->ScriptCount ) 5539 return ERR(HB_Err_Invalid_Argument); 5540 5541 s = &sr[script_index].Script; 5542 lsr = s->LangSysRecord; 5543 5544 for ( n = 0; n < s->LangSysCount; n++ ) 5545 if ( language_tag == lsr[n].LangSysTag ) 5546 { 5547 *language_index = n; 5548 *req_feature_index = lsr[n].LangSys.ReqFeatureIndex; 5549 5550 return HB_Err_Ok; 5551 } 5552 5553 return HB_Err_Not_Covered; 5554 } 5555 5556 5557 /* selecting 0xFFFF for language_index asks for the values of the 5558 default language (DefaultLangSys) */ 5559 5560 5561 HB_Error HB_GPOS_Select_Feature( HB_GPOSHeader* gpos, 5562 HB_UInt feature_tag, 5563 HB_UShort script_index, 5564 HB_UShort language_index, 5565 HB_UShort* feature_index ) 5566 { 5567 HB_UShort n; 5568 5569 HB_ScriptList* sl; 5570 HB_ScriptRecord* sr; 5571 HB_ScriptTable* s; 5572 HB_LangSysRecord* lsr; 5573 HB_LangSys* ls; 5574 HB_UShort* fi; 5575 5576 HB_FeatureList* fl; 5577 HB_FeatureRecord* fr; 5578 5579 5580 if ( !gpos || !feature_index ) 5581 return ERR(HB_Err_Invalid_Argument); 5582 5583 sl = &gpos->ScriptList; 5584 sr = sl->ScriptRecord; 5585 5586 fl = &gpos->FeatureList; 5587 fr = fl->FeatureRecord; 5588 5589 if ( script_index >= sl->ScriptCount ) 5590 return ERR(HB_Err_Invalid_Argument); 5591 5592 s = &sr[script_index].Script; 5593 lsr = s->LangSysRecord; 5594 5595 if ( language_index == 0xFFFF ) 5596 ls = &s->DefaultLangSys; 5597 else 5598 { 5599 if ( language_index >= s->LangSysCount ) 5600 return ERR(HB_Err_Invalid_Argument); 5601 5602 ls = &lsr[language_index].LangSys; 5603 } 5604 5605 fi = ls->FeatureIndex; 5606 5607 for ( n = 0; n < ls->FeatureCount; n++ ) 5608 { 5609 if ( fi[n] >= fl->FeatureCount ) 5610 return ERR(HB_Err_Invalid_SubTable_Format); 5611 5612 if ( feature_tag == fr[fi[n]].FeatureTag ) 5613 { 5614 *feature_index = fi[n]; 5615 5616 return HB_Err_Ok; 5617 } 5618 } 5619 5620 return HB_Err_Not_Covered; 5621 } 5622 5623 5624 /* The next three functions return a null-terminated list */ 5625 5626 5627 HB_Error HB_GPOS_Query_Scripts( HB_GPOSHeader* gpos, 5628 HB_UInt** script_tag_list ) 5629 { 5630 HB_Error error; 5631 HB_UShort n; 5632 HB_UInt* stl; 5633 5634 HB_ScriptList* sl; 5635 HB_ScriptRecord* sr; 5636 5637 5638 if ( !gpos || !script_tag_list ) 5639 return ERR(HB_Err_Invalid_Argument); 5640 5641 sl = &gpos->ScriptList; 5642 sr = sl->ScriptRecord; 5643 5644 if ( ALLOC_ARRAY( stl, sl->ScriptCount + 1, HB_UInt ) ) 5645 return error; 5646 5647 for ( n = 0; n < sl->ScriptCount; n++ ) 5648 stl[n] = sr[n].ScriptTag; 5649 stl[n] = 0; 5650 5651 *script_tag_list = stl; 5652 5653 return HB_Err_Ok; 5654 } 5655 5656 5657 5658 HB_Error HB_GPOS_Query_Languages( HB_GPOSHeader* gpos, 5659 HB_UShort script_index, 5660 HB_UInt** language_tag_list ) 5661 { 5662 HB_Error error; 5663 HB_UShort n; 5664 HB_UInt* ltl; 5665 5666 HB_ScriptList* sl; 5667 HB_ScriptRecord* sr; 5668 HB_ScriptTable* s; 5669 HB_LangSysRecord* lsr; 5670 5671 5672 if ( !gpos || !language_tag_list ) 5673 return ERR(HB_Err_Invalid_Argument); 5674 5675 sl = &gpos->ScriptList; 5676 sr = sl->ScriptRecord; 5677 5678 if ( script_index >= sl->ScriptCount ) 5679 return ERR(HB_Err_Invalid_Argument); 5680 5681 s = &sr[script_index].Script; 5682 lsr = s->LangSysRecord; 5683 5684 if ( ALLOC_ARRAY( ltl, s->LangSysCount + 1, HB_UInt ) ) 5685 return error; 5686 5687 for ( n = 0; n < s->LangSysCount; n++ ) 5688 ltl[n] = lsr[n].LangSysTag; 5689 ltl[n] = 0; 5690 5691 *language_tag_list = ltl; 5692 5693 return HB_Err_Ok; 5694 } 5695 5696 5697 /* selecting 0xFFFF for language_index asks for the values of the 5698 default language (DefaultLangSys) */ 5699 5700 5701 HB_Error HB_GPOS_Query_Features( HB_GPOSHeader* gpos, 5702 HB_UShort script_index, 5703 HB_UShort language_index, 5704 HB_UInt** feature_tag_list ) 5705 { 5706 HB_UShort n; 5707 HB_Error error; 5708 HB_UInt* ftl; 5709 5710 HB_ScriptList* sl; 5711 HB_ScriptRecord* sr; 5712 HB_ScriptTable* s; 5713 HB_LangSysRecord* lsr; 5714 HB_LangSys* ls; 5715 HB_UShort* fi; 5716 5717 HB_FeatureList* fl; 5718 HB_FeatureRecord* fr; 5719 5720 5721 if ( !gpos || !feature_tag_list ) 5722 return ERR(HB_Err_Invalid_Argument); 5723 5724 sl = &gpos->ScriptList; 5725 sr = sl->ScriptRecord; 5726 5727 fl = &gpos->FeatureList; 5728 fr = fl->FeatureRecord; 5729 5730 if ( script_index >= sl->ScriptCount ) 5731 return ERR(HB_Err_Invalid_Argument); 5732 5733 s = &sr[script_index].Script; 5734 lsr = s->LangSysRecord; 5735 5736 if ( language_index == 0xFFFF ) 5737 ls = &s->DefaultLangSys; 5738 else 5739 { 5740 if ( language_index >= s->LangSysCount ) 5741 return ERR(HB_Err_Invalid_Argument); 5742 5743 ls = &lsr[language_index].LangSys; 5744 } 5745 5746 fi = ls->FeatureIndex; 5747 5748 if ( ALLOC_ARRAY( ftl, ls->FeatureCount + 1, HB_UInt ) ) 5749 return error; 5750 5751 for ( n = 0; n < ls->FeatureCount; n++ ) 5752 { 5753 if ( fi[n] >= fl->FeatureCount ) 5754 { 5755 FREE( ftl ); 5756 return ERR(HB_Err_Invalid_SubTable_Format); 5757 } 5758 ftl[n] = fr[fi[n]].FeatureTag; 5759 } 5760 ftl[n] = 0; 5761 5762 *feature_tag_list = ftl; 5763 5764 return HB_Err_Ok; 5765 } 5766 5767 5768 /* Do an individual subtable lookup. Returns HB_Err_Ok if positioning 5769 has been done, or HB_Err_Not_Covered if not. */ 5770 static HB_Error GPOS_Do_Glyph_Lookup( GPOS_Instance* gpi, 5771 HB_UShort lookup_index, 5772 HB_Buffer buffer, 5773 HB_UShort context_length, 5774 int nesting_level ) 5775 { 5776 HB_Error error = HB_Err_Not_Covered; 5777 HB_UShort i, flags, lookup_count; 5778 HB_GPOSHeader* gpos = gpi->gpos; 5779 HB_Lookup* lo; 5780 int lookup_type; 5781 5782 5783 nesting_level++; 5784 5785 if ( nesting_level > HB_MAX_NESTING_LEVEL ) 5786 return ERR(HB_Err_Not_Covered); /* ERR() call intended */ 5787 5788 lookup_count = gpos->LookupList.LookupCount; 5789 if (lookup_index >= lookup_count) 5790 return error; 5791 5792 lo = &gpos->LookupList.Lookup[lookup_index]; 5793 flags = lo->LookupFlag; 5794 lookup_type = lo->LookupType; 5795 5796 for ( i = 0; i < lo->SubTableCount; i++ ) 5797 { 5798 HB_GPOS_SubTable *st = &lo->SubTable[i].st.gpos; 5799 5800 switch (lookup_type) { 5801 case HB_GPOS_LOOKUP_SINGLE: 5802 error = Lookup_SinglePos ( gpi, st, buffer, flags, context_length, nesting_level ); break; 5803 case HB_GPOS_LOOKUP_PAIR: 5804 error = Lookup_PairPos ( gpi, st, buffer, flags, context_length, nesting_level ); break; 5805 case HB_GPOS_LOOKUP_CURSIVE: 5806 error = Lookup_CursivePos ( gpi, st, buffer, flags, context_length, nesting_level ); break; 5807 case HB_GPOS_LOOKUP_MARKBASE: 5808 error = Lookup_MarkBasePos ( gpi, st, buffer, flags, context_length, nesting_level ); break; 5809 case HB_GPOS_LOOKUP_MARKLIG: 5810 error = Lookup_MarkLigPos ( gpi, st, buffer, flags, context_length, nesting_level ); break; 5811 case HB_GPOS_LOOKUP_MARKMARK: 5812 error = Lookup_MarkMarkPos ( gpi, st, buffer, flags, context_length, nesting_level ); break; 5813 case HB_GPOS_LOOKUP_CONTEXT: 5814 error = Lookup_ContextPos ( gpi, st, buffer, flags, context_length, nesting_level ); break; 5815 case HB_GPOS_LOOKUP_CHAIN: 5816 error = Lookup_ChainContextPos ( gpi, st, buffer, flags, context_length, nesting_level ); break; 5817 /*case HB_GPOS_LOOKUP_EXTENSION: 5818 error = Lookup_ExtensionPos ( gpi, st, buffer, flags, context_length, nesting_level ); break;*/ 5819 default: 5820 error = HB_Err_Not_Covered; 5821 } 5822 5823 /* Check whether we have a successful positioning or an error other 5824 than HB_Err_Not_Covered */ 5825 if ( error != HB_Err_Not_Covered ) 5826 return error; 5827 } 5828 5829 return HB_Err_Not_Covered; 5830 } 5831 5832 5833 HB_INTERNAL HB_Error 5834 _HB_GPOS_Load_SubTable( HB_GPOS_SubTable* st, 5835 HB_Stream stream, 5836 HB_UShort lookup_type ) 5837 { 5838 switch ( lookup_type ) { 5839 case HB_GPOS_LOOKUP_SINGLE: return Load_SinglePos ( st, stream ); 5840 case HB_GPOS_LOOKUP_PAIR: return Load_PairPos ( st, stream ); 5841 case HB_GPOS_LOOKUP_CURSIVE: return Load_CursivePos ( st, stream ); 5842 case HB_GPOS_LOOKUP_MARKBASE: return Load_MarkBasePos ( st, stream ); 5843 case HB_GPOS_LOOKUP_MARKLIG: return Load_MarkLigPos ( st, stream ); 5844 case HB_GPOS_LOOKUP_MARKMARK: return Load_MarkMarkPos ( st, stream ); 5845 case HB_GPOS_LOOKUP_CONTEXT: return Load_ContextPos ( st, stream ); 5846 case HB_GPOS_LOOKUP_CHAIN: return Load_ChainContextPos ( st, stream ); 5847 /*case HB_GPOS_LOOKUP_EXTENSION: return Load_ExtensionPos ( st, stream );*/ 5848 default: return ERR(HB_Err_Invalid_SubTable_Format); 5849 } 5850 } 5851 5852 5853 HB_INTERNAL void 5854 _HB_GPOS_Free_SubTable( HB_GPOS_SubTable* st, 5855 HB_UShort lookup_type ) 5856 { 5857 switch ( lookup_type ) { 5858 case HB_GPOS_LOOKUP_SINGLE: Free_SinglePos ( st ); return; 5859 case HB_GPOS_LOOKUP_PAIR: Free_PairPos ( st ); return; 5860 case HB_GPOS_LOOKUP_CURSIVE: Free_CursivePos ( st ); return; 5861 case HB_GPOS_LOOKUP_MARKBASE: Free_MarkBasePos ( st ); return; 5862 case HB_GPOS_LOOKUP_MARKLIG: Free_MarkLigPos ( st ); return; 5863 case HB_GPOS_LOOKUP_MARKMARK: Free_MarkMarkPos ( st ); return; 5864 case HB_GPOS_LOOKUP_CONTEXT: Free_ContextPos ( st ); return; 5865 case HB_GPOS_LOOKUP_CHAIN: Free_ChainContextPos ( st ); return; 5866 /*case HB_GPOS_LOOKUP_EXTENSION: Free_ExtensionPos ( st ); return;*/ 5867 default: return; 5868 } 5869 } 5870 5871 5872 /* apply one lookup to the input string object */ 5873 5874 static HB_Error GPOS_Do_String_Lookup( GPOS_Instance* gpi, 5875 HB_UShort lookup_index, 5876 HB_Buffer buffer ) 5877 { 5878 HB_Error error, retError = HB_Err_Not_Covered; 5879 HB_GPOSHeader* gpos = gpi->gpos; 5880 5881 HB_UInt* properties = gpos->LookupList.Properties; 5882 5883 const int nesting_level = 0; 5884 /* 0xFFFF indicates that we don't have a context length yet */ 5885 const HB_UShort context_length = 0xFFFF; 5886 5887 5888 gpi->last = 0xFFFF; /* no last valid glyph for cursive pos. */ 5889 5890 buffer->in_pos = 0; 5891 while ( buffer->in_pos < buffer->in_length ) 5892 { 5893 if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] ) 5894 { 5895 /* Note that the connection between mark and base glyphs hold 5896 exactly one (string) lookup. For example, it would be possible 5897 that in the first lookup, mark glyph X is attached to base 5898 glyph A, and in the next lookup it is attached to base glyph B. 5899 It is up to the font designer to provide meaningful lookups and 5900 lookup order. */ 5901 5902 error = GPOS_Do_Glyph_Lookup( gpi, lookup_index, buffer, context_length, nesting_level ); 5903 if ( error && error != HB_Err_Not_Covered ) 5904 return error; 5905 } 5906 else 5907 { 5908 /* Contrary to properties defined in GDEF, user-defined properties 5909 will always stop a possible cursive positioning. */ 5910 gpi->last = 0xFFFF; 5911 5912 error = HB_Err_Not_Covered; 5913 } 5914 5915 if ( error == HB_Err_Not_Covered ) 5916 (buffer->in_pos)++; 5917 else 5918 retError = error; 5919 } 5920 5921 return retError; 5922 } 5923 5924 5925 static HB_Error Position_CursiveChain ( HB_Buffer buffer ) 5926 { 5927 HB_UInt i, j; 5928 HB_Position positions = buffer->positions; 5929 5930 /* First handle all left-to-right connections */ 5931 for (j = 0; j < buffer->in_length; j++) 5932 { 5933 if (positions[j].cursive_chain > 0) 5934 positions[j].y_pos += positions[j - positions[j].cursive_chain].y_pos; 5935 } 5936 5937 /* Then handle all right-to-left connections */ 5938 for (i = buffer->in_length; i > 0; i--) 5939 { 5940 j = i - 1; 5941 5942 if (positions[j].cursive_chain < 0) 5943 positions[j].y_pos += positions[j - positions[j].cursive_chain].y_pos; 5944 } 5945 5946 return HB_Err_Ok; 5947 } 5948 5949 5950 HB_Error HB_GPOS_Add_Feature( HB_GPOSHeader* gpos, 5951 HB_UShort feature_index, 5952 HB_UInt property ) 5953 { 5954 HB_UShort i; 5955 5956 HB_Feature feature; 5957 HB_UInt* properties; 5958 HB_UShort* index; 5959 HB_UShort lookup_count; 5960 5961 /* Each feature can only be added once */ 5962 5963 if ( !gpos || 5964 feature_index >= gpos->FeatureList.FeatureCount || 5965 gpos->FeatureList.ApplyCount == gpos->FeatureList.FeatureCount ) 5966 return ERR(HB_Err_Invalid_Argument); 5967 5968 gpos->FeatureList.ApplyOrder[gpos->FeatureList.ApplyCount++] = feature_index; 5969 5970 properties = gpos->LookupList.Properties; 5971 5972 feature = gpos->FeatureList.FeatureRecord[feature_index].Feature; 5973 index = feature.LookupListIndex; 5974 lookup_count = gpos->LookupList.LookupCount; 5975 5976 for ( i = 0; i < feature.LookupListCount; i++ ) 5977 { 5978 HB_UShort lookup_index = index[i]; 5979 if (lookup_index < lookup_count) 5980 properties[lookup_index] |= property; 5981 } 5982 5983 return HB_Err_Ok; 5984 } 5985 5986 5987 5988 HB_Error HB_GPOS_Clear_Features( HB_GPOSHeader* gpos ) 5989 { 5990 HB_UShort i; 5991 5992 HB_UInt* properties; 5993 5994 5995 if ( !gpos ) 5996 return ERR(HB_Err_Invalid_Argument); 5997 5998 gpos->FeatureList.ApplyCount = 0; 5999 6000 properties = gpos->LookupList.Properties; 6001 6002 for ( i = 0; i < gpos->LookupList.LookupCount; i++ ) 6003 properties[i] = 0; 6004 6005 return HB_Err_Ok; 6006 } 6007 6008 #ifdef HB_SUPPORT_MULTIPLE_MASTER 6009 HB_Error HB_GPOS_Register_MM_Function( HB_GPOSHeader* gpos, 6010 HB_MMFunction mmfunc, 6011 void* data ) 6012 { 6013 if ( !gpos ) 6014 return ERR(HB_Err_Invalid_Argument); 6015 6016 gpos->mmfunc = mmfunc; 6017 gpos->data = data; 6018 6019 return HB_Err_Ok; 6020 } 6021 #endif 6022 6023 /* If `dvi' is TRUE, glyph contour points for anchor points and device 6024 tables are ignored -- you will get device independent values. */ 6025 6026 6027 HB_Error HB_GPOS_Apply_String( HB_Font font, 6028 HB_GPOSHeader* gpos, 6029 HB_UShort load_flags, 6030 HB_Buffer buffer, 6031 HB_Bool dvi, 6032 HB_Bool r2l ) 6033 { 6034 HB_Error error, retError = HB_Err_Not_Covered; 6035 GPOS_Instance gpi; 6036 int i, j, lookup_count, num_features; 6037 6038 if ( !font || !gpos || !buffer ) 6039 return ERR(HB_Err_Invalid_Argument); 6040 6041 if ( buffer->in_length == 0 ) 6042 return HB_Err_Not_Covered; 6043 6044 gpi.font = font; 6045 gpi.gpos = gpos; 6046 gpi.load_flags = load_flags; 6047 gpi.r2l = r2l; 6048 gpi.dvi = dvi; 6049 6050 lookup_count = gpos->LookupList.LookupCount; 6051 num_features = gpos->FeatureList.ApplyCount; 6052 6053 if ( num_features ) 6054 { 6055 error = _hb_buffer_clear_positions( buffer ); 6056 if ( error ) 6057 return error; 6058 } 6059 6060 for ( i = 0; i < num_features; i++ ) 6061 { 6062 HB_UShort feature_index = gpos->FeatureList.ApplyOrder[i]; 6063 HB_Feature feature = gpos->FeatureList.FeatureRecord[feature_index].Feature; 6064 6065 for ( j = 0; j < feature.LookupListCount; j++ ) 6066 { 6067 HB_UShort lookup_index = feature.LookupListIndex[j]; 6068 6069 /* Skip nonexistant lookups */ 6070 if (lookup_index >= lookup_count) 6071 continue; 6072 6073 error = GPOS_Do_String_Lookup( &gpi, lookup_index, buffer ); 6074 if ( error ) 6075 { 6076 if ( error != HB_Err_Not_Covered ) 6077 return error; 6078 } 6079 else 6080 retError = error; 6081 } 6082 } 6083 6084 if ( num_features ) 6085 { 6086 error = Position_CursiveChain ( buffer ); 6087 if ( error ) 6088 return error; 6089 } 6090 6091 return retError; 6092 } 6093 6094 /* END */ 6095