1 /**************************************************************************** 2 * 3 * pfrgload.c 4 * 5 * FreeType PFR glyph loader (body). 6 * 7 * Copyright (C) 2002-2020 by 8 * David Turner, Robert Wilhelm, and Werner Lemberg. 9 * 10 * This file is part of the FreeType project, and may only be used, 11 * modified, and distributed under the terms of the FreeType project 12 * license, LICENSE.TXT. By continuing to use, modify, or distribute 13 * this file you indicate that you have read the license and 14 * understand and accept it fully. 15 * 16 */ 17 18 19 #include "pfrgload.h" 20 #include "pfrsbit.h" 21 #include "pfrload.h" /* for macro definitions */ 22 #include <freetype/internal/ftdebug.h> 23 24 #include "pfrerror.h" 25 26 #undef FT_COMPONENT 27 #define FT_COMPONENT pfr 28 29 30 /*************************************************************************/ 31 /*************************************************************************/ 32 /***** *****/ 33 /***** PFR GLYPH BUILDER *****/ 34 /***** *****/ 35 /*************************************************************************/ 36 /*************************************************************************/ 37 38 39 FT_LOCAL_DEF( void ) pfr_glyph_init(PFR_Glyph glyph,FT_GlyphLoader loader)40 pfr_glyph_init( PFR_Glyph glyph, 41 FT_GlyphLoader loader ) 42 { 43 FT_ZERO( glyph ); 44 45 glyph->loader = loader; 46 glyph->path_begun = 0; 47 48 FT_GlyphLoader_Rewind( loader ); 49 } 50 51 52 FT_LOCAL_DEF( void ) pfr_glyph_done(PFR_Glyph glyph)53 pfr_glyph_done( PFR_Glyph glyph ) 54 { 55 FT_Memory memory = glyph->loader->memory; 56 57 58 FT_FREE( glyph->x_control ); 59 glyph->y_control = NULL; 60 61 glyph->max_xy_control = 0; 62 #if 0 63 glyph->num_x_control = 0; 64 glyph->num_y_control = 0; 65 #endif 66 67 FT_FREE( glyph->subs ); 68 69 glyph->max_subs = 0; 70 glyph->num_subs = 0; 71 72 glyph->loader = NULL; 73 glyph->path_begun = 0; 74 } 75 76 77 /* close current contour, if any */ 78 static void pfr_glyph_close_contour(PFR_Glyph glyph)79 pfr_glyph_close_contour( PFR_Glyph glyph ) 80 { 81 FT_GlyphLoader loader = glyph->loader; 82 FT_Outline* outline = &loader->current.outline; 83 FT_Int last, first; 84 85 86 if ( !glyph->path_begun ) 87 return; 88 89 /* compute first and last point indices in current glyph outline */ 90 last = outline->n_points - 1; 91 first = 0; 92 if ( outline->n_contours > 0 ) 93 first = outline->contours[outline->n_contours - 1]; 94 95 /* if the last point falls on the same location as the first one */ 96 /* we need to delete it */ 97 if ( last > first ) 98 { 99 FT_Vector* p1 = outline->points + first; 100 FT_Vector* p2 = outline->points + last; 101 102 103 if ( p1->x == p2->x && p1->y == p2->y ) 104 { 105 outline->n_points--; 106 last--; 107 } 108 } 109 110 /* don't add empty contours */ 111 if ( last >= first ) 112 outline->contours[outline->n_contours++] = (short)last; 113 114 glyph->path_begun = 0; 115 } 116 117 118 /* reset glyph to start the loading of a new glyph */ 119 static void pfr_glyph_start(PFR_Glyph glyph)120 pfr_glyph_start( PFR_Glyph glyph ) 121 { 122 glyph->path_begun = 0; 123 } 124 125 126 static FT_Error pfr_glyph_line_to(PFR_Glyph glyph,FT_Vector * to)127 pfr_glyph_line_to( PFR_Glyph glyph, 128 FT_Vector* to ) 129 { 130 FT_GlyphLoader loader = glyph->loader; 131 FT_Outline* outline = &loader->current.outline; 132 FT_Error error; 133 134 135 /* check that we have begun a new path */ 136 if ( !glyph->path_begun ) 137 { 138 error = FT_THROW( Invalid_Table ); 139 FT_ERROR(( "pfr_glyph_line_to: invalid glyph data\n" )); 140 goto Exit; 141 } 142 143 error = FT_GLYPHLOADER_CHECK_POINTS( loader, 1, 0 ); 144 if ( !error ) 145 { 146 FT_Int n = outline->n_points; 147 148 149 outline->points[n] = *to; 150 outline->tags [n] = FT_CURVE_TAG_ON; 151 152 outline->n_points++; 153 } 154 155 Exit: 156 return error; 157 } 158 159 160 static FT_Error pfr_glyph_curve_to(PFR_Glyph glyph,FT_Vector * control1,FT_Vector * control2,FT_Vector * to)161 pfr_glyph_curve_to( PFR_Glyph glyph, 162 FT_Vector* control1, 163 FT_Vector* control2, 164 FT_Vector* to ) 165 { 166 FT_GlyphLoader loader = glyph->loader; 167 FT_Outline* outline = &loader->current.outline; 168 FT_Error error; 169 170 171 /* check that we have begun a new path */ 172 if ( !glyph->path_begun ) 173 { 174 error = FT_THROW( Invalid_Table ); 175 FT_ERROR(( "pfr_glyph_line_to: invalid glyph data\n" )); 176 goto Exit; 177 } 178 179 error = FT_GLYPHLOADER_CHECK_POINTS( loader, 3, 0 ); 180 if ( !error ) 181 { 182 FT_Vector* vec = outline->points + outline->n_points; 183 FT_Byte* tag = (FT_Byte*)outline->tags + outline->n_points; 184 185 186 vec[0] = *control1; 187 vec[1] = *control2; 188 vec[2] = *to; 189 tag[0] = FT_CURVE_TAG_CUBIC; 190 tag[1] = FT_CURVE_TAG_CUBIC; 191 tag[2] = FT_CURVE_TAG_ON; 192 193 outline->n_points = (FT_Short)( outline->n_points + 3 ); 194 } 195 196 Exit: 197 return error; 198 } 199 200 201 static FT_Error pfr_glyph_move_to(PFR_Glyph glyph,FT_Vector * to)202 pfr_glyph_move_to( PFR_Glyph glyph, 203 FT_Vector* to ) 204 { 205 FT_GlyphLoader loader = glyph->loader; 206 FT_Error error; 207 208 209 /* close current contour if any */ 210 pfr_glyph_close_contour( glyph ); 211 212 /* indicate that a new contour has started */ 213 glyph->path_begun = 1; 214 215 /* check that there is space for a new contour and a new point */ 216 error = FT_GLYPHLOADER_CHECK_POINTS( loader, 1, 1 ); 217 if ( !error ) 218 { 219 /* add new start point */ 220 error = pfr_glyph_line_to( glyph, to ); 221 } 222 223 return error; 224 } 225 226 227 static void pfr_glyph_end(PFR_Glyph glyph)228 pfr_glyph_end( PFR_Glyph glyph ) 229 { 230 /* close current contour if any */ 231 pfr_glyph_close_contour( glyph ); 232 233 /* merge the current glyph into the stack */ 234 FT_GlyphLoader_Add( glyph->loader ); 235 } 236 237 238 /*************************************************************************/ 239 /*************************************************************************/ 240 /***** *****/ 241 /***** PFR GLYPH LOADER *****/ 242 /***** *****/ 243 /*************************************************************************/ 244 /*************************************************************************/ 245 246 247 /* load a simple glyph */ 248 static FT_Error pfr_glyph_load_simple(PFR_Glyph glyph,FT_Byte * p,FT_Byte * limit)249 pfr_glyph_load_simple( PFR_Glyph glyph, 250 FT_Byte* p, 251 FT_Byte* limit ) 252 { 253 FT_Error error = FT_Err_Ok; 254 FT_Memory memory = glyph->loader->memory; 255 FT_UInt flags, x_count, y_count, i, count, mask; 256 FT_Int x; 257 258 259 PFR_CHECK( 1 ); 260 flags = PFR_NEXT_BYTE( p ); 261 262 /* test for composite glyphs */ 263 if ( flags & PFR_GLYPH_IS_COMPOUND ) 264 goto Failure; 265 266 x_count = 0; 267 y_count = 0; 268 269 if ( flags & PFR_GLYPH_1BYTE_XYCOUNT ) 270 { 271 PFR_CHECK( 1 ); 272 count = PFR_NEXT_BYTE( p ); 273 x_count = count & 15; 274 y_count = count >> 4; 275 } 276 else 277 { 278 if ( flags & PFR_GLYPH_XCOUNT ) 279 { 280 PFR_CHECK( 1 ); 281 x_count = PFR_NEXT_BYTE( p ); 282 } 283 284 if ( flags & PFR_GLYPH_YCOUNT ) 285 { 286 PFR_CHECK( 1 ); 287 y_count = PFR_NEXT_BYTE( p ); 288 } 289 } 290 291 count = x_count + y_count; 292 293 /* re-allocate array when necessary */ 294 if ( count > glyph->max_xy_control ) 295 { 296 FT_UInt new_max = FT_PAD_CEIL( count, 8 ); 297 298 299 if ( FT_RENEW_ARRAY( glyph->x_control, 300 glyph->max_xy_control, 301 new_max ) ) 302 goto Exit; 303 304 glyph->max_xy_control = new_max; 305 } 306 307 glyph->y_control = glyph->x_control + x_count; 308 309 mask = 0; 310 x = 0; 311 312 for ( i = 0; i < count; i++ ) 313 { 314 if ( ( i & 7 ) == 0 ) 315 { 316 PFR_CHECK( 1 ); 317 mask = PFR_NEXT_BYTE( p ); 318 } 319 320 if ( mask & 1 ) 321 { 322 PFR_CHECK( 2 ); 323 x = PFR_NEXT_SHORT( p ); 324 } 325 else 326 { 327 PFR_CHECK( 1 ); 328 x += PFR_NEXT_BYTE( p ); 329 } 330 331 glyph->x_control[i] = x; 332 333 mask >>= 1; 334 } 335 336 /* XXX: we ignore the secondary stroke and edge definitions */ 337 /* since we don't support native PFR hinting */ 338 /* */ 339 if ( flags & PFR_GLYPH_SINGLE_EXTRA_ITEMS ) 340 { 341 error = pfr_extra_items_skip( &p, limit ); 342 if ( error ) 343 goto Exit; 344 } 345 346 pfr_glyph_start( glyph ); 347 348 /* now load a simple glyph */ 349 { 350 FT_Vector pos[4]; 351 FT_Vector* cur; 352 353 354 pos[0].x = pos[0].y = 0; 355 pos[3] = pos[0]; 356 357 for (;;) 358 { 359 FT_UInt format, format_low, args_format = 0, args_count, n; 360 361 362 /**************************************************************** 363 * read instruction 364 */ 365 PFR_CHECK( 1 ); 366 format = PFR_NEXT_BYTE( p ); 367 format_low = format & 15; 368 369 switch ( format >> 4 ) 370 { 371 case 0: /* end glyph */ 372 FT_TRACE6(( "- end glyph" )); 373 args_count = 0; 374 break; 375 376 case 1: /* general line operation */ 377 FT_TRACE6(( "- general line" )); 378 goto Line1; 379 380 case 4: /* move to inside contour */ 381 FT_TRACE6(( "- move to inside" )); 382 goto Line1; 383 384 case 5: /* move to outside contour */ 385 FT_TRACE6(( "- move to outside" )); 386 Line1: 387 args_format = format_low; 388 args_count = 1; 389 break; 390 391 case 2: /* horizontal line to */ 392 FT_TRACE6(( "- horizontal line to cx.%d", format_low )); 393 if ( format_low >= x_count ) 394 goto Failure; 395 pos[0].x = glyph->x_control[format_low]; 396 pos[0].y = pos[3].y; 397 pos[3] = pos[0]; 398 args_count = 0; 399 break; 400 401 case 3: /* vertical line to */ 402 FT_TRACE6(( "- vertical line to cy.%d", format_low )); 403 if ( format_low >= y_count ) 404 goto Failure; 405 pos[0].x = pos[3].x; 406 pos[0].y = glyph->y_control[format_low]; 407 pos[3] = pos[0]; 408 args_count = 0; 409 break; 410 411 case 6: /* horizontal to vertical curve */ 412 FT_TRACE6(( "- hv curve " )); 413 args_format = 0xB8E; 414 args_count = 3; 415 break; 416 417 case 7: /* vertical to horizontal curve */ 418 FT_TRACE6(( "- vh curve" )); 419 args_format = 0xE2B; 420 args_count = 3; 421 break; 422 423 default: /* general curve to */ 424 FT_TRACE6(( "- general curve" )); 425 args_count = 4; 426 args_format = format_low; 427 } 428 429 /************************************************************ 430 * now read arguments 431 */ 432 cur = pos; 433 for ( n = 0; n < args_count; n++ ) 434 { 435 FT_UInt idx; 436 FT_Int delta; 437 438 439 /* read the X argument */ 440 switch ( args_format & 3 ) 441 { 442 case 0: /* 8-bit index */ 443 PFR_CHECK( 1 ); 444 idx = PFR_NEXT_BYTE( p ); 445 if ( idx >= x_count ) 446 goto Failure; 447 cur->x = glyph->x_control[idx]; 448 FT_TRACE7(( " cx#%d", idx )); 449 break; 450 451 case 1: /* 16-bit absolute value */ 452 PFR_CHECK( 2 ); 453 cur->x = PFR_NEXT_SHORT( p ); 454 FT_TRACE7(( " x.%ld", cur->x )); 455 break; 456 457 case 2: /* 8-bit delta */ 458 PFR_CHECK( 1 ); 459 delta = PFR_NEXT_INT8( p ); 460 cur->x = pos[3].x + delta; 461 FT_TRACE7(( " dx.%d", delta )); 462 break; 463 464 default: 465 FT_TRACE7(( " |" )); 466 cur->x = pos[3].x; 467 } 468 469 /* read the Y argument */ 470 switch ( ( args_format >> 2 ) & 3 ) 471 { 472 case 0: /* 8-bit index */ 473 PFR_CHECK( 1 ); 474 idx = PFR_NEXT_BYTE( p ); 475 if ( idx >= y_count ) 476 goto Failure; 477 cur->y = glyph->y_control[idx]; 478 FT_TRACE7(( " cy#%d", idx )); 479 break; 480 481 case 1: /* 16-bit absolute value */ 482 PFR_CHECK( 2 ); 483 cur->y = PFR_NEXT_SHORT( p ); 484 FT_TRACE7(( " y.%ld", cur->y )); 485 break; 486 487 case 2: /* 8-bit delta */ 488 PFR_CHECK( 1 ); 489 delta = PFR_NEXT_INT8( p ); 490 cur->y = pos[3].y + delta; 491 FT_TRACE7(( " dy.%d", delta )); 492 break; 493 494 default: 495 FT_TRACE7(( " -" )); 496 cur->y = pos[3].y; 497 } 498 499 /* read the additional format flag for the general curve */ 500 if ( n == 0 && args_count == 4 ) 501 { 502 PFR_CHECK( 1 ); 503 args_format = PFR_NEXT_BYTE( p ); 504 args_count--; 505 } 506 else 507 args_format >>= 4; 508 509 /* save the previous point */ 510 pos[3] = cur[0]; 511 cur++; 512 } 513 514 FT_TRACE7(( "\n" )); 515 516 /************************************************************ 517 * finally, execute instruction 518 */ 519 switch ( format >> 4 ) 520 { 521 case 0: /* end glyph => EXIT */ 522 pfr_glyph_end( glyph ); 523 goto Exit; 524 525 case 1: /* line operations */ 526 case 2: 527 case 3: 528 error = pfr_glyph_line_to( glyph, pos ); 529 goto Test_Error; 530 531 case 4: /* move to inside contour */ 532 case 5: /* move to outside contour */ 533 error = pfr_glyph_move_to( glyph, pos ); 534 goto Test_Error; 535 536 default: /* curve operations */ 537 error = pfr_glyph_curve_to( glyph, pos, pos + 1, pos + 2 ); 538 539 Test_Error: /* test error condition */ 540 if ( error ) 541 goto Exit; 542 } 543 } /* for (;;) */ 544 } 545 546 Exit: 547 return error; 548 549 Failure: 550 Too_Short: 551 error = FT_THROW( Invalid_Table ); 552 FT_ERROR(( "pfr_glyph_load_simple: invalid glyph data\n" )); 553 goto Exit; 554 } 555 556 557 /* load a composite/compound glyph */ 558 static FT_Error pfr_glyph_load_compound(PFR_Glyph glyph,FT_Byte * p,FT_Byte * limit)559 pfr_glyph_load_compound( PFR_Glyph glyph, 560 FT_Byte* p, 561 FT_Byte* limit ) 562 { 563 FT_Error error = FT_Err_Ok; 564 FT_GlyphLoader loader = glyph->loader; 565 FT_Memory memory = loader->memory; 566 PFR_SubGlyph subglyph; 567 FT_UInt flags, i, count, org_count; 568 FT_Int x_pos, y_pos; 569 570 571 PFR_CHECK( 1 ); 572 flags = PFR_NEXT_BYTE( p ); 573 574 /* test for composite glyphs */ 575 if ( !( flags & PFR_GLYPH_IS_COMPOUND ) ) 576 goto Failure; 577 578 count = flags & 0x3F; 579 580 /* ignore extra items when present */ 581 /* */ 582 if ( flags & PFR_GLYPH_COMPOUND_EXTRA_ITEMS ) 583 { 584 error = pfr_extra_items_skip( &p, limit ); 585 if ( error ) 586 goto Exit; 587 } 588 589 /* we can't rely on the FT_GlyphLoader to load sub-glyphs, because */ 590 /* the PFR format is dumb, using direct file offsets to point to the */ 591 /* sub-glyphs (instead of glyph indices). Sigh. */ 592 /* */ 593 /* For now, we load the list of sub-glyphs into a different array */ 594 /* but this will prevent us from using the auto-hinter at its best */ 595 /* quality. */ 596 /* */ 597 org_count = glyph->num_subs; 598 599 if ( org_count + count > glyph->max_subs ) 600 { 601 FT_UInt new_max = ( org_count + count + 3 ) & (FT_UInt)-4; 602 603 604 /* we arbitrarily limit the number of subglyphs */ 605 /* to avoid endless recursion */ 606 if ( new_max > 64 ) 607 { 608 error = FT_THROW( Invalid_Table ); 609 FT_ERROR(( "pfr_glyph_load_compound:" 610 " too many compound glyphs components\n" )); 611 goto Exit; 612 } 613 614 if ( FT_RENEW_ARRAY( glyph->subs, glyph->max_subs, new_max ) ) 615 goto Exit; 616 617 glyph->max_subs = new_max; 618 } 619 620 subglyph = glyph->subs + org_count; 621 622 for ( i = 0; i < count; i++, subglyph++ ) 623 { 624 FT_UInt format; 625 626 627 x_pos = 0; 628 y_pos = 0; 629 630 PFR_CHECK( 1 ); 631 format = PFR_NEXT_BYTE( p ); 632 633 /* read scale when available */ 634 subglyph->x_scale = 0x10000L; 635 if ( format & PFR_SUBGLYPH_XSCALE ) 636 { 637 PFR_CHECK( 2 ); 638 subglyph->x_scale = PFR_NEXT_SHORT( p ) * 16; 639 } 640 641 subglyph->y_scale = 0x10000L; 642 if ( format & PFR_SUBGLYPH_YSCALE ) 643 { 644 PFR_CHECK( 2 ); 645 subglyph->y_scale = PFR_NEXT_SHORT( p ) * 16; 646 } 647 648 /* read offset */ 649 switch ( format & 3 ) 650 { 651 case 1: 652 PFR_CHECK( 2 ); 653 x_pos = PFR_NEXT_SHORT( p ); 654 break; 655 656 case 2: 657 PFR_CHECK( 1 ); 658 x_pos += PFR_NEXT_INT8( p ); 659 break; 660 661 default: 662 ; 663 } 664 665 switch ( ( format >> 2 ) & 3 ) 666 { 667 case 1: 668 PFR_CHECK( 2 ); 669 y_pos = PFR_NEXT_SHORT( p ); 670 break; 671 672 case 2: 673 PFR_CHECK( 1 ); 674 y_pos += PFR_NEXT_INT8( p ); 675 break; 676 677 default: 678 ; 679 } 680 681 subglyph->x_delta = x_pos; 682 subglyph->y_delta = y_pos; 683 684 /* read glyph position and size now */ 685 if ( format & PFR_SUBGLYPH_2BYTE_SIZE ) 686 { 687 PFR_CHECK( 2 ); 688 subglyph->gps_size = PFR_NEXT_USHORT( p ); 689 } 690 else 691 { 692 PFR_CHECK( 1 ); 693 subglyph->gps_size = PFR_NEXT_BYTE( p ); 694 } 695 696 if ( format & PFR_SUBGLYPH_3BYTE_OFFSET ) 697 { 698 PFR_CHECK( 3 ); 699 subglyph->gps_offset = PFR_NEXT_ULONG( p ); 700 } 701 else 702 { 703 PFR_CHECK( 2 ); 704 subglyph->gps_offset = PFR_NEXT_USHORT( p ); 705 } 706 707 glyph->num_subs++; 708 } 709 710 Exit: 711 return error; 712 713 Failure: 714 Too_Short: 715 error = FT_THROW( Invalid_Table ); 716 FT_ERROR(( "pfr_glyph_load_compound: invalid glyph data\n" )); 717 goto Exit; 718 } 719 720 721 static FT_Error pfr_glyph_load_rec(PFR_Glyph glyph,FT_Stream stream,FT_ULong gps_offset,FT_ULong offset,FT_ULong size)722 pfr_glyph_load_rec( PFR_Glyph glyph, 723 FT_Stream stream, 724 FT_ULong gps_offset, 725 FT_ULong offset, 726 FT_ULong size ) 727 { 728 FT_Error error; 729 FT_Byte* p; 730 FT_Byte* limit; 731 732 733 if ( FT_STREAM_SEEK( gps_offset + offset ) || 734 FT_FRAME_ENTER( size ) ) 735 goto Exit; 736 737 p = (FT_Byte*)stream->cursor; 738 limit = p + size; 739 740 if ( size > 0 && *p & PFR_GLYPH_IS_COMPOUND ) 741 { 742 FT_UInt n, old_count, count; 743 FT_GlyphLoader loader = glyph->loader; 744 FT_Outline* base = &loader->base.outline; 745 746 747 old_count = glyph->num_subs; 748 749 /* this is a compound glyph - load it */ 750 error = pfr_glyph_load_compound( glyph, p, limit ); 751 752 FT_FRAME_EXIT(); 753 754 if ( error ) 755 goto Exit; 756 757 count = glyph->num_subs - old_count; 758 759 FT_TRACE4(( "compound glyph with %d element%s (offset %lu):\n", 760 count, 761 count == 1 ? "" : "s", 762 offset )); 763 764 /* now, load each individual glyph */ 765 for ( n = 0; n < count; n++ ) 766 { 767 FT_Int i, old_points, num_points; 768 PFR_SubGlyph subglyph; 769 770 771 FT_TRACE4(( " subglyph %d:\n", n )); 772 773 subglyph = glyph->subs + old_count + n; 774 old_points = base->n_points; 775 776 error = pfr_glyph_load_rec( glyph, stream, gps_offset, 777 subglyph->gps_offset, 778 subglyph->gps_size ); 779 if ( error ) 780 break; 781 782 /* note that `glyph->subs' might have been re-allocated */ 783 subglyph = glyph->subs + old_count + n; 784 num_points = base->n_points - old_points; 785 786 /* translate and eventually scale the new glyph points */ 787 if ( subglyph->x_scale != 0x10000L || subglyph->y_scale != 0x10000L ) 788 { 789 FT_Vector* vec = base->points + old_points; 790 791 792 for ( i = 0; i < num_points; i++, vec++ ) 793 { 794 vec->x = FT_MulFix( vec->x, subglyph->x_scale ) + 795 subglyph->x_delta; 796 vec->y = FT_MulFix( vec->y, subglyph->y_scale ) + 797 subglyph->y_delta; 798 } 799 } 800 else 801 { 802 FT_Vector* vec = loader->base.outline.points + old_points; 803 804 805 for ( i = 0; i < num_points; i++, vec++ ) 806 { 807 vec->x += subglyph->x_delta; 808 vec->y += subglyph->y_delta; 809 } 810 } 811 812 /* proceed to next sub-glyph */ 813 } 814 815 FT_TRACE4(( "end compound glyph with %d element%s\n", 816 count, 817 count == 1 ? "" : "s" )); 818 } 819 else 820 { 821 FT_TRACE4(( "simple glyph (offset %lu)\n", offset )); 822 823 /* load a simple glyph */ 824 error = pfr_glyph_load_simple( glyph, p, limit ); 825 826 FT_FRAME_EXIT(); 827 } 828 829 Exit: 830 return error; 831 } 832 833 834 FT_LOCAL_DEF( FT_Error ) pfr_glyph_load(PFR_Glyph glyph,FT_Stream stream,FT_ULong gps_offset,FT_ULong offset,FT_ULong size)835 pfr_glyph_load( PFR_Glyph glyph, 836 FT_Stream stream, 837 FT_ULong gps_offset, 838 FT_ULong offset, 839 FT_ULong size ) 840 { 841 /* initialize glyph loader */ 842 FT_GlyphLoader_Rewind( glyph->loader ); 843 844 glyph->num_subs = 0; 845 846 /* load the glyph, recursively when needed */ 847 return pfr_glyph_load_rec( glyph, stream, gps_offset, offset, size ); 848 } 849 850 851 /* END */ 852