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