1 /***************************************************************************/ 2 /* */ 3 /* afhints.c */ 4 /* */ 5 /* Auto-fitter hinting routines (body). */ 6 /* */ 7 /* Copyright 2003, 2004, 2005, 2006, 2007, 2009, 2010 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 ) af_axis_hints_new_segment(AF_AxisHints axis,FT_Memory memory,AF_Segment * asegment)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)( 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 ) af_axis_hints_new_edge(AF_AxisHints axis,FT_Int fpos,AF_Direction dir,FT_Memory memory,AF_Edge * aedge)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)( 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 FT_CONFIG_STANDARD_LIBRARY_H 131 132 static const char* af_dir_str(AF_Direction dir)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 af_glyph_hints_dump_points(AF_GlyphHints hints)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* af_edge_flags_to_string(AF_Edge_Flags flags)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 ft_memcpy( temp + pos, "round", 5 ); 207 pos += 5; 208 } 209 if ( flags & AF_EDGE_SERIF ) 210 { 211 if ( pos > 0 ) 212 temp[pos++] = ' '; 213 ft_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 af_glyph_hints_dump_segments(AF_GlyphHints hints)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 af_glyph_hints_dump_edges(AF_GlyphHints hints)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 af_glyph_hints_dump_points(AF_GlyphHints hints)310 af_glyph_hints_dump_points( AF_GlyphHints hints ) 311 { 312 FT_UNUSED( hints ); 313 } 314 315 316 void af_glyph_hints_dump_segments(AF_GlyphHints hints)317 af_glyph_hints_dump_segments( AF_GlyphHints hints ) 318 { 319 FT_UNUSED( hints ); 320 } 321 322 323 void af_glyph_hints_dump_edges(AF_GlyphHints hints)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 ) af_direction_compute(FT_Pos dx,FT_Pos dy)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 FT_LOCAL_DEF( void ) af_glyph_hints_init(AF_GlyphHints hints,FT_Memory memory)381 af_glyph_hints_init( AF_GlyphHints hints, 382 FT_Memory memory ) 383 { 384 FT_ZERO( hints ); 385 hints->memory = memory; 386 } 387 388 389 FT_LOCAL_DEF( void ) af_glyph_hints_done(AF_GlyphHints hints)390 af_glyph_hints_done( AF_GlyphHints hints ) 391 { 392 if ( hints && hints->memory ) 393 { 394 FT_Memory memory = hints->memory; 395 int dim; 396 397 398 /* 399 * note that we don't need to free the segment and edge 400 * buffers, since they are really within the hints->points array 401 */ 402 for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) 403 { 404 AF_AxisHints axis = &hints->axis[dim]; 405 406 407 axis->num_segments = 0; 408 axis->max_segments = 0; 409 FT_FREE( axis->segments ); 410 411 axis->num_edges = 0; 412 axis->max_edges = 0; 413 FT_FREE( axis->edges ); 414 } 415 416 FT_FREE( hints->contours ); 417 hints->max_contours = 0; 418 hints->num_contours = 0; 419 420 FT_FREE( hints->points ); 421 hints->num_points = 0; 422 hints->max_points = 0; 423 424 hints->memory = NULL; 425 } 426 } 427 428 429 FT_LOCAL_DEF( void ) af_glyph_hints_rescale(AF_GlyphHints hints,AF_ScriptMetrics metrics)430 af_glyph_hints_rescale( AF_GlyphHints hints, 431 AF_ScriptMetrics metrics ) 432 { 433 hints->metrics = metrics; 434 hints->scaler_flags = metrics->scaler.flags; 435 } 436 437 438 FT_LOCAL_DEF( FT_Error ) af_glyph_hints_reload(AF_GlyphHints hints,FT_Outline * outline)439 af_glyph_hints_reload( AF_GlyphHints hints, 440 FT_Outline* outline ) 441 { 442 FT_Error error = AF_Err_Ok; 443 AF_Point points; 444 FT_UInt old_max, new_max; 445 FT_Fixed x_scale = hints->x_scale; 446 FT_Fixed y_scale = hints->y_scale; 447 FT_Pos x_delta = hints->x_delta; 448 FT_Pos y_delta = hints->y_delta; 449 FT_Memory memory = hints->memory; 450 451 452 hints->num_points = 0; 453 hints->num_contours = 0; 454 455 hints->axis[0].num_segments = 0; 456 hints->axis[0].num_edges = 0; 457 hints->axis[1].num_segments = 0; 458 hints->axis[1].num_edges = 0; 459 460 /* first of all, reallocate the contours array when necessary */ 461 new_max = (FT_UInt)outline->n_contours; 462 old_max = hints->max_contours; 463 if ( new_max > old_max ) 464 { 465 new_max = ( new_max + 3 ) & ~3; 466 467 if ( FT_RENEW_ARRAY( hints->contours, old_max, new_max ) ) 468 goto Exit; 469 470 hints->max_contours = new_max; 471 } 472 473 /* 474 * then reallocate the points arrays if necessary -- 475 * note that we reserve two additional point positions, used to 476 * hint metrics appropriately 477 */ 478 new_max = (FT_UInt)( outline->n_points + 2 ); 479 old_max = hints->max_points; 480 if ( new_max > old_max ) 481 { 482 new_max = ( new_max + 2 + 7 ) & ~7; 483 484 if ( FT_RENEW_ARRAY( hints->points, old_max, new_max ) ) 485 goto Exit; 486 487 hints->max_points = new_max; 488 } 489 490 hints->num_points = outline->n_points; 491 hints->num_contours = outline->n_contours; 492 493 /* We can't rely on the value of `FT_Outline.flags' to know the fill */ 494 /* direction used for a glyph, given that some fonts are broken (e.g., */ 495 /* the Arphic ones). We thus recompute it each time we need to. */ 496 /* */ 497 hints->axis[AF_DIMENSION_HORZ].major_dir = AF_DIR_UP; 498 hints->axis[AF_DIMENSION_VERT].major_dir = AF_DIR_LEFT; 499 500 if ( FT_Outline_Get_Orientation( outline ) == FT_ORIENTATION_POSTSCRIPT ) 501 { 502 hints->axis[AF_DIMENSION_HORZ].major_dir = AF_DIR_DOWN; 503 hints->axis[AF_DIMENSION_VERT].major_dir = AF_DIR_RIGHT; 504 } 505 506 hints->x_scale = x_scale; 507 hints->y_scale = y_scale; 508 hints->x_delta = x_delta; 509 hints->y_delta = y_delta; 510 511 hints->xmin_delta = 0; 512 hints->xmax_delta = 0; 513 514 points = hints->points; 515 if ( hints->num_points == 0 ) 516 goto Exit; 517 518 { 519 AF_Point point; 520 AF_Point point_limit = points + hints->num_points; 521 522 523 /* compute coordinates & Bezier flags, next and prev */ 524 { 525 FT_Vector* vec = outline->points; 526 char* tag = outline->tags; 527 AF_Point end = points + outline->contours[0]; 528 AF_Point prev = end; 529 FT_Int contour_index = 0; 530 531 532 for ( point = points; point < point_limit; point++, vec++, tag++ ) 533 { 534 point->fx = (FT_Short)vec->x; 535 point->fy = (FT_Short)vec->y; 536 point->ox = point->x = FT_MulFix( vec->x, x_scale ) + x_delta; 537 point->oy = point->y = FT_MulFix( vec->y, y_scale ) + y_delta; 538 539 switch ( FT_CURVE_TAG( *tag ) ) 540 { 541 case FT_CURVE_TAG_CONIC: 542 point->flags = AF_FLAG_CONIC; 543 break; 544 case FT_CURVE_TAG_CUBIC: 545 point->flags = AF_FLAG_CUBIC; 546 break; 547 default: 548 point->flags = 0; 549 } 550 551 point->prev = prev; 552 prev->next = point; 553 prev = point; 554 555 if ( point == end ) 556 { 557 if ( ++contour_index < outline->n_contours ) 558 { 559 end = points + outline->contours[contour_index]; 560 prev = end; 561 } 562 } 563 } 564 } 565 566 /* set-up the contours array */ 567 { 568 AF_Point* contour = hints->contours; 569 AF_Point* contour_limit = contour + hints->num_contours; 570 short* end = outline->contours; 571 short idx = 0; 572 573 574 for ( ; contour < contour_limit; contour++, end++ ) 575 { 576 contour[0] = points + idx; 577 idx = (short)( end[0] + 1 ); 578 } 579 } 580 581 /* compute directions of in & out vectors */ 582 { 583 AF_Point first = points; 584 AF_Point prev = NULL; 585 FT_Pos in_x = 0; 586 FT_Pos in_y = 0; 587 AF_Direction in_dir = AF_DIR_NONE; 588 589 590 for ( point = points; point < point_limit; point++ ) 591 { 592 AF_Point next; 593 FT_Pos out_x, out_y; 594 595 596 if ( point == first ) 597 { 598 prev = first->prev; 599 in_x = first->fx - prev->fx; 600 in_y = first->fy - prev->fy; 601 in_dir = af_direction_compute( in_x, in_y ); 602 first = prev + 1; 603 } 604 605 point->in_dir = (FT_Char)in_dir; 606 607 next = point->next; 608 out_x = next->fx - point->fx; 609 out_y = next->fy - point->fy; 610 611 in_dir = af_direction_compute( out_x, out_y ); 612 point->out_dir = (FT_Char)in_dir; 613 614 if ( point->flags & ( AF_FLAG_CONIC | AF_FLAG_CUBIC ) ) 615 { 616 Is_Weak_Point: 617 point->flags |= AF_FLAG_WEAK_INTERPOLATION; 618 } 619 else if ( point->out_dir == point->in_dir ) 620 { 621 if ( point->out_dir != AF_DIR_NONE ) 622 goto Is_Weak_Point; 623 624 if ( ft_corner_is_flat( in_x, in_y, out_x, out_y ) ) 625 goto Is_Weak_Point; 626 } 627 else if ( point->in_dir == -point->out_dir ) 628 goto Is_Weak_Point; 629 630 in_x = out_x; 631 in_y = out_y; 632 prev = point; 633 } 634 } 635 } 636 637 Exit: 638 return error; 639 } 640 641 642 FT_LOCAL_DEF( void ) af_glyph_hints_save(AF_GlyphHints hints,FT_Outline * outline)643 af_glyph_hints_save( AF_GlyphHints hints, 644 FT_Outline* outline ) 645 { 646 AF_Point point = hints->points; 647 AF_Point limit = point + hints->num_points; 648 FT_Vector* vec = outline->points; 649 char* tag = outline->tags; 650 651 652 for ( ; point < limit; point++, vec++, tag++ ) 653 { 654 vec->x = point->x; 655 vec->y = point->y; 656 657 if ( point->flags & AF_FLAG_CONIC ) 658 tag[0] = FT_CURVE_TAG_CONIC; 659 else if ( point->flags & AF_FLAG_CUBIC ) 660 tag[0] = FT_CURVE_TAG_CUBIC; 661 else 662 tag[0] = FT_CURVE_TAG_ON; 663 } 664 } 665 666 667 /**************************************************************** 668 * 669 * EDGE POINT GRID-FITTING 670 * 671 ****************************************************************/ 672 673 674 FT_LOCAL_DEF( void ) af_glyph_hints_align_edge_points(AF_GlyphHints hints,AF_Dimension dim)675 af_glyph_hints_align_edge_points( AF_GlyphHints hints, 676 AF_Dimension dim ) 677 { 678 AF_AxisHints axis = & hints->axis[dim]; 679 AF_Segment segments = axis->segments; 680 AF_Segment segment_limit = segments + axis->num_segments; 681 AF_Segment seg; 682 683 684 if ( dim == AF_DIMENSION_HORZ ) 685 { 686 for ( seg = segments; seg < segment_limit; seg++ ) 687 { 688 AF_Edge edge = seg->edge; 689 AF_Point point, first, last; 690 691 692 if ( edge == NULL ) 693 continue; 694 695 first = seg->first; 696 last = seg->last; 697 point = first; 698 for (;;) 699 { 700 point->x = edge->pos; 701 point->flags |= AF_FLAG_TOUCH_X; 702 703 if ( point == last ) 704 break; 705 706 point = point->next; 707 708 } 709 } 710 } 711 else 712 { 713 for ( seg = segments; seg < segment_limit; seg++ ) 714 { 715 AF_Edge edge = seg->edge; 716 AF_Point point, first, last; 717 718 719 if ( edge == NULL ) 720 continue; 721 722 first = seg->first; 723 last = seg->last; 724 point = first; 725 for (;;) 726 { 727 point->y = edge->pos; 728 point->flags |= AF_FLAG_TOUCH_Y; 729 730 if ( point == last ) 731 break; 732 733 point = point->next; 734 } 735 } 736 } 737 } 738 739 740 /**************************************************************** 741 * 742 * STRONG POINT INTERPOLATION 743 * 744 ****************************************************************/ 745 746 747 /* hint the strong points -- this is equivalent to the TrueType `IP' */ 748 /* hinting instruction */ 749 750 FT_LOCAL_DEF( void ) af_glyph_hints_align_strong_points(AF_GlyphHints hints,AF_Dimension dim)751 af_glyph_hints_align_strong_points( AF_GlyphHints hints, 752 AF_Dimension dim ) 753 { 754 AF_Point points = hints->points; 755 AF_Point point_limit = points + hints->num_points; 756 AF_AxisHints axis = &hints->axis[dim]; 757 AF_Edge edges = axis->edges; 758 AF_Edge edge_limit = edges + axis->num_edges; 759 AF_Flags touch_flag; 760 761 762 if ( dim == AF_DIMENSION_HORZ ) 763 touch_flag = AF_FLAG_TOUCH_X; 764 else 765 touch_flag = AF_FLAG_TOUCH_Y; 766 767 if ( edges < edge_limit ) 768 { 769 AF_Point point; 770 AF_Edge edge; 771 772 773 for ( point = points; point < point_limit; point++ ) 774 { 775 FT_Pos u, ou, fu; /* point position */ 776 FT_Pos delta; 777 778 779 if ( point->flags & touch_flag ) 780 continue; 781 782 /* if this point is candidate to weak interpolation, we */ 783 /* interpolate it after all strong points have been processed */ 784 785 if ( ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) && 786 !( point->flags & AF_FLAG_INFLECTION ) ) 787 continue; 788 789 if ( dim == AF_DIMENSION_VERT ) 790 { 791 u = point->fy; 792 ou = point->oy; 793 } 794 else 795 { 796 u = point->fx; 797 ou = point->ox; 798 } 799 800 fu = u; 801 802 /* is the point before the first edge? */ 803 edge = edges; 804 delta = edge->fpos - u; 805 if ( delta >= 0 ) 806 { 807 u = edge->pos - ( edge->opos - ou ); 808 goto Store_Point; 809 } 810 811 /* is the point after the last edge? */ 812 edge = edge_limit - 1; 813 delta = u - edge->fpos; 814 if ( delta >= 0 ) 815 { 816 u = edge->pos + ( ou - edge->opos ); 817 goto Store_Point; 818 } 819 820 { 821 FT_PtrDist min, max, mid; 822 FT_Pos fpos; 823 824 825 /* find enclosing edges */ 826 min = 0; 827 max = edge_limit - edges; 828 829 #if 1 830 /* for small edge counts, a linear search is better */ 831 if ( max <= 8 ) 832 { 833 FT_PtrDist nn; 834 835 for ( nn = 0; nn < max; nn++ ) 836 if ( edges[nn].fpos >= u ) 837 break; 838 839 if ( edges[nn].fpos == u ) 840 { 841 u = edges[nn].pos; 842 goto Store_Point; 843 } 844 min = nn; 845 } 846 else 847 #endif 848 while ( min < max ) 849 { 850 mid = ( max + min ) >> 1; 851 edge = edges + mid; 852 fpos = edge->fpos; 853 854 if ( u < fpos ) 855 max = mid; 856 else if ( u > fpos ) 857 min = mid + 1; 858 else 859 { 860 /* we are on the edge */ 861 u = edge->pos; 862 goto Store_Point; 863 } 864 } 865 866 { 867 AF_Edge before = edges + min - 1; 868 AF_Edge after = edges + min + 0; 869 870 871 /* assert( before && after && before != after ) */ 872 if ( before->scale == 0 ) 873 before->scale = FT_DivFix( after->pos - before->pos, 874 after->fpos - before->fpos ); 875 876 u = before->pos + FT_MulFix( fu - before->fpos, 877 before->scale ); 878 } 879 } 880 881 Store_Point: 882 /* save the point position */ 883 if ( dim == AF_DIMENSION_HORZ ) 884 point->x = u; 885 else 886 point->y = u; 887 888 point->flags |= touch_flag; 889 } 890 } 891 } 892 893 894 /**************************************************************** 895 * 896 * WEAK POINT INTERPOLATION 897 * 898 ****************************************************************/ 899 900 901 static void af_iup_shift(AF_Point p1,AF_Point p2,AF_Point ref)902 af_iup_shift( AF_Point p1, 903 AF_Point p2, 904 AF_Point ref ) 905 { 906 AF_Point p; 907 FT_Pos delta = ref->u - ref->v; 908 909 if ( delta == 0 ) 910 return; 911 912 for ( p = p1; p < ref; p++ ) 913 p->u = p->v + delta; 914 915 for ( p = ref + 1; p <= p2; p++ ) 916 p->u = p->v + delta; 917 } 918 919 920 static void af_iup_interp(AF_Point p1,AF_Point p2,AF_Point ref1,AF_Point ref2)921 af_iup_interp( AF_Point p1, 922 AF_Point p2, 923 AF_Point ref1, 924 AF_Point ref2 ) 925 { 926 AF_Point p; 927 FT_Pos u; 928 FT_Pos v1 = ref1->v; 929 FT_Pos v2 = ref2->v; 930 FT_Pos d1 = ref1->u - v1; 931 FT_Pos d2 = ref2->u - v2; 932 933 934 if ( p1 > p2 ) 935 return; 936 937 if ( v1 == v2 ) 938 { 939 for ( p = p1; p <= p2; p++ ) 940 { 941 u = p->v; 942 943 if ( u <= v1 ) 944 u += d1; 945 else 946 u += d2; 947 948 p->u = u; 949 } 950 return; 951 } 952 953 if ( v1 < v2 ) 954 { 955 for ( p = p1; p <= p2; p++ ) 956 { 957 u = p->v; 958 959 if ( u <= v1 ) 960 u += d1; 961 else if ( u >= v2 ) 962 u += d2; 963 else 964 u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 ); 965 966 p->u = u; 967 } 968 } 969 else 970 { 971 for ( p = p1; p <= p2; p++ ) 972 { 973 u = p->v; 974 975 if ( u <= v2 ) 976 u += d2; 977 else if ( u >= v1 ) 978 u += d1; 979 else 980 u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 ); 981 982 p->u = u; 983 } 984 } 985 } 986 987 988 FT_LOCAL_DEF( void ) af_glyph_hints_align_weak_points(AF_GlyphHints hints,AF_Dimension dim)989 af_glyph_hints_align_weak_points( AF_GlyphHints hints, 990 AF_Dimension dim ) 991 { 992 AF_Point points = hints->points; 993 AF_Point point_limit = points + hints->num_points; 994 AF_Point* contour = hints->contours; 995 AF_Point* contour_limit = contour + hints->num_contours; 996 AF_Flags touch_flag; 997 AF_Point point; 998 AF_Point end_point; 999 AF_Point first_point; 1000 1001 1002 /* PASS 1: Move segment points to edge positions */ 1003 1004 if ( dim == AF_DIMENSION_HORZ ) 1005 { 1006 touch_flag = AF_FLAG_TOUCH_X; 1007 1008 for ( point = points; point < point_limit; point++ ) 1009 { 1010 point->u = point->x; 1011 point->v = point->ox; 1012 } 1013 } 1014 else 1015 { 1016 touch_flag = AF_FLAG_TOUCH_Y; 1017 1018 for ( point = points; point < point_limit; point++ ) 1019 { 1020 point->u = point->y; 1021 point->v = point->oy; 1022 } 1023 } 1024 1025 point = points; 1026 1027 for ( ; contour < contour_limit; contour++ ) 1028 { 1029 AF_Point first_touched, last_touched; 1030 1031 1032 point = *contour; 1033 end_point = point->prev; 1034 first_point = point; 1035 1036 /* find first touched point */ 1037 for (;;) 1038 { 1039 if ( point > end_point ) /* no touched point in contour */ 1040 goto NextContour; 1041 1042 if ( point->flags & touch_flag ) 1043 break; 1044 1045 point++; 1046 } 1047 1048 first_touched = point; 1049 last_touched = point; 1050 1051 for (;;) 1052 { 1053 FT_ASSERT( point <= end_point && 1054 ( point->flags & touch_flag ) != 0 ); 1055 1056 /* skip any touched neighbhours */ 1057 while ( point < end_point && ( point[1].flags & touch_flag ) != 0 ) 1058 point++; 1059 1060 last_touched = point; 1061 1062 /* find the next touched point, if any */ 1063 point ++; 1064 for (;;) 1065 { 1066 if ( point > end_point ) 1067 goto EndContour; 1068 1069 if ( ( point->flags & touch_flag ) != 0 ) 1070 break; 1071 1072 point++; 1073 } 1074 1075 /* interpolate between last_touched and point */ 1076 af_iup_interp( last_touched + 1, point - 1, 1077 last_touched, point ); 1078 } 1079 1080 EndContour: 1081 /* special case: only one point was touched */ 1082 if ( last_touched == first_touched ) 1083 { 1084 af_iup_shift( first_point, end_point, first_touched ); 1085 } 1086 else /* interpolate the last part */ 1087 { 1088 if ( last_touched < end_point ) 1089 af_iup_interp( last_touched + 1, end_point, 1090 last_touched, first_touched ); 1091 1092 if ( first_touched > points ) 1093 af_iup_interp( first_point, first_touched - 1, 1094 last_touched, first_touched ); 1095 } 1096 1097 NextContour: 1098 ; 1099 } 1100 1101 /* now save the interpolated values back to x/y */ 1102 if ( dim == AF_DIMENSION_HORZ ) 1103 { 1104 for ( point = points; point < point_limit; point++ ) 1105 point->x = point->u; 1106 } 1107 else 1108 { 1109 for ( point = points; point < point_limit; point++ ) 1110 point->y = point->u; 1111 } 1112 } 1113 1114 1115 #ifdef AF_USE_WARPER 1116 1117 FT_LOCAL_DEF( void ) af_glyph_hints_scale_dim(AF_GlyphHints hints,AF_Dimension dim,FT_Fixed scale,FT_Pos delta)1118 af_glyph_hints_scale_dim( AF_GlyphHints hints, 1119 AF_Dimension dim, 1120 FT_Fixed scale, 1121 FT_Pos delta ) 1122 { 1123 AF_Point points = hints->points; 1124 AF_Point points_limit = points + hints->num_points; 1125 AF_Point point; 1126 1127 1128 if ( dim == AF_DIMENSION_HORZ ) 1129 { 1130 for ( point = points; point < points_limit; point++ ) 1131 point->x = FT_MulFix( point->fx, scale ) + delta; 1132 } 1133 else 1134 { 1135 for ( point = points; point < points_limit; point++ ) 1136 point->y = FT_MulFix( point->fy, scale ) + delta; 1137 } 1138 } 1139 1140 #endif /* AF_USE_WARPER */ 1141 1142 /* END */ 1143