1 /***************************************************************************/
5 /* Auto-fitter hinting routines (body). */
7 /* Copyright 2003-2007, 2009-2013 by */
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
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. */
16 /***************************************************************************/
21 #include FT_INTERNAL_CALC_H
22 #include FT_INTERNAL_DEBUG_H
25 /*************************************************************************/
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. */
32 #define FT_COMPONENT trace_afhints
35 /* Get new segment for given axis. */
37 FT_LOCAL_DEF( FT_Error )
38 af_axis_hints_new_segment( AF_AxisHints axis,
40 AF_Segment *asegment )
42 FT_Error error = FT_Err_Ok;
43 AF_Segment segment = NULL;
46 if ( axis->num_segments >= axis->max_segments )
48 FT_Int old_max = axis->max_segments;
49 FT_Int new_max = old_max;
50 FT_Int big_max = (FT_Int)( FT_INT_MAX / sizeof ( *segment ) );
53 if ( old_max >= big_max )
55 error = FT_THROW( Out_Of_Memory );
59 new_max += ( new_max >> 2 ) + 4;
60 if ( new_max < old_max || new_max > big_max )
63 if ( FT_RENEW_ARRAY( axis->segments, old_max, new_max ) )
66 axis->max_segments = new_max;
69 segment = axis->segments + axis->num_segments++;
77 /* Get new edge for given axis, direction, and position. */
80 af_axis_hints_new_edge( AF_AxisHints axis,
86 FT_Error error = FT_Err_Ok;
91 if ( axis->num_edges >= axis->max_edges )
93 FT_Int old_max = axis->max_edges;
94 FT_Int new_max = old_max;
95 FT_Int big_max = (FT_Int)( FT_INT_MAX / sizeof ( *edge ) );
98 if ( old_max >= big_max )
100 error = FT_THROW( Out_Of_Memory );
104 new_max += ( new_max >> 2 ) + 4;
105 if ( new_max < old_max || new_max > big_max )
108 if ( FT_RENEW_ARRAY( axis->edges, old_max, new_max ) )
111 axis->max_edges = new_max;
115 edge = edges + axis->num_edges;
117 while ( edge > edges )
119 if ( edge[-1].fpos < fpos )
122 /* we want the edge with same position and minor direction */
123 /* to appear before those in the major one in the list */
124 if ( edge[-1].fpos == fpos && dir == axis->major_dir )
134 edge->fpos = (FT_Short)fpos;
135 edge->dir = (FT_Char)dir;
143 #ifdef FT_DEBUG_AUTOFIT
145 #include FT_CONFIG_STANDARD_LIBRARY_H
148 af_dir_str( AF_Direction dir )
175 #define AF_INDEX_NUM( ptr, base ) ( (ptr) ? ( (ptr) - (base) ) : -1 )
182 af_glyph_hints_dump_points( AF_GlyphHints hints )
184 AF_Point points = hints->points;
185 AF_Point limit = points + hints->num_points;
189 FT_TRACE7(( "Table of points:\n"
190 " [ index | xorg | yorg | xscale | yscale"
191 " | xfit | yfit | flags ]\n" ));
193 for ( point = points; point < limit; point++ )
194 FT_TRACE7(( " [ %5d | %5d | %5d | %6.2f | %6.2f"
195 " | %5.2f | %5.2f | %c%c%c%c%c%c ]\n",
203 ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) ? 'w' : ' ',
204 ( point->flags & AF_FLAG_INFLECTION ) ? 'i' : ' ',
205 ( point->flags & AF_FLAG_EXTREMA_X ) ? '<' : ' ',
206 ( point->flags & AF_FLAG_EXTREMA_Y ) ? 'v' : ' ',
207 ( point->flags & AF_FLAG_ROUND_X ) ? '(' : ' ',
208 ( point->flags & AF_FLAG_ROUND_Y ) ? 'u' : ' '));
217 af_edge_flags_to_string( AF_Edge_Flags flags )
219 static char temp[32];
223 if ( flags & AF_EDGE_ROUND )
225 ft_memcpy( temp + pos, "round", 5 );
228 if ( flags & AF_EDGE_SERIF )
232 ft_memcpy( temp + pos, "serif", 5 );
244 /* Dump the array of linked segments. */
250 af_glyph_hints_dump_segments( AF_GlyphHints hints )
255 for ( dimension = 1; dimension >= 0; dimension-- )
257 AF_AxisHints axis = &hints->axis[dimension];
258 AF_Point points = hints->points;
259 AF_Edge edges = axis->edges;
260 AF_Segment segments = axis->segments;
261 AF_Segment limit = segments + axis->num_segments;
265 FT_TRACE7(( "Table of %s segments:\n",
266 dimension == AF_DIMENSION_HORZ ? "vertical"
268 if ( axis->num_segments )
269 FT_TRACE7(( " [ index | pos | dir | from"
270 " | to | link | serif | edge"
271 " | height | extra | flags ]\n" ));
273 FT_TRACE7(( " (none)\n" ));
275 for ( seg = segments; seg < limit; seg++ )
276 FT_TRACE7(( " [ %5d | %5.2g | %5s | %4d"
277 " | %4d | %4d | %5d | %4d"
278 " | %6d | %5d | %11s ]\n",
280 dimension == AF_DIMENSION_HORZ
281 ? (int)seg->first->ox / 64.0
282 : (int)seg->first->oy / 64.0,
283 af_dir_str( (AF_Direction)seg->dir ),
284 AF_INDEX_NUM( seg->first, points ),
285 AF_INDEX_NUM( seg->last, points ),
286 AF_INDEX_NUM( seg->link, segments ),
287 AF_INDEX_NUM( seg->serif, segments ),
288 AF_INDEX_NUM( seg->edge, edges ),
290 seg->height - ( seg->max_coord - seg->min_coord ),
291 af_edge_flags_to_string( (AF_Edge_Flags)seg->flags ) ));
300 /* Fetch number of segments. */
306 af_glyph_hints_get_num_segments( AF_GlyphHints hints,
308 FT_Int* num_segments )
314 dim = ( dimension == 0 ) ? AF_DIMENSION_HORZ : AF_DIMENSION_VERT;
316 axis = &hints->axis[dim];
317 *num_segments = axis->num_segments;
326 /* Fetch offset of segments into user supplied offset array. */
332 af_glyph_hints_get_segment_offset( AF_GlyphHints hints,
343 return FT_THROW( Invalid_Argument );
345 dim = ( dimension == 0 ) ? AF_DIMENSION_HORZ : AF_DIMENSION_VERT;
347 axis = &hints->axis[dim];
349 if ( idx < 0 || idx >= axis->num_segments )
350 return FT_THROW( Invalid_Argument );
352 seg = &axis->segments[idx];
353 *offset = ( dim == AF_DIMENSION_HORZ ) ? seg->first->ox
363 /* Dump the array of linked edges. */
369 af_glyph_hints_dump_edges( AF_GlyphHints hints )
374 for ( dimension = 1; dimension >= 0; dimension-- )
376 AF_AxisHints axis = &hints->axis[dimension];
377 AF_Edge edges = axis->edges;
378 AF_Edge limit = edges + axis->num_edges;
383 * note: AF_DIMENSION_HORZ corresponds to _vertical_ edges
384 * since they have a constant X coordinate.
386 FT_TRACE7(( "Table of %s edges:\n",
387 dimension == AF_DIMENSION_HORZ ? "vertical"
389 if ( axis->num_edges )
390 FT_TRACE7(( " [ index | pos | dir | link"
391 " | serif | blue | opos | pos | flags ]\n" ));
393 FT_TRACE7(( " (none)\n" ));
395 for ( edge = edges; edge < limit; edge++ )
396 FT_TRACE7(( " [ %5d | %5.2g | %5s | %4d"
397 " | %5d | %c | %5.2f | %5.2f | %11s ]\n",
399 (int)edge->opos / 64.0,
400 af_dir_str( (AF_Direction)edge->dir ),
401 AF_INDEX_NUM( edge->link, edges ),
402 AF_INDEX_NUM( edge->serif, edges ),
403 edge->blue_edge ? 'y' : 'n',
406 af_edge_flags_to_string( (AF_Edge_Flags)edge->flags ) ));
414 #else /* !FT_DEBUG_AUTOFIT */
416 /* these empty stubs are only used to link the `ftgrid' test program */
417 /* if debugging is disabled */
424 af_glyph_hints_dump_points( AF_GlyphHints hints )
431 af_glyph_hints_dump_segments( AF_GlyphHints hints )
438 af_glyph_hints_get_num_segments( AF_GlyphHints hints,
440 FT_Int* num_segments )
443 FT_UNUSED( dimension );
444 FT_UNUSED( num_segments );
451 af_glyph_hints_get_segment_offset( AF_GlyphHints hints,
457 FT_UNUSED( dimension );
466 af_glyph_hints_dump_edges( AF_GlyphHints hints )
475 #endif /* !FT_DEBUG_AUTOFIT */
478 /* Compute the direction value of a given vector. */
480 FT_LOCAL_DEF( AF_Direction )
481 af_direction_compute( FT_Pos dx,
484 FT_Pos ll, ss; /* long and short arm lengths */
485 AF_Direction dir; /* candidate direction */
519 /* return no direction if arm lengths differ too much */
520 /* (value 14 is heuristic, corresponding to approx. 4.1 degrees) */
522 if ( FT_ABS( ll ) <= FT_ABS( ss ) )
530 af_glyph_hints_init( AF_GlyphHints hints,
534 hints->memory = memory;
539 af_glyph_hints_done( AF_GlyphHints hints )
541 FT_Memory memory = hints->memory;
545 if ( !( hints && hints->memory ) )
549 * note that we don't need to free the segment and edge
550 * buffers since they are really within the hints->points array
552 for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
554 AF_AxisHints axis = &hints->axis[dim];
557 axis->num_segments = 0;
558 axis->max_segments = 0;
559 FT_FREE( axis->segments );
563 FT_FREE( axis->edges );
566 FT_FREE( hints->contours );
567 hints->max_contours = 0;
568 hints->num_contours = 0;
570 FT_FREE( hints->points );
571 hints->num_points = 0;
572 hints->max_points = 0;
574 hints->memory = NULL;
581 af_glyph_hints_rescale( AF_GlyphHints hints,
582 AF_ScriptMetrics metrics )
584 hints->metrics = metrics;
585 hints->scaler_flags = metrics->scaler.flags;
589 /* Recompute all AF_Point in AF_GlyphHints from the definitions */
590 /* in a source outline. */
592 FT_LOCAL_DEF( FT_Error )
593 af_glyph_hints_reload( AF_GlyphHints hints,
594 FT_Outline* outline )
596 FT_Error error = FT_Err_Ok;
598 FT_UInt old_max, new_max;
599 FT_Fixed x_scale = hints->x_scale;
600 FT_Fixed y_scale = hints->y_scale;
601 FT_Pos x_delta = hints->x_delta;
602 FT_Pos y_delta = hints->y_delta;
603 FT_Memory memory = hints->memory;
606 hints->num_points = 0;
607 hints->num_contours = 0;
609 hints->axis[0].num_segments = 0;
610 hints->axis[0].num_edges = 0;
611 hints->axis[1].num_segments = 0;
612 hints->axis[1].num_edges = 0;
614 /* first of all, reallocate the contours array if necessary */
615 new_max = (FT_UInt)outline->n_contours;
616 old_max = hints->max_contours;
617 if ( new_max > old_max )
619 new_max = ( new_max + 3 ) & ~3; /* round up to a multiple of 4 */
621 if ( FT_RENEW_ARRAY( hints->contours, old_max, new_max ) )
624 hints->max_contours = new_max;
628 * then reallocate the points arrays if necessary --
629 * note that we reserve two additional point positions, used to
630 * hint metrics appropriately
632 new_max = (FT_UInt)( outline->n_points + 2 );
633 old_max = hints->max_points;
634 if ( new_max > old_max )
636 new_max = ( new_max + 2 + 7 ) & ~7; /* round up to a multiple of 8 */
638 if ( FT_RENEW_ARRAY( hints->points, old_max, new_max ) )
641 hints->max_points = new_max;
644 hints->num_points = outline->n_points;
645 hints->num_contours = outline->n_contours;
647 /* We can't rely on the value of `FT_Outline.flags' to know the fill */
648 /* direction used for a glyph, given that some fonts are broken (e.g., */
649 /* the Arphic ones). We thus recompute it each time we need to. */
651 hints->axis[AF_DIMENSION_HORZ].major_dir = AF_DIR_UP;
652 hints->axis[AF_DIMENSION_VERT].major_dir = AF_DIR_LEFT;
654 if ( FT_Outline_Get_Orientation( outline ) == FT_ORIENTATION_POSTSCRIPT )
656 hints->axis[AF_DIMENSION_HORZ].major_dir = AF_DIR_DOWN;
657 hints->axis[AF_DIMENSION_VERT].major_dir = AF_DIR_RIGHT;
660 hints->x_scale = x_scale;
661 hints->y_scale = y_scale;
662 hints->x_delta = x_delta;
663 hints->y_delta = y_delta;
665 hints->xmin_delta = 0;
666 hints->xmax_delta = 0;
668 points = hints->points;
669 if ( hints->num_points == 0 )
674 AF_Point point_limit = points + hints->num_points;
677 /* compute coordinates & Bezier flags, next and prev */
679 FT_Vector* vec = outline->points;
680 char* tag = outline->tags;
681 AF_Point end = points + outline->contours[0];
683 FT_Int contour_index = 0;
686 for ( point = points; point < point_limit; point++, vec++, tag++ )
688 point->fx = (FT_Short)vec->x;
689 point->fy = (FT_Short)vec->y;
690 point->ox = point->x = FT_MulFix( vec->x, x_scale ) + x_delta;
691 point->oy = point->y = FT_MulFix( vec->y, y_scale ) + y_delta;
693 switch ( FT_CURVE_TAG( *tag ) )
695 case FT_CURVE_TAG_CONIC:
696 point->flags = AF_FLAG_CONIC;
698 case FT_CURVE_TAG_CUBIC:
699 point->flags = AF_FLAG_CUBIC;
702 point->flags = AF_FLAG_NONE;
711 if ( ++contour_index < outline->n_contours )
713 end = points + outline->contours[contour_index];
720 /* set up the contours array */
722 AF_Point* contour = hints->contours;
723 AF_Point* contour_limit = contour + hints->num_contours;
724 short* end = outline->contours;
728 for ( ; contour < contour_limit; contour++, end++ )
730 contour[0] = points + idx;
731 idx = (short)( end[0] + 1 );
735 /* compute directions of in & out vectors */
737 AF_Point first = points;
738 AF_Point prev = NULL;
741 AF_Direction in_dir = AF_DIR_NONE;
744 for ( point = points; point < point_limit; point++ )
750 if ( point == first )
753 in_x = first->fx - prev->fx;
754 in_y = first->fy - prev->fy;
755 in_dir = af_direction_compute( in_x, in_y );
759 point->in_dir = (FT_Char)in_dir;
762 out_x = next->fx - point->fx;
763 out_y = next->fy - point->fy;
765 in_dir = af_direction_compute( out_x, out_y );
766 point->out_dir = (FT_Char)in_dir;
768 /* check for weak points */
770 if ( point->flags & AF_FLAG_CONTROL )
773 point->flags |= AF_FLAG_WEAK_INTERPOLATION;
775 else if ( point->out_dir == point->in_dir )
777 if ( point->out_dir != AF_DIR_NONE )
780 if ( ft_corner_is_flat( in_x, in_y, out_x, out_y ) )
783 else if ( point->in_dir == -point->out_dir )
798 /* Store the hinted outline in an FT_Outline structure. */
801 af_glyph_hints_save( AF_GlyphHints hints,
802 FT_Outline* outline )
804 AF_Point point = hints->points;
805 AF_Point limit = point + hints->num_points;
806 FT_Vector* vec = outline->points;
807 char* tag = outline->tags;
810 for ( ; point < limit; point++, vec++, tag++ )
815 if ( point->flags & AF_FLAG_CONIC )
816 tag[0] = FT_CURVE_TAG_CONIC;
817 else if ( point->flags & AF_FLAG_CUBIC )
818 tag[0] = FT_CURVE_TAG_CUBIC;
820 tag[0] = FT_CURVE_TAG_ON;
825 /****************************************************************
827 * EDGE POINT GRID-FITTING
829 ****************************************************************/
832 /* Align all points of an edge to the same coordinate value, */
833 /* either horizontally or vertically. */
836 af_glyph_hints_align_edge_points( AF_GlyphHints hints,
839 AF_AxisHints axis = & hints->axis[dim];
840 AF_Segment segments = axis->segments;
841 AF_Segment segment_limit = segments + axis->num_segments;
845 if ( dim == AF_DIMENSION_HORZ )
847 for ( seg = segments; seg < segment_limit; seg++ )
849 AF_Edge edge = seg->edge;
850 AF_Point point, first, last;
861 point->x = edge->pos;
862 point->flags |= AF_FLAG_TOUCH_X;
873 for ( seg = segments; seg < segment_limit; seg++ )
875 AF_Edge edge = seg->edge;
876 AF_Point point, first, last;
887 point->y = edge->pos;
888 point->flags |= AF_FLAG_TOUCH_Y;
900 /****************************************************************
902 * STRONG POINT INTERPOLATION
904 ****************************************************************/
907 /* Hint the strong points -- this is equivalent to the TrueType `IP' */
908 /* hinting instruction. */
911 af_glyph_hints_align_strong_points( AF_GlyphHints hints,
914 AF_Point points = hints->points;
915 AF_Point point_limit = points + hints->num_points;
916 AF_AxisHints axis = &hints->axis[dim];
917 AF_Edge edges = axis->edges;
918 AF_Edge edge_limit = edges + axis->num_edges;
922 if ( dim == AF_DIMENSION_HORZ )
923 touch_flag = AF_FLAG_TOUCH_X;
925 touch_flag = AF_FLAG_TOUCH_Y;
927 if ( edges < edge_limit )
933 for ( point = points; point < point_limit; point++ )
935 FT_Pos u, ou, fu; /* point position */
939 if ( point->flags & touch_flag )
942 /* if this point is candidate to weak interpolation, we */
943 /* interpolate it after all strong points have been processed */
945 if ( ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) &&
946 !( point->flags & AF_FLAG_INFLECTION ) )
949 if ( dim == AF_DIMENSION_VERT )
962 /* is the point before the first edge? */
964 delta = edge->fpos - u;
967 u = edge->pos - ( edge->opos - ou );
971 /* is the point after the last edge? */
972 edge = edge_limit - 1;
973 delta = u - edge->fpos;
976 u = edge->pos + ( ou - edge->opos );
981 FT_PtrDist min, max, mid;
985 /* find enclosing edges */
987 max = edge_limit - edges;
990 /* for a small number of edges, a linear search is better */
996 for ( nn = 0; nn < max; nn++ )
997 if ( edges[nn].fpos >= u )
1000 if ( edges[nn].fpos == u )
1011 mid = ( max + min ) >> 1;
1017 else if ( u > fpos )
1021 /* we are on the edge */
1027 /* point is not on an edge */
1029 AF_Edge before = edges + min - 1;
1030 AF_Edge after = edges + min + 0;
1033 /* assert( before && after && before != after ) */
1034 if ( before->scale == 0 )
1035 before->scale = FT_DivFix( after->pos - before->pos,
1036 after->fpos - before->fpos );
1038 u = before->pos + FT_MulFix( fu - before->fpos,
1044 /* save the point position */
1045 if ( dim == AF_DIMENSION_HORZ )
1050 point->flags |= touch_flag;
1056 /****************************************************************
1058 * WEAK POINT INTERPOLATION
1060 ****************************************************************/
1063 /* Shift the original coordinates of all points between `p1' and */
1064 /* `p2' to get hinted coordinates, using the same difference as */
1065 /* given by `ref'. */
1068 af_iup_shift( AF_Point p1,
1073 FT_Pos delta = ref->u - ref->v;
1079 for ( p = p1; p < ref; p++ )
1080 p->u = p->v + delta;
1082 for ( p = ref + 1; p <= p2; p++ )
1083 p->u = p->v + delta;
1087 /* Interpolate the original coordinates of all points between `p1' and */
1088 /* `p2' to get hinted coordinates, using `ref1' and `ref2' as the */
1089 /* reference points. The `u' and `v' members are the current and */
1090 /* original coordinate values, respectively. */
1092 /* Details can be found in the TrueType bytecode specification. */
1095 af_iup_interp( AF_Point p1,
1102 FT_Pos v1 = ref1->v;
1103 FT_Pos v2 = ref2->v;
1104 FT_Pos d1 = ref1->u - v1;
1105 FT_Pos d2 = ref2->u - v2;
1113 for ( p = p1; p <= p2; p++ )
1129 for ( p = p1; p <= p2; p++ )
1138 u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 );
1145 for ( p = p1; p <= p2; p++ )
1154 u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 );
1162 /* Hint the weak points -- this is equivalent to the TrueType `IUP' */
1163 /* hinting instruction. */
1165 FT_LOCAL_DEF( void )
1166 af_glyph_hints_align_weak_points( AF_GlyphHints hints,
1169 AF_Point points = hints->points;
1170 AF_Point point_limit = points + hints->num_points;
1171 AF_Point* contour = hints->contours;
1172 AF_Point* contour_limit = contour + hints->num_contours;
1173 AF_Flags touch_flag;
1176 AF_Point first_point;
1179 /* PASS 1: Move segment points to edge positions */
1181 if ( dim == AF_DIMENSION_HORZ )
1183 touch_flag = AF_FLAG_TOUCH_X;
1185 for ( point = points; point < point_limit; point++ )
1187 point->u = point->x;
1188 point->v = point->ox;
1193 touch_flag = AF_FLAG_TOUCH_Y;
1195 for ( point = points; point < point_limit; point++ )
1197 point->u = point->y;
1198 point->v = point->oy;
1204 for ( ; contour < contour_limit; contour++ )
1206 AF_Point first_touched, last_touched;
1210 end_point = point->prev;
1211 first_point = point;
1213 /* find first touched point */
1216 if ( point > end_point ) /* no touched point in contour */
1219 if ( point->flags & touch_flag )
1225 first_touched = point;
1226 last_touched = point;
1230 FT_ASSERT( point <= end_point &&
1231 ( point->flags & touch_flag ) != 0 );
1233 /* skip any touched neighbours */
1234 while ( point < end_point &&
1235 ( point[1].flags & touch_flag ) != 0 )
1238 last_touched = point;
1240 /* find the next touched point, if any */
1244 if ( point > end_point )
1247 if ( ( point->flags & touch_flag ) != 0 )
1253 /* interpolate between last_touched and point */
1254 af_iup_interp( last_touched + 1, point - 1,
1255 last_touched, point );
1259 /* special case: only one point was touched */
1260 if ( last_touched == first_touched )
1261 af_iup_shift( first_point, end_point, first_touched );
1263 else /* interpolate the last part */
1265 if ( last_touched < end_point )
1266 af_iup_interp( last_touched + 1, end_point,
1267 last_touched, first_touched );
1269 if ( first_touched > points )
1270 af_iup_interp( first_point, first_touched - 1,
1271 last_touched, first_touched );
1278 /* now save the interpolated values back to x/y */
1279 if ( dim == AF_DIMENSION_HORZ )
1281 for ( point = points; point < point_limit; point++ )
1282 point->x = point->u;
1286 for ( point = points; point < point_limit; point++ )
1287 point->y = point->u;
1292 #ifdef AF_CONFIG_OPTION_USE_WARPER
1294 /* Apply (small) warp scale and warp delta for given dimension. */
1296 FT_LOCAL_DEF( void )
1297 af_glyph_hints_scale_dim( AF_GlyphHints hints,
1302 AF_Point points = hints->points;
1303 AF_Point points_limit = points + hints->num_points;
1307 if ( dim == AF_DIMENSION_HORZ )
1309 for ( point = points; point < points_limit; point++ )
1310 point->x = FT_MulFix( point->fx, scale ) + delta;
1314 for ( point = points; point < points_limit; point++ )
1315 point->y = FT_MulFix( point->fy, scale ) + delta;
1319 #endif /* AF_CONFIG_OPTION_USE_WARPER */