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