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