1 /***************************************************************************/ 2 /* */ 3 /* afhints.c */ 4 /* */ 5 /* Auto-fitter hinting routines (body). */ 6 /* */ 7 /* Copyright 2003-2017 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 #include FT_INTERNAL_DEBUG_H 23 24 25 /*************************************************************************/ 26 /* */ 27 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 28 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 29 /* messages during execution. */ 30 /* */ 31 #undef FT_COMPONENT 32 #define FT_COMPONENT trace_afhints 33 34 35 /* Get new segment for given axis. */ 36 37 FT_LOCAL_DEF( FT_Error ) af_axis_hints_new_segment(AF_AxisHints axis,FT_Memory memory,AF_Segment * asegment)38 af_axis_hints_new_segment( AF_AxisHints axis, 39 FT_Memory memory, 40 AF_Segment *asegment ) 41 { 42 FT_Error error = FT_Err_Ok; 43 AF_Segment segment = NULL; 44 45 46 if ( axis->num_segments < AF_SEGMENTS_EMBEDDED ) 47 { 48 if ( !axis->segments ) 49 { 50 axis->segments = axis->embedded.segments; 51 axis->max_segments = AF_SEGMENTS_EMBEDDED; 52 } 53 } 54 else if ( axis->num_segments >= axis->max_segments ) 55 { 56 FT_Int old_max = axis->max_segments; 57 FT_Int new_max = old_max; 58 FT_Int big_max = (FT_Int)( FT_INT_MAX / sizeof ( *segment ) ); 59 60 61 if ( old_max >= big_max ) 62 { 63 error = FT_THROW( Out_Of_Memory ); 64 goto Exit; 65 } 66 67 new_max += ( new_max >> 2 ) + 4; 68 if ( new_max < old_max || new_max > big_max ) 69 new_max = big_max; 70 71 if ( axis->segments == axis->embedded.segments ) 72 { 73 if ( FT_NEW_ARRAY( axis->segments, new_max ) ) 74 goto Exit; 75 ft_memcpy( axis->segments, axis->embedded.segments, 76 sizeof ( axis->embedded.segments ) ); 77 } 78 else 79 { 80 if ( FT_RENEW_ARRAY( axis->segments, old_max, new_max ) ) 81 goto Exit; 82 } 83 84 axis->max_segments = new_max; 85 } 86 87 segment = axis->segments + axis->num_segments++; 88 89 Exit: 90 *asegment = segment; 91 return error; 92 } 93 94 95 /* Get new edge for given axis, direction, and position, */ 96 /* without initializing the edge itself. */ 97 98 FT_LOCAL( FT_Error ) af_axis_hints_new_edge(AF_AxisHints axis,FT_Int fpos,AF_Direction dir,FT_Bool top_to_bottom_hinting,FT_Memory memory,AF_Edge * anedge)99 af_axis_hints_new_edge( AF_AxisHints axis, 100 FT_Int fpos, 101 AF_Direction dir, 102 FT_Bool top_to_bottom_hinting, 103 FT_Memory memory, 104 AF_Edge *anedge ) 105 { 106 FT_Error error = FT_Err_Ok; 107 AF_Edge edge = NULL; 108 AF_Edge edges; 109 110 111 if ( axis->num_edges < AF_EDGES_EMBEDDED ) 112 { 113 if ( !axis->edges ) 114 { 115 axis->edges = axis->embedded.edges; 116 axis->max_edges = AF_EDGES_EMBEDDED; 117 } 118 } 119 else if ( axis->num_edges >= axis->max_edges ) 120 { 121 FT_Int old_max = axis->max_edges; 122 FT_Int new_max = old_max; 123 FT_Int big_max = (FT_Int)( FT_INT_MAX / sizeof ( *edge ) ); 124 125 126 if ( old_max >= big_max ) 127 { 128 error = FT_THROW( Out_Of_Memory ); 129 goto Exit; 130 } 131 132 new_max += ( new_max >> 2 ) + 4; 133 if ( new_max < old_max || new_max > big_max ) 134 new_max = big_max; 135 136 if ( axis->edges == axis->embedded.edges ) 137 { 138 if ( FT_NEW_ARRAY( axis->edges, new_max ) ) 139 goto Exit; 140 ft_memcpy( axis->edges, axis->embedded.edges, 141 sizeof ( axis->embedded.edges ) ); 142 } 143 else 144 { 145 if ( FT_RENEW_ARRAY( axis->edges, old_max, new_max ) ) 146 goto Exit; 147 } 148 149 axis->max_edges = new_max; 150 } 151 152 edges = axis->edges; 153 edge = edges + axis->num_edges; 154 155 while ( edge > edges ) 156 { 157 if ( top_to_bottom_hinting ? ( edge[-1].fpos > fpos ) 158 : ( edge[-1].fpos < fpos ) ) 159 break; 160 161 /* we want the edge with same position and minor direction */ 162 /* to appear before those in the major one in the list */ 163 if ( edge[-1].fpos == fpos && dir == axis->major_dir ) 164 break; 165 166 edge[0] = edge[-1]; 167 edge--; 168 } 169 170 axis->num_edges++; 171 172 Exit: 173 *anedge = edge; 174 return error; 175 } 176 177 178 #ifdef FT_DEBUG_AUTOFIT 179 180 #include FT_CONFIG_STANDARD_LIBRARY_H 181 182 /* The dump functions are used in the `ftgrid' demo program, too. */ 183 #define AF_DUMP( varformat ) \ 184 do \ 185 { \ 186 if ( to_stdout ) \ 187 printf varformat; \ 188 else \ 189 FT_TRACE7( varformat ); \ 190 } while ( 0 ) 191 192 193 static const char* af_dir_str(AF_Direction dir)194 af_dir_str( AF_Direction dir ) 195 { 196 const char* result; 197 198 199 switch ( dir ) 200 { 201 case AF_DIR_UP: 202 result = "up"; 203 break; 204 case AF_DIR_DOWN: 205 result = "down"; 206 break; 207 case AF_DIR_LEFT: 208 result = "left"; 209 break; 210 case AF_DIR_RIGHT: 211 result = "right"; 212 break; 213 default: 214 result = "none"; 215 } 216 217 return result; 218 } 219 220 221 #define AF_INDEX_NUM( ptr, base ) (int)( (ptr) ? ( (ptr) - (base) ) : -1 ) 222 223 224 static char* af_print_idx(char * p,int idx)225 af_print_idx( char* p, 226 int idx ) 227 { 228 if ( idx == -1 ) 229 { 230 p[0] = '-'; 231 p[1] = '-'; 232 p[2] = '\0'; 233 } 234 else 235 ft_sprintf( p, "%d", idx ); 236 237 return p; 238 } 239 240 241 static int af_get_segment_index(AF_GlyphHints hints,int point_idx,int dimension)242 af_get_segment_index( AF_GlyphHints hints, 243 int point_idx, 244 int dimension ) 245 { 246 AF_AxisHints axis = &hints->axis[dimension]; 247 AF_Point point = hints->points + point_idx; 248 AF_Segment segments = axis->segments; 249 AF_Segment limit = segments + axis->num_segments; 250 AF_Segment segment; 251 252 253 for ( segment = segments; segment < limit; segment++ ) 254 { 255 if ( segment->first <= segment->last ) 256 { 257 if ( point >= segment->first && point <= segment->last ) 258 break; 259 } 260 else 261 { 262 AF_Point p = segment->first; 263 264 265 for (;;) 266 { 267 if ( point == p ) 268 goto Exit; 269 270 if ( p == segment->last ) 271 break; 272 273 p = p->next; 274 } 275 } 276 } 277 278 Exit: 279 if ( segment == limit ) 280 return -1; 281 282 return (int)( segment - segments ); 283 } 284 285 286 static int af_get_edge_index(AF_GlyphHints hints,int segment_idx,int dimension)287 af_get_edge_index( AF_GlyphHints hints, 288 int segment_idx, 289 int dimension ) 290 { 291 AF_AxisHints axis = &hints->axis[dimension]; 292 AF_Edge edges = axis->edges; 293 AF_Segment segment = axis->segments + segment_idx; 294 295 296 return segment_idx == -1 ? -1 : AF_INDEX_NUM( segment->edge, edges ); 297 } 298 299 300 #ifdef __cplusplus 301 extern "C" { 302 #endif 303 void af_glyph_hints_dump_points(AF_GlyphHints hints,FT_Bool to_stdout)304 af_glyph_hints_dump_points( AF_GlyphHints hints, 305 FT_Bool to_stdout ) 306 { 307 AF_Point points = hints->points; 308 AF_Point limit = points + hints->num_points; 309 AF_Point* contour = hints->contours; 310 AF_Point* climit = contour + hints->num_contours; 311 AF_Point point; 312 313 314 AF_DUMP(( "Table of points:\n" )); 315 316 if ( hints->num_points ) 317 AF_DUMP(( " index hedge hseg vedge vseg flags " 318 " xorg yorg xscale yscale xfit yfit" )); 319 else 320 AF_DUMP(( " (none)\n" )); 321 322 for ( point = points; point < limit; point++ ) 323 { 324 int point_idx = AF_INDEX_NUM( point, points ); 325 int segment_idx_0 = af_get_segment_index( hints, point_idx, 0 ); 326 int segment_idx_1 = af_get_segment_index( hints, point_idx, 1 ); 327 328 char buf1[16], buf2[16], buf3[16], buf4[16]; 329 330 331 /* insert extra newline at the beginning of a contour */ 332 if ( contour < climit && *contour == point ) 333 { 334 AF_DUMP(( "\n" )); 335 contour++; 336 } 337 338 AF_DUMP(( " %5d %5s %5s %5s %5s %s" 339 " %5d %5d %7.2f %7.2f %7.2f %7.2f\n", 340 point_idx, 341 af_print_idx( buf1, 342 af_get_edge_index( hints, segment_idx_1, 1 ) ), 343 af_print_idx( buf2, segment_idx_1 ), 344 af_print_idx( buf3, 345 af_get_edge_index( hints, segment_idx_0, 0 ) ), 346 af_print_idx( buf4, segment_idx_0 ), 347 ( point->flags & AF_FLAG_NEAR ) 348 ? " near " 349 : ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) 350 ? " weak " 351 : "strong", 352 353 point->fx, 354 point->fy, 355 point->ox / 64.0, 356 point->oy / 64.0, 357 point->x / 64.0, 358 point->y / 64.0 )); 359 } 360 AF_DUMP(( "\n" )); 361 } 362 #ifdef __cplusplus 363 } 364 #endif 365 366 367 static const char* af_edge_flags_to_string(FT_UInt flags)368 af_edge_flags_to_string( FT_UInt flags ) 369 { 370 static char temp[32]; 371 int pos = 0; 372 373 374 if ( flags & AF_EDGE_ROUND ) 375 { 376 ft_memcpy( temp + pos, "round", 5 ); 377 pos += 5; 378 } 379 if ( flags & AF_EDGE_SERIF ) 380 { 381 if ( pos > 0 ) 382 temp[pos++] = ' '; 383 ft_memcpy( temp + pos, "serif", 5 ); 384 pos += 5; 385 } 386 if ( pos == 0 ) 387 return "normal"; 388 389 temp[pos] = '\0'; 390 391 return temp; 392 } 393 394 395 /* Dump the array of linked segments. */ 396 397 #ifdef __cplusplus 398 extern "C" { 399 #endif 400 void af_glyph_hints_dump_segments(AF_GlyphHints hints,FT_Bool to_stdout)401 af_glyph_hints_dump_segments( AF_GlyphHints hints, 402 FT_Bool to_stdout ) 403 { 404 FT_Int dimension; 405 406 407 for ( dimension = 1; dimension >= 0; dimension-- ) 408 { 409 AF_AxisHints axis = &hints->axis[dimension]; 410 AF_Point points = hints->points; 411 AF_Edge edges = axis->edges; 412 AF_Segment segments = axis->segments; 413 AF_Segment limit = segments + axis->num_segments; 414 AF_Segment seg; 415 416 char buf1[16], buf2[16], buf3[16]; 417 418 419 AF_DUMP(( "Table of %s segments:\n", 420 dimension == AF_DIMENSION_HORZ ? "vertical" 421 : "horizontal" )); 422 if ( axis->num_segments ) 423 AF_DUMP(( " index pos delta dir from to " 424 " link serif edge" 425 " height extra flags\n" )); 426 else 427 AF_DUMP(( " (none)\n" )); 428 429 for ( seg = segments; seg < limit; seg++ ) 430 AF_DUMP(( " %5d %5d %5d %5s %4d %4d" 431 " %4s %5s %4s" 432 " %6d %5d %11s\n", 433 AF_INDEX_NUM( seg, segments ), 434 seg->pos, 435 seg->delta, 436 af_dir_str( (AF_Direction)seg->dir ), 437 AF_INDEX_NUM( seg->first, points ), 438 AF_INDEX_NUM( seg->last, points ), 439 440 af_print_idx( buf1, AF_INDEX_NUM( seg->link, segments ) ), 441 af_print_idx( buf2, AF_INDEX_NUM( seg->serif, segments ) ), 442 af_print_idx( buf3, AF_INDEX_NUM( seg->edge, edges ) ), 443 444 seg->height, 445 seg->height - ( seg->max_coord - seg->min_coord ), 446 af_edge_flags_to_string( seg->flags ) )); 447 AF_DUMP(( "\n" )); 448 } 449 } 450 #ifdef __cplusplus 451 } 452 #endif 453 454 455 /* Fetch number of segments. */ 456 457 #ifdef __cplusplus 458 extern "C" { 459 #endif 460 FT_Error af_glyph_hints_get_num_segments(AF_GlyphHints hints,FT_Int dimension,FT_Int * num_segments)461 af_glyph_hints_get_num_segments( AF_GlyphHints hints, 462 FT_Int dimension, 463 FT_Int* num_segments ) 464 { 465 AF_Dimension dim; 466 AF_AxisHints axis; 467 468 469 dim = ( dimension == 0 ) ? AF_DIMENSION_HORZ : AF_DIMENSION_VERT; 470 471 axis = &hints->axis[dim]; 472 *num_segments = axis->num_segments; 473 474 return FT_Err_Ok; 475 } 476 #ifdef __cplusplus 477 } 478 #endif 479 480 481 /* Fetch offset of segments into user supplied offset array. */ 482 483 #ifdef __cplusplus 484 extern "C" { 485 #endif 486 FT_Error af_glyph_hints_get_segment_offset(AF_GlyphHints hints,FT_Int dimension,FT_Int idx,FT_Pos * offset,FT_Bool * is_blue,FT_Pos * blue_offset)487 af_glyph_hints_get_segment_offset( AF_GlyphHints hints, 488 FT_Int dimension, 489 FT_Int idx, 490 FT_Pos *offset, 491 FT_Bool *is_blue, 492 FT_Pos *blue_offset ) 493 { 494 AF_Dimension dim; 495 AF_AxisHints axis; 496 AF_Segment seg; 497 498 499 if ( !offset ) 500 return FT_THROW( Invalid_Argument ); 501 502 dim = ( dimension == 0 ) ? AF_DIMENSION_HORZ : AF_DIMENSION_VERT; 503 504 axis = &hints->axis[dim]; 505 506 if ( idx < 0 || idx >= axis->num_segments ) 507 return FT_THROW( Invalid_Argument ); 508 509 seg = &axis->segments[idx]; 510 *offset = ( dim == AF_DIMENSION_HORZ ) ? seg->first->ox 511 : seg->first->oy; 512 if ( seg->edge ) 513 *is_blue = (FT_Bool)( seg->edge->blue_edge != 0 ); 514 else 515 *is_blue = FALSE; 516 517 if ( *is_blue ) 518 *blue_offset = seg->edge->blue_edge->cur; 519 else 520 *blue_offset = 0; 521 522 return FT_Err_Ok; 523 } 524 #ifdef __cplusplus 525 } 526 #endif 527 528 529 /* Dump the array of linked edges. */ 530 531 #ifdef __cplusplus 532 extern "C" { 533 #endif 534 void af_glyph_hints_dump_edges(AF_GlyphHints hints,FT_Bool to_stdout)535 af_glyph_hints_dump_edges( AF_GlyphHints hints, 536 FT_Bool to_stdout ) 537 { 538 FT_Int dimension; 539 540 541 for ( dimension = 1; dimension >= 0; dimension-- ) 542 { 543 AF_AxisHints axis = &hints->axis[dimension]; 544 AF_Edge edges = axis->edges; 545 AF_Edge limit = edges + axis->num_edges; 546 AF_Edge edge; 547 548 char buf1[16], buf2[16]; 549 550 551 /* 552 * note: AF_DIMENSION_HORZ corresponds to _vertical_ edges 553 * since they have a constant X coordinate. 554 */ 555 if ( dimension == AF_DIMENSION_HORZ ) 556 AF_DUMP(( "Table of %s edges (1px=%.2fu, 10u=%.2fpx):\n", 557 "vertical", 558 65536.0 * 64.0 / hints->x_scale, 559 10.0 * hints->x_scale / 65536.0 / 64.0 )); 560 else 561 AF_DUMP(( "Table of %s edges (1px=%.2fu, 10u=%.2fpx):\n", 562 "horizontal", 563 65536.0 * 64.0 / hints->y_scale, 564 10.0 * hints->y_scale / 65536.0 / 64.0 )); 565 566 if ( axis->num_edges ) 567 AF_DUMP(( " index pos dir link serif" 568 " blue opos pos flags\n" )); 569 else 570 AF_DUMP(( " (none)\n" )); 571 572 for ( edge = edges; edge < limit; edge++ ) 573 AF_DUMP(( " %5d %7.2f %5s %4s %5s" 574 " %c %7.2f %7.2f %11s\n", 575 AF_INDEX_NUM( edge, edges ), 576 (int)edge->opos / 64.0, 577 af_dir_str( (AF_Direction)edge->dir ), 578 af_print_idx( buf1, AF_INDEX_NUM( edge->link, edges ) ), 579 af_print_idx( buf2, AF_INDEX_NUM( edge->serif, edges ) ), 580 581 edge->blue_edge ? 'y' : 'n', 582 edge->opos / 64.0, 583 edge->pos / 64.0, 584 af_edge_flags_to_string( edge->flags ) )); 585 AF_DUMP(( "\n" )); 586 } 587 } 588 #ifdef __cplusplus 589 } 590 #endif 591 592 #undef AF_DUMP 593 594 #endif /* !FT_DEBUG_AUTOFIT */ 595 596 597 /* Compute the direction value of a given vector. */ 598 599 FT_LOCAL_DEF( AF_Direction ) af_direction_compute(FT_Pos dx,FT_Pos dy)600 af_direction_compute( FT_Pos dx, 601 FT_Pos dy ) 602 { 603 FT_Pos ll, ss; /* long and short arm lengths */ 604 AF_Direction dir; /* candidate direction */ 605 606 607 if ( dy >= dx ) 608 { 609 if ( dy >= -dx ) 610 { 611 dir = AF_DIR_UP; 612 ll = dy; 613 ss = dx; 614 } 615 else 616 { 617 dir = AF_DIR_LEFT; 618 ll = -dx; 619 ss = dy; 620 } 621 } 622 else /* dy < dx */ 623 { 624 if ( dy >= -dx ) 625 { 626 dir = AF_DIR_RIGHT; 627 ll = dx; 628 ss = dy; 629 } 630 else 631 { 632 dir = AF_DIR_DOWN; 633 ll = -dy; 634 ss = dx; 635 } 636 } 637 638 /* return no direction if arm lengths do not differ enough */ 639 /* (value 14 is heuristic, corresponding to approx. 4.1 degrees) */ 640 /* the long arm is never negative */ 641 if ( ll <= 14 * FT_ABS( ss ) ) 642 dir = AF_DIR_NONE; 643 644 return dir; 645 } 646 647 648 FT_LOCAL_DEF( void ) af_glyph_hints_init(AF_GlyphHints hints,FT_Memory memory)649 af_glyph_hints_init( AF_GlyphHints hints, 650 FT_Memory memory ) 651 { 652 /* no need to initialize the embedded items */ 653 FT_MEM_ZERO( hints, sizeof ( *hints ) - sizeof ( hints->embedded ) ); 654 hints->memory = memory; 655 } 656 657 658 FT_LOCAL_DEF( void ) af_glyph_hints_done(AF_GlyphHints hints)659 af_glyph_hints_done( AF_GlyphHints hints ) 660 { 661 FT_Memory memory; 662 int dim; 663 664 665 if ( !( hints && hints->memory ) ) 666 return; 667 668 memory = hints->memory; 669 670 /* 671 * note that we don't need to free the segment and edge 672 * buffers since they are really within the hints->points array 673 */ 674 for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) 675 { 676 AF_AxisHints axis = &hints->axis[dim]; 677 678 679 axis->num_segments = 0; 680 axis->max_segments = 0; 681 if ( axis->segments != axis->embedded.segments ) 682 FT_FREE( axis->segments ); 683 684 axis->num_edges = 0; 685 axis->max_edges = 0; 686 if ( axis->edges != axis->embedded.edges ) 687 FT_FREE( axis->edges ); 688 } 689 690 if ( hints->contours != hints->embedded.contours ) 691 FT_FREE( hints->contours ); 692 hints->max_contours = 0; 693 hints->num_contours = 0; 694 695 if ( hints->points != hints->embedded.points ) 696 FT_FREE( hints->points ); 697 hints->max_points = 0; 698 hints->num_points = 0; 699 700 hints->memory = NULL; 701 } 702 703 704 /* Reset metrics. */ 705 706 FT_LOCAL_DEF( void ) af_glyph_hints_rescale(AF_GlyphHints hints,AF_StyleMetrics metrics)707 af_glyph_hints_rescale( AF_GlyphHints hints, 708 AF_StyleMetrics metrics ) 709 { 710 hints->metrics = metrics; 711 hints->scaler_flags = metrics->scaler.flags; 712 } 713 714 715 /* Recompute all AF_Point in AF_GlyphHints from the definitions */ 716 /* in a source outline. */ 717 718 FT_LOCAL_DEF( FT_Error ) af_glyph_hints_reload(AF_GlyphHints hints,FT_Outline * outline)719 af_glyph_hints_reload( AF_GlyphHints hints, 720 FT_Outline* outline ) 721 { 722 FT_Error error = FT_Err_Ok; 723 AF_Point points; 724 FT_UInt old_max, new_max; 725 FT_Fixed x_scale = hints->x_scale; 726 FT_Fixed y_scale = hints->y_scale; 727 FT_Pos x_delta = hints->x_delta; 728 FT_Pos y_delta = hints->y_delta; 729 FT_Memory memory = hints->memory; 730 731 732 hints->num_points = 0; 733 hints->num_contours = 0; 734 735 hints->axis[0].num_segments = 0; 736 hints->axis[0].num_edges = 0; 737 hints->axis[1].num_segments = 0; 738 hints->axis[1].num_edges = 0; 739 740 /* first of all, reallocate the contours array if necessary */ 741 new_max = (FT_UInt)outline->n_contours; 742 old_max = (FT_UInt)hints->max_contours; 743 744 if ( new_max <= AF_CONTOURS_EMBEDDED ) 745 { 746 if ( !hints->contours ) 747 { 748 hints->contours = hints->embedded.contours; 749 hints->max_contours = AF_CONTOURS_EMBEDDED; 750 } 751 } 752 else if ( new_max > old_max ) 753 { 754 if ( hints->contours == hints->embedded.contours ) 755 hints->contours = NULL; 756 757 new_max = ( new_max + 3 ) & ~3U; /* round up to a multiple of 4 */ 758 759 if ( FT_RENEW_ARRAY( hints->contours, old_max, new_max ) ) 760 goto Exit; 761 762 hints->max_contours = (FT_Int)new_max; 763 } 764 765 /* 766 * then reallocate the points arrays if necessary -- 767 * note that we reserve two additional point positions, used to 768 * hint metrics appropriately 769 */ 770 new_max = (FT_UInt)( outline->n_points + 2 ); 771 old_max = (FT_UInt)hints->max_points; 772 773 if ( new_max <= AF_POINTS_EMBEDDED ) 774 { 775 if ( !hints->points ) 776 { 777 hints->points = hints->embedded.points; 778 hints->max_points = AF_POINTS_EMBEDDED; 779 } 780 } 781 else if ( new_max > old_max ) 782 { 783 if ( hints->points == hints->embedded.points ) 784 hints->points = NULL; 785 786 new_max = ( new_max + 2 + 7 ) & ~7U; /* round up to a multiple of 8 */ 787 788 if ( FT_RENEW_ARRAY( hints->points, old_max, new_max ) ) 789 goto Exit; 790 791 hints->max_points = (FT_Int)new_max; 792 } 793 794 hints->num_points = outline->n_points; 795 hints->num_contours = outline->n_contours; 796 797 /* We can't rely on the value of `FT_Outline.flags' to know the fill */ 798 /* direction used for a glyph, given that some fonts are broken (e.g., */ 799 /* the Arphic ones). We thus recompute it each time we need to. */ 800 /* */ 801 hints->axis[AF_DIMENSION_HORZ].major_dir = AF_DIR_UP; 802 hints->axis[AF_DIMENSION_VERT].major_dir = AF_DIR_LEFT; 803 804 if ( FT_Outline_Get_Orientation( outline ) == FT_ORIENTATION_POSTSCRIPT ) 805 { 806 hints->axis[AF_DIMENSION_HORZ].major_dir = AF_DIR_DOWN; 807 hints->axis[AF_DIMENSION_VERT].major_dir = AF_DIR_RIGHT; 808 } 809 810 hints->x_scale = x_scale; 811 hints->y_scale = y_scale; 812 hints->x_delta = x_delta; 813 hints->y_delta = y_delta; 814 815 hints->xmin_delta = 0; 816 hints->xmax_delta = 0; 817 818 points = hints->points; 819 if ( hints->num_points == 0 ) 820 goto Exit; 821 822 { 823 AF_Point point; 824 AF_Point point_limit = points + hints->num_points; 825 826 /* value 20 in `near_limit' is heuristic */ 827 FT_UInt units_per_em = hints->metrics->scaler.face->units_per_EM; 828 FT_Int near_limit = 20 * units_per_em / 2048; 829 830 831 /* compute coordinates & Bezier flags, next and prev */ 832 { 833 FT_Vector* vec = outline->points; 834 char* tag = outline->tags; 835 FT_Short endpoint = outline->contours[0]; 836 AF_Point end = points + endpoint; 837 AF_Point prev = end; 838 FT_Int contour_index = 0; 839 840 841 for ( point = points; point < point_limit; point++, vec++, tag++ ) 842 { 843 FT_Pos out_x, out_y; 844 845 846 point->in_dir = (FT_Char)AF_DIR_NONE; 847 point->out_dir = (FT_Char)AF_DIR_NONE; 848 849 point->fx = (FT_Short)vec->x; 850 point->fy = (FT_Short)vec->y; 851 point->ox = point->x = FT_MulFix( vec->x, x_scale ) + x_delta; 852 point->oy = point->y = FT_MulFix( vec->y, y_scale ) + y_delta; 853 854 end->fx = (FT_Short)outline->points[endpoint].x; 855 end->fy = (FT_Short)outline->points[endpoint].y; 856 857 switch ( FT_CURVE_TAG( *tag ) ) 858 { 859 case FT_CURVE_TAG_CONIC: 860 point->flags = AF_FLAG_CONIC; 861 break; 862 case FT_CURVE_TAG_CUBIC: 863 point->flags = AF_FLAG_CUBIC; 864 break; 865 default: 866 point->flags = AF_FLAG_NONE; 867 } 868 869 out_x = point->fx - prev->fx; 870 out_y = point->fy - prev->fy; 871 872 if ( FT_ABS( out_x ) + FT_ABS( out_y ) < near_limit ) 873 prev->flags |= AF_FLAG_NEAR; 874 875 point->prev = prev; 876 prev->next = point; 877 prev = point; 878 879 if ( point == end ) 880 { 881 if ( ++contour_index < outline->n_contours ) 882 { 883 endpoint = outline->contours[contour_index]; 884 end = points + endpoint; 885 prev = end; 886 } 887 } 888 } 889 } 890 891 /* set up the contours array */ 892 { 893 AF_Point* contour = hints->contours; 894 AF_Point* contour_limit = contour + hints->num_contours; 895 short* end = outline->contours; 896 short idx = 0; 897 898 899 for ( ; contour < contour_limit; contour++, end++ ) 900 { 901 contour[0] = points + idx; 902 idx = (short)( end[0] + 1 ); 903 } 904 } 905 906 { 907 /* 908 * Compute directions of `in' and `out' vectors. 909 * 910 * Note that distances between points that are very near to each 911 * other are accumulated. In other words, the auto-hinter either 912 * prepends the small vectors between near points to the first 913 * non-near vector, or the sum of small vector lengths exceeds a 914 * threshold, thus `grouping' the small vectors. All intermediate 915 * points are tagged as weak; the directions are adjusted also to 916 * be equal to the accumulated one. 917 */ 918 919 FT_Int near_limit2 = 2 * near_limit - 1; 920 921 AF_Point* contour; 922 AF_Point* contour_limit = hints->contours + hints->num_contours; 923 924 925 for ( contour = hints->contours; contour < contour_limit; contour++ ) 926 { 927 AF_Point first = *contour; 928 AF_Point next, prev, curr; 929 930 FT_Pos out_x, out_y; 931 932 933 /* since the first point of a contour could be part of a */ 934 /* series of near points, go backwards to find the first */ 935 /* non-near point and adjust `first' */ 936 937 point = first; 938 prev = first->prev; 939 940 while ( prev != first ) 941 { 942 out_x = point->fx - prev->fx; 943 out_y = point->fy - prev->fy; 944 945 /* 946 * We use Taxicab metrics to measure the vector length. 947 * 948 * Note that the accumulated distances so far could have the 949 * opposite direction of the distance measured here. For this 950 * reason we use `near_limit2' for the comparison to get a 951 * non-near point even in the worst case. 952 */ 953 if ( FT_ABS( out_x ) + FT_ABS( out_y ) >= near_limit2 ) 954 break; 955 956 point = prev; 957 prev = prev->prev; 958 } 959 960 /* adjust first point */ 961 first = point; 962 963 /* now loop over all points of the contour to get */ 964 /* `in' and `out' vector directions */ 965 966 curr = first; 967 968 /* 969 * We abuse the `u' and `v' fields to store index deltas to the 970 * next and previous non-near point, respectively. 971 * 972 * To avoid problems with not having non-near points, we point to 973 * `first' by default as the next non-near point. 974 * 975 */ 976 curr->u = (FT_Pos)( first - curr ); 977 first->v = -curr->u; 978 979 out_x = 0; 980 out_y = 0; 981 982 next = first; 983 do 984 { 985 AF_Direction out_dir; 986 987 988 point = next; 989 next = point->next; 990 991 out_x += next->fx - point->fx; 992 out_y += next->fy - point->fy; 993 994 if ( FT_ABS( out_x ) + FT_ABS( out_y ) < near_limit ) 995 { 996 next->flags |= AF_FLAG_WEAK_INTERPOLATION; 997 continue; 998 } 999 1000 curr->u = (FT_Pos)( next - curr ); 1001 next->v = -curr->u; 1002 1003 out_dir = af_direction_compute( out_x, out_y ); 1004 1005 /* adjust directions for all points inbetween; */ 1006 /* the loop also updates position of `curr' */ 1007 curr->out_dir = (FT_Char)out_dir; 1008 for ( curr = curr->next; curr != next; curr = curr->next ) 1009 { 1010 curr->in_dir = (FT_Char)out_dir; 1011 curr->out_dir = (FT_Char)out_dir; 1012 } 1013 next->in_dir = (FT_Char)out_dir; 1014 1015 curr->u = (FT_Pos)( first - curr ); 1016 first->v = -curr->u; 1017 1018 out_x = 0; 1019 out_y = 0; 1020 1021 } while ( next != first ); 1022 } 1023 1024 /* 1025 * The next step is to `simplify' an outline's topology so that we 1026 * can identify local extrema more reliably: A series of 1027 * non-horizontal or non-vertical vectors pointing into the same 1028 * quadrant are handled as a single, long vector. From a 1029 * topological point of the view, the intermediate points are of no 1030 * interest and thus tagged as weak. 1031 */ 1032 1033 for ( point = points; point < point_limit; point++ ) 1034 { 1035 if ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) 1036 continue; 1037 1038 if ( point->in_dir == AF_DIR_NONE && 1039 point->out_dir == AF_DIR_NONE ) 1040 { 1041 /* check whether both vectors point into the same quadrant */ 1042 1043 FT_Pos in_x, in_y; 1044 FT_Pos out_x, out_y; 1045 1046 AF_Point next_u = point + point->u; 1047 AF_Point prev_v = point + point->v; 1048 1049 1050 in_x = point->fx - prev_v->fx; 1051 in_y = point->fy - prev_v->fy; 1052 1053 out_x = next_u->fx - point->fx; 1054 out_y = next_u->fy - point->fy; 1055 1056 if ( ( in_x ^ out_x ) >= 0 && ( in_y ^ out_y ) >= 0 ) 1057 { 1058 /* yes, so tag current point as weak */ 1059 /* and update index deltas */ 1060 1061 point->flags |= AF_FLAG_WEAK_INTERPOLATION; 1062 1063 prev_v->u = (FT_Pos)( next_u - prev_v ); 1064 next_u->v = -prev_v->u; 1065 } 1066 } 1067 } 1068 1069 /* 1070 * Finally, check for remaining weak points. Everything else not 1071 * collected in edges so far is then implicitly classified as strong 1072 * points. 1073 */ 1074 1075 for ( point = points; point < point_limit; point++ ) 1076 { 1077 if ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) 1078 continue; 1079 1080 if ( point->flags & AF_FLAG_CONTROL ) 1081 { 1082 /* control points are always weak */ 1083 Is_Weak_Point: 1084 point->flags |= AF_FLAG_WEAK_INTERPOLATION; 1085 } 1086 else if ( point->out_dir == point->in_dir ) 1087 { 1088 if ( point->out_dir != AF_DIR_NONE ) 1089 { 1090 /* current point lies on a horizontal or */ 1091 /* vertical segment (but doesn't start or end it) */ 1092 goto Is_Weak_Point; 1093 } 1094 1095 { 1096 AF_Point next_u = point + point->u; 1097 AF_Point prev_v = point + point->v; 1098 1099 1100 if ( ft_corner_is_flat( point->fx - prev_v->fx, 1101 point->fy - prev_v->fy, 1102 next_u->fx - point->fx, 1103 next_u->fy - point->fy ) ) 1104 { 1105 /* either the `in' or the `out' vector is much more */ 1106 /* dominant than the other one, so tag current point */ 1107 /* as weak and update index deltas */ 1108 1109 prev_v->u = (FT_Pos)( next_u - prev_v ); 1110 next_u->v = -prev_v->u; 1111 1112 goto Is_Weak_Point; 1113 } 1114 } 1115 } 1116 else if ( point->in_dir == -point->out_dir ) 1117 { 1118 /* current point forms a spike */ 1119 goto Is_Weak_Point; 1120 } 1121 } 1122 } 1123 } 1124 1125 Exit: 1126 return error; 1127 } 1128 1129 1130 /* Store the hinted outline in an FT_Outline structure. */ 1131 1132 FT_LOCAL_DEF( void ) af_glyph_hints_save(AF_GlyphHints hints,FT_Outline * outline)1133 af_glyph_hints_save( AF_GlyphHints hints, 1134 FT_Outline* outline ) 1135 { 1136 AF_Point point = hints->points; 1137 AF_Point limit = point + hints->num_points; 1138 FT_Vector* vec = outline->points; 1139 char* tag = outline->tags; 1140 1141 1142 for ( ; point < limit; point++, vec++, tag++ ) 1143 { 1144 vec->x = point->x; 1145 vec->y = point->y; 1146 1147 if ( point->flags & AF_FLAG_CONIC ) 1148 tag[0] = FT_CURVE_TAG_CONIC; 1149 else if ( point->flags & AF_FLAG_CUBIC ) 1150 tag[0] = FT_CURVE_TAG_CUBIC; 1151 else 1152 tag[0] = FT_CURVE_TAG_ON; 1153 } 1154 } 1155 1156 1157 /**************************************************************** 1158 * 1159 * EDGE POINT GRID-FITTING 1160 * 1161 ****************************************************************/ 1162 1163 1164 /* Align all points of an edge to the same coordinate value, */ 1165 /* either horizontally or vertically. */ 1166 1167 FT_LOCAL_DEF( void ) af_glyph_hints_align_edge_points(AF_GlyphHints hints,AF_Dimension dim)1168 af_glyph_hints_align_edge_points( AF_GlyphHints hints, 1169 AF_Dimension dim ) 1170 { 1171 AF_AxisHints axis = & hints->axis[dim]; 1172 AF_Segment segments = axis->segments; 1173 AF_Segment segment_limit = segments + axis->num_segments; 1174 AF_Segment seg; 1175 1176 1177 if ( dim == AF_DIMENSION_HORZ ) 1178 { 1179 for ( seg = segments; seg < segment_limit; seg++ ) 1180 { 1181 AF_Edge edge = seg->edge; 1182 AF_Point point, first, last; 1183 1184 1185 if ( !edge ) 1186 continue; 1187 1188 first = seg->first; 1189 last = seg->last; 1190 point = first; 1191 for (;;) 1192 { 1193 point->x = edge->pos; 1194 point->flags |= AF_FLAG_TOUCH_X; 1195 1196 if ( point == last ) 1197 break; 1198 1199 point = point->next; 1200 } 1201 } 1202 } 1203 else 1204 { 1205 for ( seg = segments; seg < segment_limit; seg++ ) 1206 { 1207 AF_Edge edge = seg->edge; 1208 AF_Point point, first, last; 1209 1210 1211 if ( !edge ) 1212 continue; 1213 1214 first = seg->first; 1215 last = seg->last; 1216 point = first; 1217 for (;;) 1218 { 1219 point->y = edge->pos; 1220 point->flags |= AF_FLAG_TOUCH_Y; 1221 1222 if ( point == last ) 1223 break; 1224 1225 point = point->next; 1226 } 1227 } 1228 } 1229 } 1230 1231 1232 /**************************************************************** 1233 * 1234 * STRONG POINT INTERPOLATION 1235 * 1236 ****************************************************************/ 1237 1238 1239 /* Hint the strong points -- this is equivalent to the TrueType `IP' */ 1240 /* hinting instruction. */ 1241 1242 FT_LOCAL_DEF( void ) af_glyph_hints_align_strong_points(AF_GlyphHints hints,AF_Dimension dim)1243 af_glyph_hints_align_strong_points( AF_GlyphHints hints, 1244 AF_Dimension dim ) 1245 { 1246 AF_Point points = hints->points; 1247 AF_Point point_limit = points + hints->num_points; 1248 AF_AxisHints axis = &hints->axis[dim]; 1249 AF_Edge edges = axis->edges; 1250 AF_Edge edge_limit = edges + axis->num_edges; 1251 FT_UInt touch_flag; 1252 1253 1254 if ( dim == AF_DIMENSION_HORZ ) 1255 touch_flag = AF_FLAG_TOUCH_X; 1256 else 1257 touch_flag = AF_FLAG_TOUCH_Y; 1258 1259 if ( edges < edge_limit ) 1260 { 1261 AF_Point point; 1262 AF_Edge edge; 1263 1264 1265 for ( point = points; point < point_limit; point++ ) 1266 { 1267 FT_Pos u, ou, fu; /* point position */ 1268 FT_Pos delta; 1269 1270 1271 if ( point->flags & touch_flag ) 1272 continue; 1273 1274 /* if this point is candidate to weak interpolation, we */ 1275 /* interpolate it after all strong points have been processed */ 1276 1277 if ( ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) ) 1278 continue; 1279 1280 if ( dim == AF_DIMENSION_VERT ) 1281 { 1282 u = point->fy; 1283 ou = point->oy; 1284 } 1285 else 1286 { 1287 u = point->fx; 1288 ou = point->ox; 1289 } 1290 1291 fu = u; 1292 1293 /* is the point before the first edge? */ 1294 edge = edges; 1295 delta = edge->fpos - u; 1296 if ( delta >= 0 ) 1297 { 1298 u = edge->pos - ( edge->opos - ou ); 1299 goto Store_Point; 1300 } 1301 1302 /* is the point after the last edge? */ 1303 edge = edge_limit - 1; 1304 delta = u - edge->fpos; 1305 if ( delta >= 0 ) 1306 { 1307 u = edge->pos + ( ou - edge->opos ); 1308 goto Store_Point; 1309 } 1310 1311 { 1312 FT_PtrDist min, max, mid; 1313 FT_Pos fpos; 1314 1315 1316 /* find enclosing edges */ 1317 min = 0; 1318 max = edge_limit - edges; 1319 1320 #if 1 1321 /* for a small number of edges, a linear search is better */ 1322 if ( max <= 8 ) 1323 { 1324 FT_PtrDist nn; 1325 1326 1327 for ( nn = 0; nn < max; nn++ ) 1328 if ( edges[nn].fpos >= u ) 1329 break; 1330 1331 if ( edges[nn].fpos == u ) 1332 { 1333 u = edges[nn].pos; 1334 goto Store_Point; 1335 } 1336 min = nn; 1337 } 1338 else 1339 #endif 1340 while ( min < max ) 1341 { 1342 mid = ( max + min ) >> 1; 1343 edge = edges + mid; 1344 fpos = edge->fpos; 1345 1346 if ( u < fpos ) 1347 max = mid; 1348 else if ( u > fpos ) 1349 min = mid + 1; 1350 else 1351 { 1352 /* we are on the edge */ 1353 u = edge->pos; 1354 goto Store_Point; 1355 } 1356 } 1357 1358 /* point is not on an edge */ 1359 { 1360 AF_Edge before = edges + min - 1; 1361 AF_Edge after = edges + min + 0; 1362 1363 1364 /* assert( before && after && before != after ) */ 1365 if ( before->scale == 0 ) 1366 before->scale = FT_DivFix( after->pos - before->pos, 1367 after->fpos - before->fpos ); 1368 1369 u = before->pos + FT_MulFix( fu - before->fpos, 1370 before->scale ); 1371 } 1372 } 1373 1374 Store_Point: 1375 /* save the point position */ 1376 if ( dim == AF_DIMENSION_HORZ ) 1377 point->x = u; 1378 else 1379 point->y = u; 1380 1381 point->flags |= touch_flag; 1382 } 1383 } 1384 } 1385 1386 1387 /**************************************************************** 1388 * 1389 * WEAK POINT INTERPOLATION 1390 * 1391 ****************************************************************/ 1392 1393 1394 /* Shift the original coordinates of all points between `p1' and */ 1395 /* `p2' to get hinted coordinates, using the same difference as */ 1396 /* given by `ref'. */ 1397 1398 static void af_iup_shift(AF_Point p1,AF_Point p2,AF_Point ref)1399 af_iup_shift( AF_Point p1, 1400 AF_Point p2, 1401 AF_Point ref ) 1402 { 1403 AF_Point p; 1404 FT_Pos delta = ref->u - ref->v; 1405 1406 1407 if ( delta == 0 ) 1408 return; 1409 1410 for ( p = p1; p < ref; p++ ) 1411 p->u = p->v + delta; 1412 1413 for ( p = ref + 1; p <= p2; p++ ) 1414 p->u = p->v + delta; 1415 } 1416 1417 1418 /* Interpolate the original coordinates of all points between `p1' and */ 1419 /* `p2' to get hinted coordinates, using `ref1' and `ref2' as the */ 1420 /* reference points. The `u' and `v' members are the current and */ 1421 /* original coordinate values, respectively. */ 1422 /* */ 1423 /* Details can be found in the TrueType bytecode specification. */ 1424 1425 static void af_iup_interp(AF_Point p1,AF_Point p2,AF_Point ref1,AF_Point ref2)1426 af_iup_interp( AF_Point p1, 1427 AF_Point p2, 1428 AF_Point ref1, 1429 AF_Point ref2 ) 1430 { 1431 AF_Point p; 1432 FT_Pos u, v1, v2, u1, u2, d1, d2; 1433 1434 1435 if ( p1 > p2 ) 1436 return; 1437 1438 if ( ref1->v > ref2->v ) 1439 { 1440 p = ref1; 1441 ref1 = ref2; 1442 ref2 = p; 1443 } 1444 1445 v1 = ref1->v; 1446 v2 = ref2->v; 1447 u1 = ref1->u; 1448 u2 = ref2->u; 1449 d1 = u1 - v1; 1450 d2 = u2 - v2; 1451 1452 if ( u1 == u2 || v1 == v2 ) 1453 { 1454 for ( p = p1; p <= p2; p++ ) 1455 { 1456 u = p->v; 1457 1458 if ( u <= v1 ) 1459 u += d1; 1460 else if ( u >= v2 ) 1461 u += d2; 1462 else 1463 u = u1; 1464 1465 p->u = u; 1466 } 1467 } 1468 else 1469 { 1470 FT_Fixed scale = FT_DivFix( u2 - u1, v2 - v1 ); 1471 1472 1473 for ( p = p1; p <= p2; p++ ) 1474 { 1475 u = p->v; 1476 1477 if ( u <= v1 ) 1478 u += d1; 1479 else if ( u >= v2 ) 1480 u += d2; 1481 else 1482 u = u1 + FT_MulFix( u - v1, scale ); 1483 1484 p->u = u; 1485 } 1486 } 1487 } 1488 1489 1490 /* Hint the weak points -- this is equivalent to the TrueType `IUP' */ 1491 /* hinting instruction. */ 1492 1493 FT_LOCAL_DEF( void ) af_glyph_hints_align_weak_points(AF_GlyphHints hints,AF_Dimension dim)1494 af_glyph_hints_align_weak_points( AF_GlyphHints hints, 1495 AF_Dimension dim ) 1496 { 1497 AF_Point points = hints->points; 1498 AF_Point point_limit = points + hints->num_points; 1499 AF_Point* contour = hints->contours; 1500 AF_Point* contour_limit = contour + hints->num_contours; 1501 FT_UInt touch_flag; 1502 AF_Point point; 1503 AF_Point end_point; 1504 AF_Point first_point; 1505 1506 1507 /* PASS 1: Move segment points to edge positions */ 1508 1509 if ( dim == AF_DIMENSION_HORZ ) 1510 { 1511 touch_flag = AF_FLAG_TOUCH_X; 1512 1513 for ( point = points; point < point_limit; point++ ) 1514 { 1515 point->u = point->x; 1516 point->v = point->ox; 1517 } 1518 } 1519 else 1520 { 1521 touch_flag = AF_FLAG_TOUCH_Y; 1522 1523 for ( point = points; point < point_limit; point++ ) 1524 { 1525 point->u = point->y; 1526 point->v = point->oy; 1527 } 1528 } 1529 1530 for ( ; contour < contour_limit; contour++ ) 1531 { 1532 AF_Point first_touched, last_touched; 1533 1534 1535 point = *contour; 1536 end_point = point->prev; 1537 first_point = point; 1538 1539 /* find first touched point */ 1540 for (;;) 1541 { 1542 if ( point > end_point ) /* no touched point in contour */ 1543 goto NextContour; 1544 1545 if ( point->flags & touch_flag ) 1546 break; 1547 1548 point++; 1549 } 1550 1551 first_touched = point; 1552 1553 for (;;) 1554 { 1555 FT_ASSERT( point <= end_point && 1556 ( point->flags & touch_flag ) != 0 ); 1557 1558 /* skip any touched neighbours */ 1559 while ( point < end_point && 1560 ( point[1].flags & touch_flag ) != 0 ) 1561 point++; 1562 1563 last_touched = point; 1564 1565 /* find the next touched point, if any */ 1566 point++; 1567 for (;;) 1568 { 1569 if ( point > end_point ) 1570 goto EndContour; 1571 1572 if ( ( point->flags & touch_flag ) != 0 ) 1573 break; 1574 1575 point++; 1576 } 1577 1578 /* interpolate between last_touched and point */ 1579 af_iup_interp( last_touched + 1, point - 1, 1580 last_touched, point ); 1581 } 1582 1583 EndContour: 1584 /* special case: only one point was touched */ 1585 if ( last_touched == first_touched ) 1586 af_iup_shift( first_point, end_point, first_touched ); 1587 1588 else /* interpolate the last part */ 1589 { 1590 if ( last_touched < end_point ) 1591 af_iup_interp( last_touched + 1, end_point, 1592 last_touched, first_touched ); 1593 1594 if ( first_touched > points ) 1595 af_iup_interp( first_point, first_touched - 1, 1596 last_touched, first_touched ); 1597 } 1598 1599 NextContour: 1600 ; 1601 } 1602 1603 /* now save the interpolated values back to x/y */ 1604 if ( dim == AF_DIMENSION_HORZ ) 1605 { 1606 for ( point = points; point < point_limit; point++ ) 1607 point->x = point->u; 1608 } 1609 else 1610 { 1611 for ( point = points; point < point_limit; point++ ) 1612 point->y = point->u; 1613 } 1614 } 1615 1616 1617 #ifdef AF_CONFIG_OPTION_USE_WARPER 1618 1619 /* Apply (small) warp scale and warp delta for given dimension. */ 1620 1621 FT_LOCAL_DEF( void ) af_glyph_hints_scale_dim(AF_GlyphHints hints,AF_Dimension dim,FT_Fixed scale,FT_Pos delta)1622 af_glyph_hints_scale_dim( AF_GlyphHints hints, 1623 AF_Dimension dim, 1624 FT_Fixed scale, 1625 FT_Pos delta ) 1626 { 1627 AF_Point points = hints->points; 1628 AF_Point points_limit = points + hints->num_points; 1629 AF_Point point; 1630 1631 1632 if ( dim == AF_DIMENSION_HORZ ) 1633 { 1634 for ( point = points; point < points_limit; point++ ) 1635 point->x = FT_MulFix( point->fx, scale ) + delta; 1636 } 1637 else 1638 { 1639 for ( point = points; point < points_limit; point++ ) 1640 point->y = FT_MulFix( point->fy, scale ) + delta; 1641 } 1642 } 1643 1644 #endif /* AF_CONFIG_OPTION_USE_WARPER */ 1645 1646 /* END */ 1647