1 /**************************************************************************** 2 * 3 * pshrec.c 4 * 5 * FreeType PostScript hints recorder (body). 6 * 7 * Copyright (C) 2001-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 <freetype/freetype.h> 20 #include <freetype/internal/ftobjs.h> 21 #include <freetype/internal/ftdebug.h> 22 #include <freetype/internal/ftcalc.h> 23 24 #include "pshrec.h" 25 #include "pshalgo.h" 26 27 #include "pshnterr.h" 28 29 #undef FT_COMPONENT 30 #define FT_COMPONENT pshrec 31 32 #ifdef DEBUG_HINTER 33 PS_Hints ps_debug_hints = NULL; 34 int ps_debug_no_horz_hints = 0; 35 int ps_debug_no_vert_hints = 0; 36 #endif 37 38 39 /*************************************************************************/ 40 /*************************************************************************/ 41 /***** *****/ 42 /***** PS_HINT MANAGEMENT *****/ 43 /***** *****/ 44 /*************************************************************************/ 45 /*************************************************************************/ 46 47 /* destroy hints table */ 48 static void ps_hint_table_done(PS_Hint_Table table,FT_Memory memory)49 ps_hint_table_done( PS_Hint_Table table, 50 FT_Memory memory ) 51 { 52 FT_FREE( table->hints ); 53 table->num_hints = 0; 54 table->max_hints = 0; 55 } 56 57 58 /* ensure that a table can contain "count" elements */ 59 static FT_Error ps_hint_table_ensure(PS_Hint_Table table,FT_UInt count,FT_Memory memory)60 ps_hint_table_ensure( PS_Hint_Table table, 61 FT_UInt count, 62 FT_Memory memory ) 63 { 64 FT_UInt old_max = table->max_hints; 65 FT_UInt new_max = count; 66 FT_Error error = FT_Err_Ok; 67 68 69 if ( new_max > old_max ) 70 { 71 /* try to grow the table */ 72 new_max = FT_PAD_CEIL( new_max, 8 ); 73 if ( !FT_RENEW_ARRAY( table->hints, old_max, new_max ) ) 74 table->max_hints = new_max; 75 } 76 return error; 77 } 78 79 80 static FT_Error ps_hint_table_alloc(PS_Hint_Table table,FT_Memory memory,PS_Hint * ahint)81 ps_hint_table_alloc( PS_Hint_Table table, 82 FT_Memory memory, 83 PS_Hint *ahint ) 84 { 85 FT_Error error = FT_Err_Ok; 86 FT_UInt count; 87 PS_Hint hint = NULL; 88 89 90 count = table->num_hints; 91 count++; 92 93 if ( count >= table->max_hints ) 94 { 95 error = ps_hint_table_ensure( table, count, memory ); 96 if ( error ) 97 goto Exit; 98 } 99 100 hint = table->hints + count - 1; 101 hint->pos = 0; 102 hint->len = 0; 103 hint->flags = 0; 104 105 table->num_hints = count; 106 107 Exit: 108 *ahint = hint; 109 return error; 110 } 111 112 113 /*************************************************************************/ 114 /*************************************************************************/ 115 /***** *****/ 116 /***** PS_MASK MANAGEMENT *****/ 117 /***** *****/ 118 /*************************************************************************/ 119 /*************************************************************************/ 120 121 /* destroy mask */ 122 static void ps_mask_done(PS_Mask mask,FT_Memory memory)123 ps_mask_done( PS_Mask mask, 124 FT_Memory memory ) 125 { 126 FT_FREE( mask->bytes ); 127 mask->num_bits = 0; 128 mask->max_bits = 0; 129 mask->end_point = 0; 130 } 131 132 133 /* ensure that a mask can contain "count" bits */ 134 static FT_Error ps_mask_ensure(PS_Mask mask,FT_UInt count,FT_Memory memory)135 ps_mask_ensure( PS_Mask mask, 136 FT_UInt count, 137 FT_Memory memory ) 138 { 139 FT_UInt old_max = ( mask->max_bits + 7 ) >> 3; 140 FT_UInt new_max = ( count + 7 ) >> 3; 141 FT_Error error = FT_Err_Ok; 142 143 144 if ( new_max > old_max ) 145 { 146 new_max = FT_PAD_CEIL( new_max, 8 ); 147 if ( !FT_RENEW_ARRAY( mask->bytes, old_max, new_max ) ) 148 mask->max_bits = new_max * 8; 149 } 150 return error; 151 } 152 153 154 /* test a bit value in a given mask */ 155 static FT_Int ps_mask_test_bit(PS_Mask mask,FT_Int idx)156 ps_mask_test_bit( PS_Mask mask, 157 FT_Int idx ) 158 { 159 if ( (FT_UInt)idx >= mask->num_bits ) 160 return 0; 161 162 return mask->bytes[idx >> 3] & ( 0x80 >> ( idx & 7 ) ); 163 } 164 165 166 /* clear a given bit */ 167 static void ps_mask_clear_bit(PS_Mask mask,FT_UInt idx)168 ps_mask_clear_bit( PS_Mask mask, 169 FT_UInt idx ) 170 { 171 FT_Byte* p; 172 173 174 if ( idx >= mask->num_bits ) 175 return; 176 177 p = mask->bytes + ( idx >> 3 ); 178 p[0] = (FT_Byte)( p[0] & ~( 0x80 >> ( idx & 7 ) ) ); 179 } 180 181 182 /* set a given bit, possibly grow the mask */ 183 static FT_Error ps_mask_set_bit(PS_Mask mask,FT_UInt idx,FT_Memory memory)184 ps_mask_set_bit( PS_Mask mask, 185 FT_UInt idx, 186 FT_Memory memory ) 187 { 188 FT_Error error = FT_Err_Ok; 189 FT_Byte* p; 190 191 192 if ( idx >= mask->num_bits ) 193 { 194 error = ps_mask_ensure( mask, idx + 1, memory ); 195 if ( error ) 196 goto Exit; 197 198 mask->num_bits = idx + 1; 199 } 200 201 p = mask->bytes + ( idx >> 3 ); 202 p[0] = (FT_Byte)( p[0] | ( 0x80 >> ( idx & 7 ) ) ); 203 204 Exit: 205 return error; 206 } 207 208 209 /* destroy mask table */ 210 static void ps_mask_table_done(PS_Mask_Table table,FT_Memory memory)211 ps_mask_table_done( PS_Mask_Table table, 212 FT_Memory memory ) 213 { 214 FT_UInt count = table->max_masks; 215 PS_Mask mask = table->masks; 216 217 218 for ( ; count > 0; count--, mask++ ) 219 ps_mask_done( mask, memory ); 220 221 FT_FREE( table->masks ); 222 table->num_masks = 0; 223 table->max_masks = 0; 224 } 225 226 227 /* ensure that a mask table can contain "count" masks */ 228 static FT_Error ps_mask_table_ensure(PS_Mask_Table table,FT_UInt count,FT_Memory memory)229 ps_mask_table_ensure( PS_Mask_Table table, 230 FT_UInt count, 231 FT_Memory memory ) 232 { 233 FT_UInt old_max = table->max_masks; 234 FT_UInt new_max = count; 235 FT_Error error = FT_Err_Ok; 236 237 238 if ( new_max > old_max ) 239 { 240 new_max = FT_PAD_CEIL( new_max, 8 ); 241 if ( !FT_RENEW_ARRAY( table->masks, old_max, new_max ) ) 242 table->max_masks = new_max; 243 } 244 return error; 245 } 246 247 248 /* allocate a new mask in a table */ 249 static FT_Error ps_mask_table_alloc(PS_Mask_Table table,FT_Memory memory,PS_Mask * amask)250 ps_mask_table_alloc( PS_Mask_Table table, 251 FT_Memory memory, 252 PS_Mask *amask ) 253 { 254 FT_UInt count; 255 FT_Error error = FT_Err_Ok; 256 PS_Mask mask = NULL; 257 258 259 count = table->num_masks; 260 count++; 261 262 if ( count > table->max_masks ) 263 { 264 error = ps_mask_table_ensure( table, count, memory ); 265 if ( error ) 266 goto Exit; 267 } 268 269 mask = table->masks + count - 1; 270 mask->num_bits = 0; 271 mask->end_point = 0; 272 table->num_masks = count; 273 274 Exit: 275 *amask = mask; 276 return error; 277 } 278 279 280 /* return last hint mask in a table, create one if the table is empty */ 281 static FT_Error ps_mask_table_last(PS_Mask_Table table,FT_Memory memory,PS_Mask * amask)282 ps_mask_table_last( PS_Mask_Table table, 283 FT_Memory memory, 284 PS_Mask *amask ) 285 { 286 FT_Error error = FT_Err_Ok; 287 FT_UInt count; 288 PS_Mask mask; 289 290 291 count = table->num_masks; 292 if ( count == 0 ) 293 { 294 error = ps_mask_table_alloc( table, memory, &mask ); 295 if ( error ) 296 goto Exit; 297 } 298 else 299 mask = table->masks + count - 1; 300 301 Exit: 302 *amask = mask; 303 return error; 304 } 305 306 307 /* set a new mask to a given bit range */ 308 static FT_Error ps_mask_table_set_bits(PS_Mask_Table table,const FT_Byte * source,FT_UInt bit_pos,FT_UInt bit_count,FT_Memory memory)309 ps_mask_table_set_bits( PS_Mask_Table table, 310 const FT_Byte* source, 311 FT_UInt bit_pos, 312 FT_UInt bit_count, 313 FT_Memory memory ) 314 { 315 FT_Error error; 316 PS_Mask mask; 317 318 319 error = ps_mask_table_last( table, memory, &mask ); 320 if ( error ) 321 goto Exit; 322 323 error = ps_mask_ensure( mask, bit_count, memory ); 324 if ( error ) 325 goto Exit; 326 327 mask->num_bits = bit_count; 328 329 /* now, copy bits */ 330 { 331 FT_Byte* read = (FT_Byte*)source + ( bit_pos >> 3 ); 332 FT_Int rmask = 0x80 >> ( bit_pos & 7 ); 333 FT_Byte* write = mask->bytes; 334 FT_Int wmask = 0x80; 335 FT_Int val; 336 337 338 for ( ; bit_count > 0; bit_count-- ) 339 { 340 val = write[0] & ~wmask; 341 342 if ( read[0] & rmask ) 343 val |= wmask; 344 345 write[0] = (FT_Byte)val; 346 347 rmask >>= 1; 348 if ( rmask == 0 ) 349 { 350 read++; 351 rmask = 0x80; 352 } 353 354 wmask >>= 1; 355 if ( wmask == 0 ) 356 { 357 write++; 358 wmask = 0x80; 359 } 360 } 361 } 362 363 Exit: 364 return error; 365 } 366 367 368 /* test whether two masks in a table intersect */ 369 static FT_Int ps_mask_table_test_intersect(PS_Mask_Table table,FT_UInt index1,FT_UInt index2)370 ps_mask_table_test_intersect( PS_Mask_Table table, 371 FT_UInt index1, 372 FT_UInt index2 ) 373 { 374 PS_Mask mask1 = table->masks + index1; 375 PS_Mask mask2 = table->masks + index2; 376 FT_Byte* p1 = mask1->bytes; 377 FT_Byte* p2 = mask2->bytes; 378 FT_UInt count1 = mask1->num_bits; 379 FT_UInt count2 = mask2->num_bits; 380 FT_UInt count; 381 382 383 count = FT_MIN( count1, count2 ); 384 for ( ; count >= 8; count -= 8 ) 385 { 386 if ( p1[0] & p2[0] ) 387 return 1; 388 389 p1++; 390 p2++; 391 } 392 393 if ( count == 0 ) 394 return 0; 395 396 return ( p1[0] & p2[0] ) & ~( 0xFF >> count ); 397 } 398 399 400 /* merge two masks, used by ps_mask_table_merge_all */ 401 static FT_Error ps_mask_table_merge(PS_Mask_Table table,FT_UInt index1,FT_UInt index2,FT_Memory memory)402 ps_mask_table_merge( PS_Mask_Table table, 403 FT_UInt index1, 404 FT_UInt index2, 405 FT_Memory memory ) 406 { 407 FT_Error error = FT_Err_Ok; 408 409 410 /* swap index1 and index2 so that index1 < index2 */ 411 if ( index1 > index2 ) 412 { 413 FT_UInt temp; 414 415 416 temp = index1; 417 index1 = index2; 418 index2 = temp; 419 } 420 421 if ( index1 < index2 && index2 < table->num_masks ) 422 { 423 /* we need to merge the bitsets of index1 and index2 with a */ 424 /* simple union */ 425 PS_Mask mask1 = table->masks + index1; 426 PS_Mask mask2 = table->masks + index2; 427 FT_UInt count1 = mask1->num_bits; 428 FT_UInt count2 = mask2->num_bits; 429 FT_Int delta; 430 431 432 if ( count2 > 0 ) 433 { 434 FT_UInt pos; 435 FT_Byte* read; 436 FT_Byte* write; 437 438 439 /* if "count2" is greater than "count1", we need to grow the */ 440 /* first bitset, and clear the highest bits */ 441 if ( count2 > count1 ) 442 { 443 error = ps_mask_ensure( mask1, count2, memory ); 444 if ( error ) 445 goto Exit; 446 447 for ( pos = count1; pos < count2; pos++ ) 448 ps_mask_clear_bit( mask1, pos ); 449 } 450 451 /* merge (unite) the bitsets */ 452 read = mask2->bytes; 453 write = mask1->bytes; 454 pos = ( count2 + 7 ) >> 3; 455 456 for ( ; pos > 0; pos-- ) 457 { 458 write[0] = (FT_Byte)( write[0] | read[0] ); 459 write++; 460 read++; 461 } 462 } 463 464 /* Now, remove "mask2" from the list. We need to keep the masks */ 465 /* sorted in order of importance, so move table elements. */ 466 mask2->num_bits = 0; 467 mask2->end_point = 0; 468 469 /* number of masks to move */ 470 delta = (FT_Int)( table->num_masks - 1 - index2 ); 471 if ( delta > 0 ) 472 { 473 /* move to end of table for reuse */ 474 PS_MaskRec dummy = *mask2; 475 476 477 ft_memmove( mask2, 478 mask2 + 1, 479 (FT_UInt)delta * sizeof ( PS_MaskRec ) ); 480 481 mask2[delta] = dummy; 482 } 483 484 table->num_masks--; 485 } 486 else 487 FT_TRACE0(( "ps_mask_table_merge: ignoring invalid indices (%d,%d)\n", 488 index1, index2 )); 489 490 Exit: 491 return error; 492 } 493 494 495 /* Try to merge all masks in a given table. This is used to merge */ 496 /* all counter masks into independent counter "paths". */ 497 /* */ 498 static FT_Error ps_mask_table_merge_all(PS_Mask_Table table,FT_Memory memory)499 ps_mask_table_merge_all( PS_Mask_Table table, 500 FT_Memory memory ) 501 { 502 FT_Int index1, index2; 503 FT_Error error = FT_Err_Ok; 504 505 506 /* both loops go down to 0, thus FT_Int for index1 and index2 */ 507 for ( index1 = (FT_Int)table->num_masks - 1; index1 > 0; index1-- ) 508 { 509 for ( index2 = index1 - 1; index2 >= 0; index2-- ) 510 { 511 if ( ps_mask_table_test_intersect( table, 512 (FT_UInt)index1, 513 (FT_UInt)index2 ) ) 514 { 515 error = ps_mask_table_merge( table, 516 (FT_UInt)index2, 517 (FT_UInt)index1, 518 memory ); 519 if ( error ) 520 goto Exit; 521 522 break; 523 } 524 } 525 } 526 527 Exit: 528 return error; 529 } 530 531 532 /*************************************************************************/ 533 /*************************************************************************/ 534 /***** *****/ 535 /***** PS_DIMENSION MANAGEMENT *****/ 536 /***** *****/ 537 /*************************************************************************/ 538 /*************************************************************************/ 539 540 541 /* finalize a given dimension */ 542 static void ps_dimension_done(PS_Dimension dimension,FT_Memory memory)543 ps_dimension_done( PS_Dimension dimension, 544 FT_Memory memory ) 545 { 546 ps_mask_table_done( &dimension->counters, memory ); 547 ps_mask_table_done( &dimension->masks, memory ); 548 ps_hint_table_done( &dimension->hints, memory ); 549 } 550 551 552 /* initialize a given dimension */ 553 static void ps_dimension_init(PS_Dimension dimension)554 ps_dimension_init( PS_Dimension dimension ) 555 { 556 dimension->hints.num_hints = 0; 557 dimension->masks.num_masks = 0; 558 dimension->counters.num_masks = 0; 559 } 560 561 562 #if 0 563 564 /* set a bit at a given index in the current hint mask */ 565 static FT_Error 566 ps_dimension_set_mask_bit( PS_Dimension dim, 567 FT_UInt idx, 568 FT_Memory memory ) 569 { 570 PS_Mask mask; 571 FT_Error error = FT_Err_Ok; 572 573 574 /* get last hint mask */ 575 error = ps_mask_table_last( &dim->masks, memory, &mask ); 576 if ( error ) 577 goto Exit; 578 579 error = ps_mask_set_bit( mask, idx, memory ); 580 581 Exit: 582 return error; 583 } 584 585 #endif 586 587 /* set the end point in a mask, called from "End" & "Reset" methods */ 588 static void ps_dimension_end_mask(PS_Dimension dim,FT_UInt end_point)589 ps_dimension_end_mask( PS_Dimension dim, 590 FT_UInt end_point ) 591 { 592 FT_UInt count = dim->masks.num_masks; 593 594 595 if ( count > 0 ) 596 { 597 PS_Mask mask = dim->masks.masks + count - 1; 598 599 600 mask->end_point = end_point; 601 } 602 } 603 604 605 /* set the end point in the current mask, then create a new empty one */ 606 /* (called by "Reset" method) */ 607 static FT_Error ps_dimension_reset_mask(PS_Dimension dim,FT_UInt end_point,FT_Memory memory)608 ps_dimension_reset_mask( PS_Dimension dim, 609 FT_UInt end_point, 610 FT_Memory memory ) 611 { 612 PS_Mask mask; 613 614 615 /* end current mask */ 616 ps_dimension_end_mask( dim, end_point ); 617 618 /* allocate new one */ 619 return ps_mask_table_alloc( &dim->masks, memory, &mask ); 620 } 621 622 623 /* set a new mask, called from the "T2Stem" method */ 624 static FT_Error ps_dimension_set_mask_bits(PS_Dimension dim,const FT_Byte * source,FT_UInt source_pos,FT_UInt source_bits,FT_UInt end_point,FT_Memory memory)625 ps_dimension_set_mask_bits( PS_Dimension dim, 626 const FT_Byte* source, 627 FT_UInt source_pos, 628 FT_UInt source_bits, 629 FT_UInt end_point, 630 FT_Memory memory ) 631 { 632 FT_Error error; 633 634 635 /* reset current mask, if any */ 636 error = ps_dimension_reset_mask( dim, end_point, memory ); 637 if ( error ) 638 goto Exit; 639 640 /* set bits in new mask */ 641 error = ps_mask_table_set_bits( &dim->masks, source, 642 source_pos, source_bits, memory ); 643 644 Exit: 645 return error; 646 } 647 648 649 /* add a new single stem (called from "T1Stem" method) */ 650 static FT_Error ps_dimension_add_t1stem(PS_Dimension dim,FT_Int pos,FT_Int len,FT_Memory memory,FT_Int * aindex)651 ps_dimension_add_t1stem( PS_Dimension dim, 652 FT_Int pos, 653 FT_Int len, 654 FT_Memory memory, 655 FT_Int *aindex ) 656 { 657 FT_Error error = FT_Err_Ok; 658 FT_UInt flags = 0; 659 660 661 /* detect ghost stem */ 662 if ( len < 0 ) 663 { 664 flags |= PS_HINT_FLAG_GHOST; 665 if ( len == -21 ) 666 { 667 flags |= PS_HINT_FLAG_BOTTOM; 668 pos = ADD_INT( pos, len ); 669 } 670 len = 0; 671 } 672 673 if ( aindex ) 674 *aindex = -1; 675 676 /* now, lookup stem in the current hints table */ 677 { 678 PS_Mask mask; 679 FT_UInt idx; 680 FT_UInt max = dim->hints.num_hints; 681 PS_Hint hint = dim->hints.hints; 682 683 684 for ( idx = 0; idx < max; idx++, hint++ ) 685 { 686 if ( hint->pos == pos && hint->len == len ) 687 break; 688 } 689 690 /* we need to create a new hint in the table */ 691 if ( idx >= max ) 692 { 693 error = ps_hint_table_alloc( &dim->hints, memory, &hint ); 694 if ( error ) 695 goto Exit; 696 697 hint->pos = pos; 698 hint->len = len; 699 hint->flags = flags; 700 } 701 702 /* now, store the hint in the current mask */ 703 error = ps_mask_table_last( &dim->masks, memory, &mask ); 704 if ( error ) 705 goto Exit; 706 707 error = ps_mask_set_bit( mask, idx, memory ); 708 if ( error ) 709 goto Exit; 710 711 if ( aindex ) 712 *aindex = (FT_Int)idx; 713 } 714 715 Exit: 716 return error; 717 } 718 719 720 /* add a "hstem3/vstem3" counter to our dimension table */ 721 static FT_Error ps_dimension_add_counter(PS_Dimension dim,FT_Int hint1,FT_Int hint2,FT_Int hint3,FT_Memory memory)722 ps_dimension_add_counter( PS_Dimension dim, 723 FT_Int hint1, 724 FT_Int hint2, 725 FT_Int hint3, 726 FT_Memory memory ) 727 { 728 FT_Error error = FT_Err_Ok; 729 FT_UInt count = dim->counters.num_masks; 730 PS_Mask counter = dim->counters.masks; 731 732 733 /* try to find an existing counter mask that already uses */ 734 /* one of these stems here */ 735 for ( ; count > 0; count--, counter++ ) 736 { 737 if ( ps_mask_test_bit( counter, hint1 ) || 738 ps_mask_test_bit( counter, hint2 ) || 739 ps_mask_test_bit( counter, hint3 ) ) 740 break; 741 } 742 743 /* create a new counter when needed */ 744 if ( count == 0 ) 745 { 746 error = ps_mask_table_alloc( &dim->counters, memory, &counter ); 747 if ( error ) 748 goto Exit; 749 } 750 751 /* now, set the bits for our hints in the counter mask */ 752 if ( hint1 >= 0 ) 753 { 754 error = ps_mask_set_bit( counter, (FT_UInt)hint1, memory ); 755 if ( error ) 756 goto Exit; 757 } 758 759 if ( hint2 >= 0 ) 760 { 761 error = ps_mask_set_bit( counter, (FT_UInt)hint2, memory ); 762 if ( error ) 763 goto Exit; 764 } 765 766 if ( hint3 >= 0 ) 767 { 768 error = ps_mask_set_bit( counter, (FT_UInt)hint3, memory ); 769 if ( error ) 770 goto Exit; 771 } 772 773 Exit: 774 return error; 775 } 776 777 778 /* end of recording session for a given dimension */ 779 static FT_Error ps_dimension_end(PS_Dimension dim,FT_UInt end_point,FT_Memory memory)780 ps_dimension_end( PS_Dimension dim, 781 FT_UInt end_point, 782 FT_Memory memory ) 783 { 784 /* end hint mask table */ 785 ps_dimension_end_mask( dim, end_point ); 786 787 /* merge all counter masks into independent "paths" */ 788 return ps_mask_table_merge_all( &dim->counters, memory ); 789 } 790 791 792 /*************************************************************************/ 793 /*************************************************************************/ 794 /***** *****/ 795 /***** PS_RECORDER MANAGEMENT *****/ 796 /***** *****/ 797 /*************************************************************************/ 798 /*************************************************************************/ 799 800 801 /* destroy hints */ 802 FT_LOCAL( void ) ps_hints_done(PS_Hints hints)803 ps_hints_done( PS_Hints hints ) 804 { 805 FT_Memory memory = hints->memory; 806 807 808 ps_dimension_done( &hints->dimension[0], memory ); 809 ps_dimension_done( &hints->dimension[1], memory ); 810 811 hints->error = FT_Err_Ok; 812 hints->memory = NULL; 813 } 814 815 816 FT_LOCAL( void ) ps_hints_init(PS_Hints hints,FT_Memory memory)817 ps_hints_init( PS_Hints hints, 818 FT_Memory memory ) 819 { 820 FT_ZERO( hints ); 821 hints->memory = memory; 822 } 823 824 825 /* initialize a hints for a new session */ 826 static void ps_hints_open(PS_Hints hints,PS_Hint_Type hint_type)827 ps_hints_open( PS_Hints hints, 828 PS_Hint_Type hint_type ) 829 { 830 hints->error = FT_Err_Ok; 831 hints->hint_type = hint_type; 832 833 ps_dimension_init( &hints->dimension[0] ); 834 ps_dimension_init( &hints->dimension[1] ); 835 } 836 837 838 /* add one or more stems to the current hints table */ 839 static void ps_hints_stem(PS_Hints hints,FT_UInt dimension,FT_Int count,FT_Long * stems)840 ps_hints_stem( PS_Hints hints, 841 FT_UInt dimension, 842 FT_Int count, 843 FT_Long* stems ) 844 { 845 PS_Dimension dim; 846 847 848 if ( hints->error ) 849 return; 850 851 /* limit "dimension" to 0..1 */ 852 if ( dimension > 1 ) 853 { 854 FT_TRACE0(( "ps_hints_stem: invalid dimension (%d) used\n", 855 dimension )); 856 dimension = ( dimension != 0 ); 857 } 858 859 /* record the stems in the current hints/masks table */ 860 /* (Type 1 & 2's `hstem' or `vstem' operators) */ 861 dim = &hints->dimension[dimension]; 862 863 for ( ; count > 0; count--, stems += 2 ) 864 { 865 FT_Error error; 866 FT_Memory memory = hints->memory; 867 868 869 error = ps_dimension_add_t1stem( dim, 870 (FT_Int)stems[0], 871 (FT_Int)stems[1], 872 memory, 873 NULL ); 874 if ( error ) 875 { 876 FT_ERROR(( "ps_hints_stem: could not add stem" 877 " (%ld,%ld) to hints table\n", stems[0], stems[1] )); 878 879 hints->error = error; 880 return; 881 } 882 } 883 } 884 885 886 /* add one Type1 counter stem to the current hints table */ 887 static void ps_hints_t1stem3(PS_Hints hints,FT_UInt dimension,FT_Fixed * stems)888 ps_hints_t1stem3( PS_Hints hints, 889 FT_UInt dimension, 890 FT_Fixed* stems ) 891 { 892 FT_Error error = FT_Err_Ok; 893 894 895 if ( !hints->error ) 896 { 897 PS_Dimension dim; 898 FT_Memory memory = hints->memory; 899 FT_Int count; 900 FT_Int idx[3]; 901 902 903 /* limit "dimension" to 0..1 */ 904 if ( dimension > 1 ) 905 { 906 FT_TRACE0(( "ps_hints_t1stem3: invalid dimension (%d) used\n", 907 dimension )); 908 dimension = ( dimension != 0 ); 909 } 910 911 dim = &hints->dimension[dimension]; 912 913 /* there must be 6 elements in the 'stem' array */ 914 if ( hints->hint_type == PS_HINT_TYPE_1 ) 915 { 916 /* add the three stems to our hints/masks table */ 917 for ( count = 0; count < 3; count++, stems += 2 ) 918 { 919 error = ps_dimension_add_t1stem( dim, 920 (FT_Int)FIXED_TO_INT( stems[0] ), 921 (FT_Int)FIXED_TO_INT( stems[1] ), 922 memory, &idx[count] ); 923 if ( error ) 924 goto Fail; 925 } 926 927 /* now, add the hints to the counters table */ 928 error = ps_dimension_add_counter( dim, idx[0], idx[1], idx[2], 929 memory ); 930 if ( error ) 931 goto Fail; 932 } 933 else 934 { 935 FT_ERROR(( "ps_hints_t1stem3: called with invalid hint type\n" )); 936 error = FT_THROW( Invalid_Argument ); 937 goto Fail; 938 } 939 } 940 941 return; 942 943 Fail: 944 FT_ERROR(( "ps_hints_t1stem3: could not add counter stems to table\n" )); 945 hints->error = error; 946 } 947 948 949 /* reset hints (only with Type 1 hints) */ 950 static void ps_hints_t1reset(PS_Hints hints,FT_UInt end_point)951 ps_hints_t1reset( PS_Hints hints, 952 FT_UInt end_point ) 953 { 954 FT_Error error = FT_Err_Ok; 955 956 957 if ( !hints->error ) 958 { 959 FT_Memory memory = hints->memory; 960 961 962 if ( hints->hint_type == PS_HINT_TYPE_1 ) 963 { 964 error = ps_dimension_reset_mask( &hints->dimension[0], 965 end_point, memory ); 966 if ( error ) 967 goto Fail; 968 969 error = ps_dimension_reset_mask( &hints->dimension[1], 970 end_point, memory ); 971 if ( error ) 972 goto Fail; 973 } 974 else 975 { 976 /* invalid hint type */ 977 error = FT_THROW( Invalid_Argument ); 978 goto Fail; 979 } 980 } 981 return; 982 983 Fail: 984 hints->error = error; 985 } 986 987 988 /* Type2 "hintmask" operator, add a new hintmask to each direction */ 989 static void ps_hints_t2mask(PS_Hints hints,FT_UInt end_point,FT_UInt bit_count,const FT_Byte * bytes)990 ps_hints_t2mask( PS_Hints hints, 991 FT_UInt end_point, 992 FT_UInt bit_count, 993 const FT_Byte* bytes ) 994 { 995 FT_Error error; 996 997 998 if ( !hints->error ) 999 { 1000 PS_Dimension dim = hints->dimension; 1001 FT_Memory memory = hints->memory; 1002 FT_UInt count1 = dim[0].hints.num_hints; 1003 FT_UInt count2 = dim[1].hints.num_hints; 1004 1005 1006 /* check bit count; must be equal to current total hint count */ 1007 if ( bit_count != count1 + count2 ) 1008 { 1009 FT_TRACE0(( "ps_hints_t2mask:" 1010 " called with invalid bitcount %d (instead of %d)\n", 1011 bit_count, count1 + count2 )); 1012 1013 /* simply ignore the operator */ 1014 return; 1015 } 1016 1017 /* set-up new horizontal and vertical hint mask now */ 1018 error = ps_dimension_set_mask_bits( &dim[0], bytes, count2, count1, 1019 end_point, memory ); 1020 if ( error ) 1021 goto Fail; 1022 1023 error = ps_dimension_set_mask_bits( &dim[1], bytes, 0, count2, 1024 end_point, memory ); 1025 if ( error ) 1026 goto Fail; 1027 } 1028 return; 1029 1030 Fail: 1031 hints->error = error; 1032 } 1033 1034 1035 static void ps_hints_t2counter(PS_Hints hints,FT_UInt bit_count,const FT_Byte * bytes)1036 ps_hints_t2counter( PS_Hints hints, 1037 FT_UInt bit_count, 1038 const FT_Byte* bytes ) 1039 { 1040 FT_Error error; 1041 1042 1043 if ( !hints->error ) 1044 { 1045 PS_Dimension dim = hints->dimension; 1046 FT_Memory memory = hints->memory; 1047 FT_UInt count1 = dim[0].hints.num_hints; 1048 FT_UInt count2 = dim[1].hints.num_hints; 1049 1050 1051 /* check bit count, must be equal to current total hint count */ 1052 if ( bit_count != count1 + count2 ) 1053 { 1054 FT_TRACE0(( "ps_hints_t2counter:" 1055 " called with invalid bitcount %d (instead of %d)\n", 1056 bit_count, count1 + count2 )); 1057 1058 /* simply ignore the operator */ 1059 return; 1060 } 1061 1062 /* set-up new horizontal and vertical hint mask now */ 1063 error = ps_dimension_set_mask_bits( &dim[0], bytes, 0, count1, 1064 0, memory ); 1065 if ( error ) 1066 goto Fail; 1067 1068 error = ps_dimension_set_mask_bits( &dim[1], bytes, count1, count2, 1069 0, memory ); 1070 if ( error ) 1071 goto Fail; 1072 } 1073 return; 1074 1075 Fail: 1076 hints->error = error; 1077 } 1078 1079 1080 /* end recording session */ 1081 static FT_Error ps_hints_close(PS_Hints hints,FT_UInt end_point)1082 ps_hints_close( PS_Hints hints, 1083 FT_UInt end_point ) 1084 { 1085 FT_Error error; 1086 1087 1088 error = hints->error; 1089 if ( !error ) 1090 { 1091 FT_Memory memory = hints->memory; 1092 PS_Dimension dim = hints->dimension; 1093 1094 1095 error = ps_dimension_end( &dim[0], end_point, memory ); 1096 if ( !error ) 1097 { 1098 error = ps_dimension_end( &dim[1], end_point, memory ); 1099 } 1100 } 1101 1102 #ifdef DEBUG_HINTER 1103 if ( !error ) 1104 ps_debug_hints = hints; 1105 #endif 1106 return error; 1107 } 1108 1109 1110 /*************************************************************************/ 1111 /*************************************************************************/ 1112 /***** *****/ 1113 /***** TYPE 1 HINTS RECORDING INTERFACE *****/ 1114 /***** *****/ 1115 /*************************************************************************/ 1116 /*************************************************************************/ 1117 1118 static void t1_hints_open(T1_Hints hints)1119 t1_hints_open( T1_Hints hints ) 1120 { 1121 ps_hints_open( (PS_Hints)hints, PS_HINT_TYPE_1 ); 1122 } 1123 1124 static void t1_hints_stem(T1_Hints hints,FT_UInt dimension,FT_Fixed * coords)1125 t1_hints_stem( T1_Hints hints, 1126 FT_UInt dimension, 1127 FT_Fixed* coords ) 1128 { 1129 FT_Pos stems[2]; 1130 1131 1132 stems[0] = FIXED_TO_INT( coords[0] ); 1133 stems[1] = FIXED_TO_INT( coords[1] ); 1134 1135 ps_hints_stem( (PS_Hints)hints, dimension, 1, stems ); 1136 } 1137 1138 1139 FT_LOCAL_DEF( void ) t1_hints_funcs_init(T1_Hints_FuncsRec * funcs)1140 t1_hints_funcs_init( T1_Hints_FuncsRec* funcs ) 1141 { 1142 FT_ZERO( funcs ); 1143 1144 funcs->open = (T1_Hints_OpenFunc) t1_hints_open; 1145 funcs->close = (T1_Hints_CloseFunc) ps_hints_close; 1146 funcs->stem = (T1_Hints_SetStemFunc) t1_hints_stem; 1147 funcs->stem3 = (T1_Hints_SetStem3Func)ps_hints_t1stem3; 1148 funcs->reset = (T1_Hints_ResetFunc) ps_hints_t1reset; 1149 funcs->apply = (T1_Hints_ApplyFunc) ps_hints_apply; 1150 } 1151 1152 1153 /*************************************************************************/ 1154 /*************************************************************************/ 1155 /***** *****/ 1156 /***** TYPE 2 HINTS RECORDING INTERFACE *****/ 1157 /***** *****/ 1158 /*************************************************************************/ 1159 /*************************************************************************/ 1160 1161 static void t2_hints_open(T2_Hints hints)1162 t2_hints_open( T2_Hints hints ) 1163 { 1164 ps_hints_open( (PS_Hints)hints, PS_HINT_TYPE_2 ); 1165 } 1166 1167 1168 static void t2_hints_stems(T2_Hints hints,FT_UInt dimension,FT_Int count,FT_Fixed * coords)1169 t2_hints_stems( T2_Hints hints, 1170 FT_UInt dimension, 1171 FT_Int count, 1172 FT_Fixed* coords ) 1173 { 1174 FT_Pos stems[32], y; 1175 FT_Int total = count, n; 1176 1177 1178 y = 0; 1179 while ( total > 0 ) 1180 { 1181 /* determine number of stems to write */ 1182 count = total; 1183 if ( count > 16 ) 1184 count = 16; 1185 1186 /* compute integer stem positions in font units */ 1187 for ( n = 0; n < count * 2; n++ ) 1188 { 1189 y = ADD_LONG( y, coords[n] ); 1190 stems[n] = FIXED_TO_INT( y ); 1191 } 1192 1193 /* compute lengths */ 1194 for ( n = 0; n < count * 2; n += 2 ) 1195 stems[n + 1] = stems[n + 1] - stems[n]; 1196 1197 /* add them to the current dimension */ 1198 ps_hints_stem( (PS_Hints)hints, dimension, count, stems ); 1199 1200 total -= count; 1201 } 1202 } 1203 1204 1205 FT_LOCAL_DEF( void ) t2_hints_funcs_init(T2_Hints_FuncsRec * funcs)1206 t2_hints_funcs_init( T2_Hints_FuncsRec* funcs ) 1207 { 1208 FT_ZERO( funcs ); 1209 1210 funcs->open = (T2_Hints_OpenFunc) t2_hints_open; 1211 funcs->close = (T2_Hints_CloseFunc) ps_hints_close; 1212 funcs->stems = (T2_Hints_StemsFunc) t2_hints_stems; 1213 funcs->hintmask= (T2_Hints_MaskFunc) ps_hints_t2mask; 1214 funcs->counter = (T2_Hints_CounterFunc)ps_hints_t2counter; 1215 funcs->apply = (T2_Hints_ApplyFunc) ps_hints_apply; 1216 } 1217 1218 1219 /* END */ 1220