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