1 /**************************************************************************** 2 * 3 * pshrec.c 4 * 5 * FreeType PostScript hints recorder (body). 6 * 7 * Copyright (C) 2001-2021 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_UInt index1, index2; 503 FT_Error error = FT_Err_Ok; 504 505 506 /* the loops stop when unsigned indices wrap around after 0 */ 507 for ( index1 = table->num_masks - 1; index1 < table->num_masks; index1-- ) 508 { 509 for ( index2 = index1 - 1; index2 < index1; index2-- ) 510 { 511 if ( ps_mask_table_test_intersect( table, index1, index2 ) ) 512 { 513 error = ps_mask_table_merge( table, index2, index1, memory ); 514 if ( error ) 515 goto Exit; 516 517 break; 518 } 519 } 520 } 521 522 Exit: 523 return error; 524 } 525 526 527 /*************************************************************************/ 528 /*************************************************************************/ 529 /***** *****/ 530 /***** PS_DIMENSION MANAGEMENT *****/ 531 /***** *****/ 532 /*************************************************************************/ 533 /*************************************************************************/ 534 535 536 /* finalize a given dimension */ 537 static void ps_dimension_done(PS_Dimension dimension,FT_Memory memory)538 ps_dimension_done( PS_Dimension dimension, 539 FT_Memory memory ) 540 { 541 ps_mask_table_done( &dimension->counters, memory ); 542 ps_mask_table_done( &dimension->masks, memory ); 543 ps_hint_table_done( &dimension->hints, memory ); 544 } 545 546 547 /* initialize a given dimension */ 548 static void ps_dimension_init(PS_Dimension dimension)549 ps_dimension_init( PS_Dimension dimension ) 550 { 551 dimension->hints.num_hints = 0; 552 dimension->masks.num_masks = 0; 553 dimension->counters.num_masks = 0; 554 } 555 556 557 #if 0 558 559 /* set a bit at a given index in the current hint mask */ 560 static FT_Error 561 ps_dimension_set_mask_bit( PS_Dimension dim, 562 FT_UInt idx, 563 FT_Memory memory ) 564 { 565 PS_Mask mask; 566 FT_Error error = FT_Err_Ok; 567 568 569 /* get last hint mask */ 570 error = ps_mask_table_last( &dim->masks, memory, &mask ); 571 if ( error ) 572 goto Exit; 573 574 error = ps_mask_set_bit( mask, idx, memory ); 575 576 Exit: 577 return error; 578 } 579 580 #endif 581 582 /* set the end point in a mask, called from "End" & "Reset" methods */ 583 static void ps_dimension_end_mask(PS_Dimension dim,FT_UInt end_point)584 ps_dimension_end_mask( PS_Dimension dim, 585 FT_UInt end_point ) 586 { 587 FT_UInt count = dim->masks.num_masks; 588 589 590 if ( count > 0 ) 591 { 592 PS_Mask mask = dim->masks.masks + count - 1; 593 594 595 mask->end_point = end_point; 596 } 597 } 598 599 600 /* set the end point in the current mask, then create a new empty one */ 601 /* (called by "Reset" method) */ 602 static FT_Error ps_dimension_reset_mask(PS_Dimension dim,FT_UInt end_point,FT_Memory memory)603 ps_dimension_reset_mask( PS_Dimension dim, 604 FT_UInt end_point, 605 FT_Memory memory ) 606 { 607 PS_Mask mask; 608 609 610 /* end current mask */ 611 ps_dimension_end_mask( dim, end_point ); 612 613 /* allocate new one */ 614 return ps_mask_table_alloc( &dim->masks, memory, &mask ); 615 } 616 617 618 /* set a new mask, called from the "T2Stem" method */ 619 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)620 ps_dimension_set_mask_bits( PS_Dimension dim, 621 const FT_Byte* source, 622 FT_UInt source_pos, 623 FT_UInt source_bits, 624 FT_UInt end_point, 625 FT_Memory memory ) 626 { 627 FT_Error error; 628 629 630 /* reset current mask, if any */ 631 error = ps_dimension_reset_mask( dim, end_point, memory ); 632 if ( error ) 633 goto Exit; 634 635 /* set bits in new mask */ 636 error = ps_mask_table_set_bits( &dim->masks, source, 637 source_pos, source_bits, memory ); 638 639 Exit: 640 return error; 641 } 642 643 644 /* add a new single stem (called from "T1Stem" method) */ 645 static FT_Error ps_dimension_add_t1stem(PS_Dimension dim,FT_Int pos,FT_Int len,FT_Memory memory,FT_Int * aindex)646 ps_dimension_add_t1stem( PS_Dimension dim, 647 FT_Int pos, 648 FT_Int len, 649 FT_Memory memory, 650 FT_Int *aindex ) 651 { 652 FT_Error error = FT_Err_Ok; 653 FT_UInt flags = 0; 654 655 656 /* detect ghost stem */ 657 if ( len < 0 ) 658 { 659 flags |= PS_HINT_FLAG_GHOST; 660 if ( len == -21 ) 661 { 662 flags |= PS_HINT_FLAG_BOTTOM; 663 pos = ADD_INT( pos, len ); 664 } 665 len = 0; 666 } 667 668 if ( aindex ) 669 *aindex = -1; 670 671 /* now, lookup stem in the current hints table */ 672 { 673 PS_Mask mask; 674 FT_UInt idx; 675 FT_UInt max = dim->hints.num_hints; 676 PS_Hint hint = dim->hints.hints; 677 678 679 for ( idx = 0; idx < max; idx++, hint++ ) 680 { 681 if ( hint->pos == pos && hint->len == len ) 682 break; 683 } 684 685 /* we need to create a new hint in the table */ 686 if ( idx >= max ) 687 { 688 error = ps_hint_table_alloc( &dim->hints, memory, &hint ); 689 if ( error ) 690 goto Exit; 691 692 hint->pos = pos; 693 hint->len = len; 694 hint->flags = flags; 695 } 696 697 /* now, store the hint in the current mask */ 698 error = ps_mask_table_last( &dim->masks, memory, &mask ); 699 if ( error ) 700 goto Exit; 701 702 error = ps_mask_set_bit( mask, idx, memory ); 703 if ( error ) 704 goto Exit; 705 706 if ( aindex ) 707 *aindex = (FT_Int)idx; 708 } 709 710 Exit: 711 return error; 712 } 713 714 715 /* add a "hstem3/vstem3" counter to our dimension table */ 716 static FT_Error ps_dimension_add_counter(PS_Dimension dim,FT_Int hint1,FT_Int hint2,FT_Int hint3,FT_Memory memory)717 ps_dimension_add_counter( PS_Dimension dim, 718 FT_Int hint1, 719 FT_Int hint2, 720 FT_Int hint3, 721 FT_Memory memory ) 722 { 723 FT_Error error = FT_Err_Ok; 724 FT_UInt count = dim->counters.num_masks; 725 PS_Mask counter = dim->counters.masks; 726 727 728 /* try to find an existing counter mask that already uses */ 729 /* one of these stems here */ 730 for ( ; count > 0; count--, counter++ ) 731 { 732 if ( ps_mask_test_bit( counter, hint1 ) || 733 ps_mask_test_bit( counter, hint2 ) || 734 ps_mask_test_bit( counter, hint3 ) ) 735 break; 736 } 737 738 /* create a new counter when needed */ 739 if ( count == 0 ) 740 { 741 error = ps_mask_table_alloc( &dim->counters, memory, &counter ); 742 if ( error ) 743 goto Exit; 744 } 745 746 /* now, set the bits for our hints in the counter mask */ 747 if ( hint1 >= 0 ) 748 { 749 error = ps_mask_set_bit( counter, (FT_UInt)hint1, memory ); 750 if ( error ) 751 goto Exit; 752 } 753 754 if ( hint2 >= 0 ) 755 { 756 error = ps_mask_set_bit( counter, (FT_UInt)hint2, memory ); 757 if ( error ) 758 goto Exit; 759 } 760 761 if ( hint3 >= 0 ) 762 { 763 error = ps_mask_set_bit( counter, (FT_UInt)hint3, memory ); 764 if ( error ) 765 goto Exit; 766 } 767 768 Exit: 769 return error; 770 } 771 772 773 /* end of recording session for a given dimension */ 774 static FT_Error ps_dimension_end(PS_Dimension dim,FT_UInt end_point,FT_Memory memory)775 ps_dimension_end( PS_Dimension dim, 776 FT_UInt end_point, 777 FT_Memory memory ) 778 { 779 /* end hint mask table */ 780 ps_dimension_end_mask( dim, end_point ); 781 782 /* merge all counter masks into independent "paths" */ 783 return ps_mask_table_merge_all( &dim->counters, memory ); 784 } 785 786 787 /*************************************************************************/ 788 /*************************************************************************/ 789 /***** *****/ 790 /***** PS_RECORDER MANAGEMENT *****/ 791 /***** *****/ 792 /*************************************************************************/ 793 /*************************************************************************/ 794 795 796 /* destroy hints */ 797 FT_LOCAL( void ) ps_hints_done(PS_Hints hints)798 ps_hints_done( PS_Hints hints ) 799 { 800 FT_Memory memory = hints->memory; 801 802 803 ps_dimension_done( &hints->dimension[0], memory ); 804 ps_dimension_done( &hints->dimension[1], memory ); 805 806 hints->error = FT_Err_Ok; 807 hints->memory = NULL; 808 } 809 810 811 FT_LOCAL( void ) ps_hints_init(PS_Hints hints,FT_Memory memory)812 ps_hints_init( PS_Hints hints, 813 FT_Memory memory ) 814 { 815 FT_ZERO( hints ); 816 hints->memory = memory; 817 } 818 819 820 /* initialize a hints for a new session */ 821 static void ps_hints_open(PS_Hints hints,PS_Hint_Type hint_type)822 ps_hints_open( PS_Hints hints, 823 PS_Hint_Type hint_type ) 824 { 825 hints->error = FT_Err_Ok; 826 hints->hint_type = hint_type; 827 828 ps_dimension_init( &hints->dimension[0] ); 829 ps_dimension_init( &hints->dimension[1] ); 830 } 831 832 833 /* add one or more stems to the current hints table */ 834 static void ps_hints_stem(PS_Hints hints,FT_UInt dimension,FT_Int count,FT_Long * stems)835 ps_hints_stem( PS_Hints hints, 836 FT_UInt dimension, 837 FT_Int count, 838 FT_Long* stems ) 839 { 840 PS_Dimension dim; 841 842 843 if ( hints->error ) 844 return; 845 846 /* limit "dimension" to 0..1 */ 847 if ( dimension > 1 ) 848 { 849 FT_TRACE0(( "ps_hints_stem: invalid dimension (%d) used\n", 850 dimension )); 851 dimension = ( dimension != 0 ); 852 } 853 854 /* record the stems in the current hints/masks table */ 855 /* (Type 1 & 2's `hstem' or `vstem' operators) */ 856 dim = &hints->dimension[dimension]; 857 858 for ( ; count > 0; count--, stems += 2 ) 859 { 860 FT_Error error; 861 FT_Memory memory = hints->memory; 862 863 864 error = ps_dimension_add_t1stem( dim, 865 (FT_Int)stems[0], 866 (FT_Int)stems[1], 867 memory, 868 NULL ); 869 if ( error ) 870 { 871 FT_ERROR(( "ps_hints_stem: could not add stem" 872 " (%ld,%ld) to hints table\n", stems[0], stems[1] )); 873 874 hints->error = error; 875 return; 876 } 877 } 878 } 879 880 881 /* add one Type1 counter stem to the current hints table */ 882 static void ps_hints_t1stem3(PS_Hints hints,FT_UInt dimension,FT_Fixed * stems)883 ps_hints_t1stem3( PS_Hints hints, 884 FT_UInt dimension, 885 FT_Fixed* stems ) 886 { 887 FT_Error error = FT_Err_Ok; 888 889 890 if ( !hints->error ) 891 { 892 PS_Dimension dim; 893 FT_Memory memory = hints->memory; 894 FT_Int count; 895 FT_Int idx[3]; 896 897 898 /* limit "dimension" to 0..1 */ 899 if ( dimension > 1 ) 900 { 901 FT_TRACE0(( "ps_hints_t1stem3: invalid dimension (%d) used\n", 902 dimension )); 903 dimension = ( dimension != 0 ); 904 } 905 906 dim = &hints->dimension[dimension]; 907 908 /* there must be 6 elements in the 'stem' array */ 909 if ( hints->hint_type == PS_HINT_TYPE_1 ) 910 { 911 /* add the three stems to our hints/masks table */ 912 for ( count = 0; count < 3; count++, stems += 2 ) 913 { 914 error = ps_dimension_add_t1stem( dim, 915 (FT_Int)FIXED_TO_INT( stems[0] ), 916 (FT_Int)FIXED_TO_INT( stems[1] ), 917 memory, &idx[count] ); 918 if ( error ) 919 goto Fail; 920 } 921 922 /* now, add the hints to the counters table */ 923 error = ps_dimension_add_counter( dim, idx[0], idx[1], idx[2], 924 memory ); 925 if ( error ) 926 goto Fail; 927 } 928 else 929 { 930 FT_ERROR(( "ps_hints_t1stem3: called with invalid hint type\n" )); 931 error = FT_THROW( Invalid_Argument ); 932 goto Fail; 933 } 934 } 935 936 return; 937 938 Fail: 939 FT_ERROR(( "ps_hints_t1stem3: could not add counter stems to table\n" )); 940 hints->error = error; 941 } 942 943 944 /* reset hints (only with Type 1 hints) */ 945 static void ps_hints_t1reset(PS_Hints hints,FT_UInt end_point)946 ps_hints_t1reset( PS_Hints hints, 947 FT_UInt end_point ) 948 { 949 FT_Error error = FT_Err_Ok; 950 951 952 if ( !hints->error ) 953 { 954 FT_Memory memory = hints->memory; 955 956 957 if ( hints->hint_type == PS_HINT_TYPE_1 ) 958 { 959 error = ps_dimension_reset_mask( &hints->dimension[0], 960 end_point, memory ); 961 if ( error ) 962 goto Fail; 963 964 error = ps_dimension_reset_mask( &hints->dimension[1], 965 end_point, memory ); 966 if ( error ) 967 goto Fail; 968 } 969 else 970 { 971 /* invalid hint type */ 972 error = FT_THROW( Invalid_Argument ); 973 goto Fail; 974 } 975 } 976 return; 977 978 Fail: 979 hints->error = error; 980 } 981 982 983 /* Type2 "hintmask" operator, add a new hintmask to each direction */ 984 static void ps_hints_t2mask(PS_Hints hints,FT_UInt end_point,FT_UInt bit_count,const FT_Byte * bytes)985 ps_hints_t2mask( PS_Hints hints, 986 FT_UInt end_point, 987 FT_UInt bit_count, 988 const FT_Byte* bytes ) 989 { 990 FT_Error error; 991 992 993 if ( !hints->error ) 994 { 995 PS_Dimension dim = hints->dimension; 996 FT_Memory memory = hints->memory; 997 FT_UInt count1 = dim[0].hints.num_hints; 998 FT_UInt count2 = dim[1].hints.num_hints; 999 1000 1001 /* check bit count; must be equal to current total hint count */ 1002 if ( bit_count != count1 + count2 ) 1003 { 1004 FT_TRACE0(( "ps_hints_t2mask:" 1005 " called with invalid bitcount %d (instead of %d)\n", 1006 bit_count, count1 + count2 )); 1007 1008 /* simply ignore the operator */ 1009 return; 1010 } 1011 1012 /* set-up new horizontal and vertical hint mask now */ 1013 error = ps_dimension_set_mask_bits( &dim[0], bytes, count2, count1, 1014 end_point, memory ); 1015 if ( error ) 1016 goto Fail; 1017 1018 error = ps_dimension_set_mask_bits( &dim[1], bytes, 0, count2, 1019 end_point, memory ); 1020 if ( error ) 1021 goto Fail; 1022 } 1023 return; 1024 1025 Fail: 1026 hints->error = error; 1027 } 1028 1029 1030 static void ps_hints_t2counter(PS_Hints hints,FT_UInt bit_count,const FT_Byte * bytes)1031 ps_hints_t2counter( PS_Hints hints, 1032 FT_UInt bit_count, 1033 const FT_Byte* bytes ) 1034 { 1035 FT_Error error; 1036 1037 1038 if ( !hints->error ) 1039 { 1040 PS_Dimension dim = hints->dimension; 1041 FT_Memory memory = hints->memory; 1042 FT_UInt count1 = dim[0].hints.num_hints; 1043 FT_UInt count2 = dim[1].hints.num_hints; 1044 1045 1046 /* check bit count, must be equal to current total hint count */ 1047 if ( bit_count != count1 + count2 ) 1048 { 1049 FT_TRACE0(( "ps_hints_t2counter:" 1050 " called with invalid bitcount %d (instead of %d)\n", 1051 bit_count, count1 + count2 )); 1052 1053 /* simply ignore the operator */ 1054 return; 1055 } 1056 1057 /* set-up new horizontal and vertical hint mask now */ 1058 error = ps_dimension_set_mask_bits( &dim[0], bytes, 0, count1, 1059 0, memory ); 1060 if ( error ) 1061 goto Fail; 1062 1063 error = ps_dimension_set_mask_bits( &dim[1], bytes, count1, count2, 1064 0, memory ); 1065 if ( error ) 1066 goto Fail; 1067 } 1068 return; 1069 1070 Fail: 1071 hints->error = error; 1072 } 1073 1074 1075 /* end recording session */ 1076 static FT_Error ps_hints_close(PS_Hints hints,FT_UInt end_point)1077 ps_hints_close( PS_Hints hints, 1078 FT_UInt end_point ) 1079 { 1080 FT_Error error; 1081 1082 1083 error = hints->error; 1084 if ( !error ) 1085 { 1086 FT_Memory memory = hints->memory; 1087 PS_Dimension dim = hints->dimension; 1088 1089 1090 error = ps_dimension_end( &dim[0], end_point, memory ); 1091 if ( !error ) 1092 { 1093 error = ps_dimension_end( &dim[1], end_point, memory ); 1094 } 1095 } 1096 1097 #ifdef DEBUG_HINTER 1098 if ( !error ) 1099 ps_debug_hints = hints; 1100 #endif 1101 return error; 1102 } 1103 1104 1105 /*************************************************************************/ 1106 /*************************************************************************/ 1107 /***** *****/ 1108 /***** TYPE 1 HINTS RECORDING INTERFACE *****/ 1109 /***** *****/ 1110 /*************************************************************************/ 1111 /*************************************************************************/ 1112 1113 static void t1_hints_open(T1_Hints hints)1114 t1_hints_open( T1_Hints hints ) 1115 { 1116 ps_hints_open( (PS_Hints)hints, PS_HINT_TYPE_1 ); 1117 } 1118 1119 static void t1_hints_stem(T1_Hints hints,FT_UInt dimension,FT_Fixed * coords)1120 t1_hints_stem( T1_Hints hints, 1121 FT_UInt dimension, 1122 FT_Fixed* coords ) 1123 { 1124 FT_Pos stems[2]; 1125 1126 1127 stems[0] = FIXED_TO_INT( coords[0] ); 1128 stems[1] = FIXED_TO_INT( coords[1] ); 1129 1130 ps_hints_stem( (PS_Hints)hints, dimension, 1, stems ); 1131 } 1132 1133 1134 FT_LOCAL_DEF( void ) t1_hints_funcs_init(T1_Hints_FuncsRec * funcs)1135 t1_hints_funcs_init( T1_Hints_FuncsRec* funcs ) 1136 { 1137 FT_ZERO( funcs ); 1138 1139 funcs->open = (T1_Hints_OpenFunc) t1_hints_open; 1140 funcs->close = (T1_Hints_CloseFunc) ps_hints_close; 1141 funcs->stem = (T1_Hints_SetStemFunc) t1_hints_stem; 1142 funcs->stem3 = (T1_Hints_SetStem3Func)ps_hints_t1stem3; 1143 funcs->reset = (T1_Hints_ResetFunc) ps_hints_t1reset; 1144 funcs->apply = (T1_Hints_ApplyFunc) ps_hints_apply; 1145 } 1146 1147 1148 /*************************************************************************/ 1149 /*************************************************************************/ 1150 /***** *****/ 1151 /***** TYPE 2 HINTS RECORDING INTERFACE *****/ 1152 /***** *****/ 1153 /*************************************************************************/ 1154 /*************************************************************************/ 1155 1156 static void t2_hints_open(T2_Hints hints)1157 t2_hints_open( T2_Hints hints ) 1158 { 1159 ps_hints_open( (PS_Hints)hints, PS_HINT_TYPE_2 ); 1160 } 1161 1162 1163 static void t2_hints_stems(T2_Hints hints,FT_UInt dimension,FT_Int count,FT_Fixed * coords)1164 t2_hints_stems( T2_Hints hints, 1165 FT_UInt dimension, 1166 FT_Int count, 1167 FT_Fixed* coords ) 1168 { 1169 FT_Pos stems[32], y; 1170 FT_Int total = count, n; 1171 1172 1173 y = 0; 1174 while ( total > 0 ) 1175 { 1176 /* determine number of stems to write */ 1177 count = total; 1178 if ( count > 16 ) 1179 count = 16; 1180 1181 /* compute integer stem positions in font units */ 1182 for ( n = 0; n < count * 2; n++ ) 1183 { 1184 y = ADD_LONG( y, coords[n] ); 1185 stems[n] = FIXED_TO_INT( y ); 1186 } 1187 1188 /* compute lengths */ 1189 for ( n = 0; n < count * 2; n += 2 ) 1190 stems[n + 1] = stems[n + 1] - stems[n]; 1191 1192 /* add them to the current dimension */ 1193 ps_hints_stem( (PS_Hints)hints, dimension, count, stems ); 1194 1195 total -= count; 1196 } 1197 } 1198 1199 1200 FT_LOCAL_DEF( void ) t2_hints_funcs_init(T2_Hints_FuncsRec * funcs)1201 t2_hints_funcs_init( T2_Hints_FuncsRec* funcs ) 1202 { 1203 FT_ZERO( funcs ); 1204 1205 funcs->open = (T2_Hints_OpenFunc) t2_hints_open; 1206 funcs->close = (T2_Hints_CloseFunc) ps_hints_close; 1207 funcs->stems = (T2_Hints_StemsFunc) t2_hints_stems; 1208 funcs->hintmask= (T2_Hints_MaskFunc) ps_hints_t2mask; 1209 funcs->counter = (T2_Hints_CounterFunc)ps_hints_t2counter; 1210 funcs->apply = (T2_Hints_ApplyFunc) ps_hints_apply; 1211 } 1212 1213 1214 /* END */ 1215