afhints.c revision f463818dd9146e11105c0572fb119e757eb47768
1/***************************************************************************/ 2/* */ 3/* afhints.c */ 4/* */ 5/* Auto-fitter hinting routines (body). */ 6/* */ 7/* Copyright 2003, 2004, 2005, 2006, 2007 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 "afhints.h" 20#include "aferrors.h" 21#include FT_INTERNAL_CALC_H 22 23 24 FT_LOCAL_DEF( FT_Error ) 25 af_axis_hints_new_segment( AF_AxisHints axis, 26 FT_Memory memory, 27 AF_Segment *asegment ) 28 { 29 FT_Error error = AF_Err_Ok; 30 AF_Segment segment = NULL; 31 32 33 if ( axis->num_segments >= axis->max_segments ) 34 { 35 FT_Int old_max = axis->max_segments; 36 FT_Int new_max = old_max; 37 FT_Int big_max = FT_INT_MAX / sizeof ( *segment ); 38 39 40 if ( old_max >= big_max ) 41 { 42 error = AF_Err_Out_Of_Memory; 43 goto Exit; 44 } 45 46 new_max += ( new_max >> 2 ) + 4; 47 if ( new_max < old_max || new_max > big_max ) 48 new_max = big_max; 49 50 if ( FT_RENEW_ARRAY( axis->segments, old_max, new_max ) ) 51 goto Exit; 52 53 axis->max_segments = new_max; 54 } 55 56 segment = axis->segments + axis->num_segments++; 57 58 Exit: 59 *asegment = segment; 60 return error; 61 } 62 63 64 FT_LOCAL( FT_Error ) 65 af_axis_hints_new_edge( AF_AxisHints axis, 66 FT_Int fpos, 67 AF_Direction dir, 68 FT_Memory memory, 69 AF_Edge *aedge ) 70 { 71 FT_Error error = AF_Err_Ok; 72 AF_Edge edge = NULL; 73 AF_Edge edges; 74 75 76 if ( axis->num_edges >= axis->max_edges ) 77 { 78 FT_Int old_max = axis->max_edges; 79 FT_Int new_max = old_max; 80 FT_Int big_max = FT_INT_MAX / sizeof ( *edge ); 81 82 83 if ( old_max >= big_max ) 84 { 85 error = AF_Err_Out_Of_Memory; 86 goto Exit; 87 } 88 89 new_max += ( new_max >> 2 ) + 4; 90 if ( new_max < old_max || new_max > big_max ) 91 new_max = big_max; 92 93 if ( FT_RENEW_ARRAY( axis->edges, old_max, new_max ) ) 94 goto Exit; 95 96 axis->max_edges = new_max; 97 } 98 99 edges = axis->edges; 100 edge = edges + axis->num_edges; 101 102 while ( edge > edges ) 103 { 104 if ( edge[-1].fpos < fpos ) 105 break; 106 107 /* we want the edge with same position and minor direction */ 108 /* to appear before those in the major one in the list */ 109 if ( edge[-1].fpos == fpos && dir == axis->major_dir ) 110 break; 111 112 edge[0] = edge[-1]; 113 edge--; 114 } 115 116 axis->num_edges++; 117 118 FT_ZERO( edge ); 119 edge->fpos = (FT_Short)fpos; 120 edge->dir = (FT_Char)dir; 121 122 Exit: 123 *aedge = edge; 124 return error; 125 } 126 127 128#ifdef AF_DEBUG 129 130#include <stdio.h> 131 132 static const char* 133 af_dir_str( AF_Direction dir ) 134 { 135 const char* result; 136 137 138 switch ( dir ) 139 { 140 case AF_DIR_UP: 141 result = "up"; 142 break; 143 case AF_DIR_DOWN: 144 result = "down"; 145 break; 146 case AF_DIR_LEFT: 147 result = "left"; 148 break; 149 case AF_DIR_RIGHT: 150 result = "right"; 151 break; 152 default: 153 result = "none"; 154 } 155 156 return result; 157 } 158 159 160#define AF_INDEX_NUM( ptr, base ) ( (ptr) ? ( (ptr) - (base) ) : -1 ) 161 162 163 void 164 af_glyph_hints_dump_points( AF_GlyphHints hints ) 165 { 166 AF_Point points = hints->points; 167 AF_Point limit = points + hints->num_points; 168 AF_Point point; 169 170 171 printf( "Table of points:\n" ); 172 printf( " [ index | xorg | yorg | xscale | yscale " 173 "| xfit | yfit | flags ]\n" ); 174 175 for ( point = points; point < limit; point++ ) 176 { 177 printf( " [ %5d | %5d | %5d | %-5.2f | %-5.2f " 178 "| %-5.2f | %-5.2f | %c%c%c%c%c%c ]\n", 179 point - points, 180 point->fx, 181 point->fy, 182 point->ox/64.0, 183 point->oy/64.0, 184 point->x/64.0, 185 point->y/64.0, 186 ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) ? 'w' : ' ', 187 ( point->flags & AF_FLAG_INFLECTION ) ? 'i' : ' ', 188 ( point->flags & AF_FLAG_EXTREMA_X ) ? '<' : ' ', 189 ( point->flags & AF_FLAG_EXTREMA_Y ) ? 'v' : ' ', 190 ( point->flags & AF_FLAG_ROUND_X ) ? '(' : ' ', 191 ( point->flags & AF_FLAG_ROUND_Y ) ? 'u' : ' '); 192 } 193 printf( "\n" ); 194 } 195 196 197 static const char* 198 af_edge_flags_to_string( AF_Edge_Flags flags ) 199 { 200 static char temp[32]; 201 int pos = 0; 202 203 204 if ( flags & AF_EDGE_ROUND ) 205 { 206 memcpy( temp + pos, "round", 5 ); 207 pos += 5; 208 } 209 if ( flags & AF_EDGE_SERIF ) 210 { 211 if ( pos > 0 ) 212 temp[pos++] = ' '; 213 memcpy( temp + pos, "serif", 5 ); 214 pos += 5; 215 } 216 if ( pos == 0 ) 217 return "normal"; 218 219 temp[pos] = 0; 220 221 return temp; 222 } 223 224 225 /* A function to dump the array of linked segments. */ 226 void 227 af_glyph_hints_dump_segments( AF_GlyphHints hints ) 228 { 229 FT_Int dimension; 230 231 232 for ( dimension = 1; dimension >= 0; dimension-- ) 233 { 234 AF_AxisHints axis = &hints->axis[dimension]; 235 AF_Segment segments = axis->segments; 236 AF_Segment limit = segments + axis->num_segments; 237 AF_Segment seg; 238 239 240 printf ( "Table of %s segments:\n", 241 dimension == AF_DIMENSION_HORZ ? "vertical" : "horizontal" ); 242 printf ( " [ index | pos | dir | link | serif |" 243 " height | extra | flags ]\n" ); 244 245 for ( seg = segments; seg < limit; seg++ ) 246 { 247 printf ( " [ %5d | %5.2g | %5s | %4d | %5d | %5d | %5d | %s ]\n", 248 seg - segments, 249 dimension == AF_DIMENSION_HORZ ? (int)seg->first->ox / 64.0 250 : (int)seg->first->oy / 64.0, 251 af_dir_str( (AF_Direction)seg->dir ), 252 AF_INDEX_NUM( seg->link, segments ), 253 AF_INDEX_NUM( seg->serif, segments ), 254 seg->height, 255 seg->height - ( seg->max_coord - seg->min_coord ), 256 af_edge_flags_to_string( seg->flags ) ); 257 } 258 printf( "\n" ); 259 } 260 } 261 262 263 void 264 af_glyph_hints_dump_edges( AF_GlyphHints hints ) 265 { 266 FT_Int dimension; 267 268 269 for ( dimension = 1; dimension >= 0; dimension-- ) 270 { 271 AF_AxisHints axis = &hints->axis[dimension]; 272 AF_Edge edges = axis->edges; 273 AF_Edge limit = edges + axis->num_edges; 274 AF_Edge edge; 275 276 277 /* 278 * note: AF_DIMENSION_HORZ corresponds to _vertical_ edges 279 * since they have constant a X coordinate. 280 */ 281 printf ( "Table of %s edges:\n", 282 dimension == AF_DIMENSION_HORZ ? "vertical" : "horizontal" ); 283 printf ( " [ index | pos | dir | link |" 284 " serif | blue | opos | pos | flags ]\n" ); 285 286 for ( edge = edges; edge < limit; edge++ ) 287 { 288 printf ( " [ %5d | %5.2g | %5s | %4d |" 289 " %5d | %c | %5.2f | %5.2f | %s ]\n", 290 edge - edges, 291 (int)edge->opos / 64.0, 292 af_dir_str( (AF_Direction)edge->dir ), 293 AF_INDEX_NUM( edge->link, edges ), 294 AF_INDEX_NUM( edge->serif, edges ), 295 edge->blue_edge ? 'y' : 'n', 296 edge->opos / 64.0, 297 edge->pos / 64.0, 298 af_edge_flags_to_string( edge->flags ) ); 299 } 300 printf( "\n" ); 301 } 302 } 303 304#else /* !AF_DEBUG */ 305 306 /* these empty stubs are only used to link the `ftgrid' test program */ 307 /* when debugging is disabled */ 308 309 void 310 af_glyph_hints_dump_points( AF_GlyphHints hints ) 311 { 312 FT_UNUSED( hints ); 313 } 314 315 316 void 317 af_glyph_hints_dump_segments( AF_GlyphHints hints ) 318 { 319 FT_UNUSED( hints ); 320 } 321 322 323 void 324 af_glyph_hints_dump_edges( AF_GlyphHints hints ) 325 { 326 FT_UNUSED( hints ); 327 } 328 329#endif /* !AF_DEBUG */ 330 331 332 /* compute the direction value of a given vector */ 333 FT_LOCAL_DEF( AF_Direction ) 334 af_direction_compute( FT_Pos dx, 335 FT_Pos dy ) 336 { 337 FT_Pos ll, ss; /* long and short arm lengths */ 338 AF_Direction dir; /* candidate direction */ 339 340 341 if ( dy >= dx ) 342 { 343 if ( dy >= -dx ) 344 { 345 dir = AF_DIR_UP; 346 ll = dy; 347 ss = dx; 348 } 349 else 350 { 351 dir = AF_DIR_LEFT; 352 ll = -dx; 353 ss = dy; 354 } 355 } 356 else /* dy < dx */ 357 { 358 if ( dy >= -dx ) 359 { 360 dir = AF_DIR_RIGHT; 361 ll = dx; 362 ss = dy; 363 } 364 else 365 { 366 dir = AF_DIR_DOWN; 367 ll = dy; 368 ss = dx; 369 } 370 } 371 372 ss *= 14; 373 if ( FT_ABS( ll ) <= FT_ABS( ss ) ) 374 dir = AF_DIR_NONE; 375 376 return dir; 377 } 378 379 380 /* compute all inflex points in a given glyph */ 381 382 static void 383 af_glyph_hints_compute_inflections( AF_GlyphHints hints ) 384 { 385 AF_Point* contour = hints->contours; 386 AF_Point* contour_limit = contour + hints->num_contours; 387 388 389 /* do each contour separately */ 390 for ( ; contour < contour_limit; contour++ ) 391 { 392 AF_Point point = contour[0]; 393 AF_Point first = point; 394 AF_Point start = point; 395 AF_Point end = point; 396 AF_Point before; 397 AF_Point after; 398 FT_Pos in_x, in_y, out_x, out_y; 399 AF_Angle orient_prev, orient_cur; 400 FT_Int finished = 0; 401 402 403 /* compute first segment in contour */ 404 first = point; 405 406 start = end = first; 407 do 408 { 409 end = end->next; 410 if ( end == first ) 411 goto Skip; 412 413 in_x = end->fx - start->fx; 414 in_y = end->fy - start->fy; 415 416 } while ( in_x == 0 && in_y == 0 ); 417 418 /* extend the segment start whenever possible */ 419 before = start; 420 do 421 { 422 do 423 { 424 start = before; 425 before = before->prev; 426 if ( before == first ) 427 goto Skip; 428 429 out_x = start->fx - before->fx; 430 out_y = start->fy - before->fy; 431 432 } while ( out_x == 0 && out_y == 0 ); 433 434 orient_prev = ft_corner_orientation( in_x, in_y, out_x, out_y ); 435 436 } while ( orient_prev == 0 ); 437 438 first = start; 439 440 in_x = out_x; 441 in_y = out_y; 442 443 /* now process all segments in the contour */ 444 do 445 { 446 /* first, extend current segment's end whenever possible */ 447 after = end; 448 do 449 { 450 do 451 { 452 end = after; 453 after = after->next; 454 if ( after == first ) 455 finished = 1; 456 457 out_x = after->fx - end->fx; 458 out_y = after->fy - end->fy; 459 460 } while ( out_x == 0 && out_y == 0 ); 461 462 orient_cur = ft_corner_orientation( in_x, in_y, out_x, out_y ); 463 464 } while ( orient_cur == 0 ); 465 466 if ( ( orient_prev + orient_cur ) == 0 ) 467 { 468 /* we have an inflection point here */ 469 do 470 { 471 start->flags |= AF_FLAG_INFLECTION; 472 start = start->next; 473 474 } while ( start != end ); 475 476 start->flags |= AF_FLAG_INFLECTION; 477 } 478 479 start = end; 480 end = after; 481 482 orient_prev = orient_cur; 483 in_x = out_x; 484 in_y = out_y; 485 486 } while ( !finished ); 487 488 Skip: 489 ; 490 } 491 } 492 493 494 FT_LOCAL_DEF( void ) 495 af_glyph_hints_init( AF_GlyphHints hints, 496 FT_Memory memory ) 497 { 498 FT_ZERO( hints ); 499 hints->memory = memory; 500 } 501 502 503 FT_LOCAL_DEF( void ) 504 af_glyph_hints_done( AF_GlyphHints hints ) 505 { 506 if ( hints && hints->memory ) 507 { 508 FT_Memory memory = hints->memory; 509 int dim; 510 511 512 /* 513 * note that we don't need to free the segment and edge 514 * buffers, since they are really within the hints->points array 515 */ 516 for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) 517 { 518 AF_AxisHints axis = &hints->axis[dim]; 519 520 521 axis->num_segments = 0; 522 axis->max_segments = 0; 523 FT_FREE( axis->segments ); 524 525 axis->num_edges = 0; 526 axis->max_edges = 0; 527 FT_FREE( axis->edges ); 528 } 529 530 FT_FREE( hints->contours ); 531 hints->max_contours = 0; 532 hints->num_contours = 0; 533 534 FT_FREE( hints->points ); 535 hints->num_points = 0; 536 hints->max_points = 0; 537 538 hints->memory = NULL; 539 } 540 } 541 542 543 FT_LOCAL_DEF( void ) 544 af_glyph_hints_rescale( AF_GlyphHints hints, 545 AF_ScriptMetrics metrics ) 546 { 547 hints->metrics = metrics; 548 hints->scaler_flags = metrics->scaler.flags; 549 } 550 551 552 FT_LOCAL_DEF( FT_Error ) 553 af_glyph_hints_reload( AF_GlyphHints hints, 554 FT_Outline* outline, 555 FT_Bool get_inflections ) 556 { 557 FT_Error error = AF_Err_Ok; 558 AF_Point points; 559 FT_UInt old_max, new_max; 560 FT_Fixed x_scale = hints->x_scale; 561 FT_Fixed y_scale = hints->y_scale; 562 FT_Pos x_delta = hints->x_delta; 563 FT_Pos y_delta = hints->y_delta; 564 FT_Memory memory = hints->memory; 565 566 567 hints->num_points = 0; 568 hints->num_contours = 0; 569 570 hints->axis[0].num_segments = 0; 571 hints->axis[0].num_edges = 0; 572 hints->axis[1].num_segments = 0; 573 hints->axis[1].num_edges = 0; 574 575 /* first of all, reallocate the contours array when necessary */ 576 new_max = (FT_UInt)outline->n_contours; 577 old_max = hints->max_contours; 578 if ( new_max > old_max ) 579 { 580 new_max = ( new_max + 3 ) & ~3; 581 582 if ( FT_RENEW_ARRAY( hints->contours, old_max, new_max ) ) 583 goto Exit; 584 585 hints->max_contours = new_max; 586 } 587 588 /* 589 * then reallocate the points arrays if necessary -- 590 * note that we reserve two additional point positions, used to 591 * hint metrics appropriately 592 */ 593 new_max = (FT_UInt)( outline->n_points + 2 ); 594 old_max = hints->max_points; 595 if ( new_max > old_max ) 596 { 597 new_max = ( new_max + 2 + 7 ) & ~7; 598 599 if ( FT_RENEW_ARRAY( hints->points, old_max, new_max ) ) 600 goto Exit; 601 602 hints->max_points = new_max; 603 } 604 605 hints->num_points = outline->n_points; 606 hints->num_contours = outline->n_contours; 607 608 /* We can't rely on the value of `FT_Outline.flags' to know the fill */ 609 /* direction used for a glyph, given that some fonts are broken (e.g., */ 610 /* the Arphic ones). We thus recompute it each time we need to. */ 611 /* */ 612 hints->axis[AF_DIMENSION_HORZ].major_dir = AF_DIR_UP; 613 hints->axis[AF_DIMENSION_VERT].major_dir = AF_DIR_LEFT; 614 615 if ( FT_Outline_Get_Orientation( outline ) == FT_ORIENTATION_POSTSCRIPT ) 616 { 617 hints->axis[AF_DIMENSION_HORZ].major_dir = AF_DIR_DOWN; 618 hints->axis[AF_DIMENSION_VERT].major_dir = AF_DIR_RIGHT; 619 } 620 621 hints->x_scale = x_scale; 622 hints->y_scale = y_scale; 623 hints->x_delta = x_delta; 624 hints->y_delta = y_delta; 625 626 hints->xmin_delta = 0; 627 hints->xmax_delta = 0; 628 629 points = hints->points; 630 if ( hints->num_points == 0 ) 631 goto Exit; 632 633 { 634 AF_Point point; 635 AF_Point point_limit = points + hints->num_points; 636 637 638 /* compute coordinates & Bezier flags, next and prev */ 639 { 640 FT_Vector* vec = outline->points; 641 char* tag = outline->tags; 642 AF_Point first = points; 643 AF_Point end = points + outline->contours[0]; 644 AF_Point prev = end; 645 FT_Int contour_index = 0; 646 647 648 for ( point = points; point < point_limit; point++, vec++, tag++ ) 649 { 650 point->fx = (FT_Short)vec->x; 651 point->fy = (FT_Short)vec->y; 652 point->ox = point->x = FT_MulFix( vec->x, x_scale ) + x_delta; 653 point->oy = point->y = FT_MulFix( vec->y, y_scale ) + y_delta; 654 655 switch ( FT_CURVE_TAG( *tag ) ) 656 { 657 case FT_CURVE_TAG_CONIC: 658 point->flags = AF_FLAG_CONIC; 659 break; 660 case FT_CURVE_TAG_CUBIC: 661 point->flags = AF_FLAG_CUBIC; 662 break; 663 default: 664 point->flags = 0; 665 } 666 667 point->prev = prev; 668 prev->next = point; 669 prev = point; 670 671 if ( point == end ) 672 { 673 if ( ++contour_index < outline->n_contours ) 674 { 675 first = point + 1; 676 end = points + outline->contours[contour_index]; 677 prev = end; 678 } 679 } 680 } 681 } 682 683 /* set-up the contours array */ 684 { 685 AF_Point* contour = hints->contours; 686 AF_Point* contour_limit = contour + hints->num_contours; 687 short* end = outline->contours; 688 short idx = 0; 689 690 691 for ( ; contour < contour_limit; contour++, end++ ) 692 { 693 contour[0] = points + idx; 694 idx = (short)( end[0] + 1 ); 695 } 696 } 697 698 /* compute directions of in & out vectors */ 699 { 700 AF_Point first = points; 701 AF_Point prev = NULL; 702 FT_Pos in_x = 0; 703 FT_Pos in_y = 0; 704 AF_Direction in_dir = AF_DIR_NONE; 705 706 707 for ( point = points; point < point_limit; point++ ) 708 { 709 AF_Point next; 710 FT_Pos out_x, out_y; 711 712 713 if ( point == first ) 714 { 715 prev = first->prev; 716 in_x = first->fx - prev->fx; 717 in_y = first->fy - prev->fy; 718 in_dir = af_direction_compute( in_x, in_y ); 719 first = prev + 1; 720 } 721 722 point->in_dir = (FT_Char)in_dir; 723 724 next = point->next; 725 out_x = next->fx - point->fx; 726 out_y = next->fy - point->fy; 727 728 in_dir = af_direction_compute( out_x, out_y ); 729 point->out_dir = (FT_Char)in_dir; 730 731 if ( point->flags & ( AF_FLAG_CONIC | AF_FLAG_CUBIC ) ) 732 { 733 Is_Weak_Point: 734 point->flags |= AF_FLAG_WEAK_INTERPOLATION; 735 } 736 else if ( point->out_dir == point->in_dir ) 737 { 738 if ( point->out_dir != AF_DIR_NONE ) 739 goto Is_Weak_Point; 740 741 if ( ft_corner_is_flat( in_x, in_y, out_x, out_y ) ) 742 goto Is_Weak_Point; 743 } 744 else if ( point->in_dir == -point->out_dir ) 745 goto Is_Weak_Point; 746 747 in_x = out_x; 748 in_y = out_y; 749 prev = point; 750 } 751 } 752 } 753 754 /* compute inflection points -- */ 755 /* disabled due to no longer perceived benefits */ 756 if ( 0 && get_inflections ) 757 af_glyph_hints_compute_inflections( hints ); 758 759 Exit: 760 return error; 761 } 762 763 764 FT_LOCAL_DEF( void ) 765 af_glyph_hints_save( AF_GlyphHints hints, 766 FT_Outline* outline ) 767 { 768 AF_Point point = hints->points; 769 AF_Point limit = point + hints->num_points; 770 FT_Vector* vec = outline->points; 771 char* tag = outline->tags; 772 773 774 for ( ; point < limit; point++, vec++, tag++ ) 775 { 776 vec->x = point->x; 777 vec->y = point->y; 778 779 if ( point->flags & AF_FLAG_CONIC ) 780 tag[0] = FT_CURVE_TAG_CONIC; 781 else if ( point->flags & AF_FLAG_CUBIC ) 782 tag[0] = FT_CURVE_TAG_CUBIC; 783 else 784 tag[0] = FT_CURVE_TAG_ON; 785 } 786 } 787 788 789 /**************************************************************** 790 * 791 * EDGE POINT GRID-FITTING 792 * 793 ****************************************************************/ 794 795 796 FT_LOCAL_DEF( void ) 797 af_glyph_hints_align_edge_points( AF_GlyphHints hints, 798 AF_Dimension dim ) 799 { 800 AF_AxisHints axis = & hints->axis[dim]; 801 AF_Segment segments = axis->segments; 802 AF_Segment segment_limit = segments + axis->num_segments; 803 AF_Segment seg; 804 805 806 if ( dim == AF_DIMENSION_HORZ ) 807 { 808 for ( seg = segments; seg < segment_limit; seg++ ) 809 { 810 AF_Edge edge = seg->edge; 811 AF_Point point, first, last; 812 813 814 if ( edge == NULL ) 815 continue; 816 817 first = seg->first; 818 last = seg->last; 819 point = first; 820 for (;;) 821 { 822 point->x = edge->pos; 823 point->flags |= AF_FLAG_TOUCH_X; 824 825 if ( point == last ) 826 break; 827 828 point = point->next; 829 830 } 831 } 832 } 833 else 834 { 835 for ( seg = segments; seg < segment_limit; seg++ ) 836 { 837 AF_Edge edge = seg->edge; 838 AF_Point point, first, last; 839 840 841 if ( edge == NULL ) 842 continue; 843 844 first = seg->first; 845 last = seg->last; 846 point = first; 847 for (;;) 848 { 849 point->y = edge->pos; 850 point->flags |= AF_FLAG_TOUCH_Y; 851 852 if ( point == last ) 853 break; 854 855 point = point->next; 856 } 857 } 858 } 859 } 860 861 862 /**************************************************************** 863 * 864 * STRONG POINT INTERPOLATION 865 * 866 ****************************************************************/ 867 868 869 /* hint the strong points -- this is equivalent to the TrueType `IP' */ 870 /* hinting instruction */ 871 872 FT_LOCAL_DEF( void ) 873 af_glyph_hints_align_strong_points( AF_GlyphHints hints, 874 AF_Dimension dim ) 875 { 876 AF_Point points = hints->points; 877 AF_Point point_limit = points + hints->num_points; 878 AF_AxisHints axis = &hints->axis[dim]; 879 AF_Edge edges = axis->edges; 880 AF_Edge edge_limit = edges + axis->num_edges; 881 AF_Flags touch_flag; 882 883 884 if ( dim == AF_DIMENSION_HORZ ) 885 touch_flag = AF_FLAG_TOUCH_X; 886 else 887 touch_flag = AF_FLAG_TOUCH_Y; 888 889 if ( edges < edge_limit ) 890 { 891 AF_Point point; 892 AF_Edge edge; 893 894 895 for ( point = points; point < point_limit; point++ ) 896 { 897 FT_Pos u, ou, fu; /* point position */ 898 FT_Pos delta; 899 900 901 if ( point->flags & touch_flag ) 902 continue; 903 904 /* if this point is candidate to weak interpolation, we */ 905 /* interpolate it after all strong points have been processed */ 906 907 if ( ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) && 908 !( point->flags & AF_FLAG_INFLECTION ) ) 909 continue; 910 911 if ( dim == AF_DIMENSION_VERT ) 912 { 913 u = point->fy; 914 ou = point->oy; 915 } 916 else 917 { 918 u = point->fx; 919 ou = point->ox; 920 } 921 922 fu = u; 923 924 /* is the point before the first edge? */ 925 edge = edges; 926 delta = edge->fpos - u; 927 if ( delta >= 0 ) 928 { 929 u = edge->pos - ( edge->opos - ou ); 930 goto Store_Point; 931 } 932 933 /* is the point after the last edge? */ 934 edge = edge_limit - 1; 935 delta = u - edge->fpos; 936 if ( delta >= 0 ) 937 { 938 u = edge->pos + ( ou - edge->opos ); 939 goto Store_Point; 940 } 941 942 { 943 FT_UInt min, max, mid; 944 FT_Pos fpos; 945 946 947 /* find enclosing edges */ 948 min = 0; 949 max = edge_limit - edges; 950 951#if 1 952 /* for small edge counts, a linear search is better */ 953 if ( max <= 8 ) 954 { 955 FT_UInt nn; 956 957 for ( nn = 0; nn < max; nn++ ) 958 if ( edges[nn].fpos >= u ) 959 break; 960 961 if ( edges[nn].fpos == u ) 962 { 963 u = edges[nn].pos; 964 goto Store_Point; 965 } 966 min = nn; 967 } 968 else 969#endif 970 while ( min < max ) 971 { 972 mid = ( max + min ) >> 1; 973 edge = edges + mid; 974 fpos = edge->fpos; 975 976 if ( u < fpos ) 977 max = mid; 978 else if ( u > fpos ) 979 min = mid + 1; 980 else 981 { 982 /* we are on the edge */ 983 u = edge->pos; 984 goto Store_Point; 985 } 986 } 987 988 { 989 AF_Edge before = edges + min - 1; 990 AF_Edge after = edges + min + 0; 991 992 993 /* assert( before && after && before != after ) */ 994 if ( before->scale == 0 ) 995 before->scale = FT_DivFix( after->pos - before->pos, 996 after->fpos - before->fpos ); 997 998 u = before->pos + FT_MulFix( fu - before->fpos, 999 before->scale ); 1000 } 1001 } 1002 1003 Store_Point: 1004 /* save the point position */ 1005 if ( dim == AF_DIMENSION_HORZ ) 1006 point->x = u; 1007 else 1008 point->y = u; 1009 1010 point->flags |= touch_flag; 1011 } 1012 } 1013 } 1014 1015 1016 /**************************************************************** 1017 * 1018 * WEAK POINT INTERPOLATION 1019 * 1020 ****************************************************************/ 1021 1022 1023 static void 1024 af_iup_shift( AF_Point p1, 1025 AF_Point p2, 1026 AF_Point ref ) 1027 { 1028 AF_Point p; 1029 FT_Pos delta = ref->u - ref->v; 1030 1031 if ( delta == 0 ) 1032 return; 1033 1034 for ( p = p1; p < ref; p++ ) 1035 p->u = p->v + delta; 1036 1037 for ( p = ref + 1; p <= p2; p++ ) 1038 p->u = p->v + delta; 1039 } 1040 1041 1042 static void 1043 af_iup_interp( AF_Point p1, 1044 AF_Point p2, 1045 AF_Point ref1, 1046 AF_Point ref2 ) 1047 { 1048 AF_Point p; 1049 FT_Pos u; 1050 FT_Pos v1 = ref1->v; 1051 FT_Pos v2 = ref2->v; 1052 FT_Pos d1 = ref1->u - v1; 1053 FT_Pos d2 = ref2->u - v2; 1054 1055 1056 if ( p1 > p2 ) 1057 return; 1058 1059 if ( v1 == v2 ) 1060 { 1061 for ( p = p1; p <= p2; p++ ) 1062 { 1063 u = p->v; 1064 1065 if ( u <= v1 ) 1066 u += d1; 1067 else 1068 u += d2; 1069 1070 p->u = u; 1071 } 1072 return; 1073 } 1074 1075 if ( v1 < v2 ) 1076 { 1077 for ( p = p1; p <= p2; p++ ) 1078 { 1079 u = p->v; 1080 1081 if ( u <= v1 ) 1082 u += d1; 1083 else if ( u >= v2 ) 1084 u += d2; 1085 else 1086 u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 ); 1087 1088 p->u = u; 1089 } 1090 } 1091 else 1092 { 1093 for ( p = p1; p <= p2; p++ ) 1094 { 1095 u = p->v; 1096 1097 if ( u <= v2 ) 1098 u += d2; 1099 else if ( u >= v1 ) 1100 u += d1; 1101 else 1102 u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 ); 1103 1104 p->u = u; 1105 } 1106 } 1107 } 1108 1109 1110 FT_LOCAL_DEF( void ) 1111 af_glyph_hints_align_weak_points( AF_GlyphHints hints, 1112 AF_Dimension dim ) 1113 { 1114 AF_Point points = hints->points; 1115 AF_Point point_limit = points + hints->num_points; 1116 AF_Point* contour = hints->contours; 1117 AF_Point* contour_limit = contour + hints->num_contours; 1118 AF_Flags touch_flag; 1119 AF_Point point; 1120 AF_Point end_point; 1121 AF_Point first_point; 1122 1123 1124 /* PASS 1: Move segment points to edge positions */ 1125 1126 if ( dim == AF_DIMENSION_HORZ ) 1127 { 1128 touch_flag = AF_FLAG_TOUCH_X; 1129 1130 for ( point = points; point < point_limit; point++ ) 1131 { 1132 point->u = point->x; 1133 point->v = point->ox; 1134 } 1135 } 1136 else 1137 { 1138 touch_flag = AF_FLAG_TOUCH_Y; 1139 1140 for ( point = points; point < point_limit; point++ ) 1141 { 1142 point->u = point->y; 1143 point->v = point->oy; 1144 } 1145 } 1146 1147 point = points; 1148 1149 for ( ; contour < contour_limit; contour++ ) 1150 { 1151 AF_Point first_touched, last_touched; 1152 1153 1154 point = *contour; 1155 end_point = point->prev; 1156 first_point = point; 1157 1158 /* find first touched point */ 1159 for (;;) 1160 { 1161 if ( point > end_point ) /* no touched point in contour */ 1162 goto NextContour; 1163 1164 if ( point->flags & touch_flag ) 1165 break; 1166 1167 point++; 1168 } 1169 1170 first_touched = point; 1171 last_touched = point; 1172 1173 for (;;) 1174 { 1175 FT_ASSERT( point <= end_point && 1176 ( point->flags & touch_flag ) != 0 ); 1177 1178 /* skip any touched neighbhours */ 1179 while ( point < end_point && ( point[1].flags & touch_flag ) != 0 ) 1180 point++; 1181 1182 last_touched = point; 1183 1184 /* find the next touched point, if any */ 1185 point ++; 1186 for (;;) 1187 { 1188 if ( point > end_point ) 1189 goto EndContour; 1190 1191 if ( ( point->flags & touch_flag ) != 0 ) 1192 break; 1193 1194 point++; 1195 } 1196 1197 /* interpolate between last_touched and point */ 1198 af_iup_interp( last_touched + 1, point - 1, 1199 last_touched, point ); 1200 } 1201 1202 EndContour: 1203 /* special case: only one point was touched */ 1204 if ( last_touched == first_touched ) 1205 { 1206 af_iup_shift( first_point, end_point, first_touched ); 1207 } 1208 else /* interpolate the last part */ 1209 { 1210 if ( last_touched < end_point ) 1211 af_iup_interp( last_touched + 1, end_point, 1212 last_touched, first_touched ); 1213 1214 if ( first_touched > points ) 1215 af_iup_interp( first_point, first_touched - 1, 1216 last_touched, first_touched ); 1217 } 1218 1219 NextContour: 1220 ; 1221 } 1222 1223 /* now save the interpolated values back to x/y */ 1224 if ( dim == AF_DIMENSION_HORZ ) 1225 { 1226 for ( point = points; point < point_limit; point++ ) 1227 point->x = point->u; 1228 } 1229 else 1230 { 1231 for ( point = points; point < point_limit; point++ ) 1232 point->y = point->u; 1233 } 1234 } 1235 1236 1237#ifdef AF_USE_WARPER 1238 1239 FT_LOCAL_DEF( void ) 1240 af_glyph_hints_scale_dim( AF_GlyphHints hints, 1241 AF_Dimension dim, 1242 FT_Fixed scale, 1243 FT_Pos delta ) 1244 { 1245 AF_Point points = hints->points; 1246 AF_Point points_limit = points + hints->num_points; 1247 AF_Point point; 1248 1249 1250 if ( dim == AF_DIMENSION_HORZ ) 1251 { 1252 for ( point = points; point < points_limit; point++ ) 1253 point->x = FT_MulFix( point->fx, scale ) + delta; 1254 } 1255 else 1256 { 1257 for ( point = points; point < points_limit; point++ ) 1258 point->y = FT_MulFix( point->fy, scale ) + delta; 1259 } 1260 } 1261 1262#endif /* AF_USE_WARPER */ 1263 1264/* END */ 1265