4 * Copyright (C) 2011-2014 by Werner Lemberg.
6 * This file is part of the ttfautohint library, and may only be used,
7 * modified, and distributed under the terms given in `COPYING'. By
8 * continuing to use, modify, or distribute this file you indicate that you
9 * have read `COPYING' and understand and accept it fully.
11 * The file `COPYING' mentioned in the previous paragraph is distributed
12 * with the ttfautohint library.
16 /* originally file `afhints.c' (2011-Mar-28) from FreeType */
18 /* heavily modified 2011 by Werner Lemberg <wl@gnu.org> */
25 /* get new segment for given axis */
28 ta_axis_hints_new_segment(TA_AxisHints axis
,
31 FT_Error error
= FT_Err_Ok
;
32 TA_Segment segment
= NULL
;
35 if (axis
->num_segments
>= axis
->max_segments
)
37 TA_Segment segments_new
;
39 FT_Int old_max
= axis
->max_segments
;
40 FT_Int new_max
= old_max
;
41 FT_Int big_max
= (FT_Int
)(FT_INT_MAX
/ sizeof (*segment
));
44 if (old_max
>= big_max
)
46 error
= FT_Err_Out_Of_Memory
;
50 new_max
+= (new_max
>> 2) + 4;
55 segments_new
= (TA_Segment
)realloc(axis
->segments
,
56 new_max
* sizeof (TA_SegmentRec
));
58 return FT_Err_Out_Of_Memory
;
60 axis
->segments
= segments_new
;
61 axis
->max_segments
= new_max
;
64 segment
= axis
->segments
+ axis
->num_segments
++;
72 /* get new edge for given axis, direction, and position */
75 ta_axis_hints_new_edge(TA_AxisHints axis
,
80 FT_Error error
= FT_Err_Ok
;
85 if (axis
->num_edges
>= axis
->max_edges
)
89 FT_Int old_max
= axis
->max_edges
;
90 FT_Int new_max
= old_max
;
91 FT_Int big_max
= (FT_Int
)(FT_INT_MAX
/ sizeof (*edge
));
94 if (old_max
>= big_max
)
96 error
= FT_Err_Out_Of_Memory
;
100 new_max
+= (new_max
>> 2) + 4;
101 if (new_max
< old_max
102 || new_max
> big_max
)
105 edges_new
= (TA_Edge
)realloc(axis
->edges
,
106 new_max
* sizeof (TA_EdgeRec
));
108 return FT_Err_Out_Of_Memory
;
110 axis
->edges
= edges_new
;
111 axis
->max_edges
= new_max
;
115 edge
= edges
+ axis
->num_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
125 && dir
== axis
->major_dir
)
134 memset(edge
, 0, sizeof (TA_EdgeRec
));
135 edge
->fpos
= (FT_Short
)fpos
;
136 edge
->dir
= (FT_Char
)dir
;
152 _ta_message(const char* format
,
158 va_start(ap
, format
);
159 vfprintf(stderr
, format
, ap
);
165 ta_dir_str(TA_Direction dir
)
192 #define TA_INDEX_NUM(ptr, base) \
193 ((ptr) ? ((ptr) - (base)) \
198 ta_glyph_hints_dump_points(TA_GlyphHints hints
)
200 TA_Point points
= hints
->points
;
201 TA_Point limit
= points
+ hints
->num_points
;
205 TA_LOG(("Table of points:\n"
206 " [ index | xorg | yorg | xscale | yscale"
207 " | xfit | yfit | flags ]\n"));
209 for (point
= points
; point
< limit
; point
++)
210 TA_LOG((" [ %5d | %5d | %5d | %6.2f | %6.2f"
211 " | %5.2f | %5.2f | %c%c%c%c%c%c ]\n",
219 (point
->flags
& TA_FLAG_WEAK_INTERPOLATION
) ? 'w' : ' ',
220 (point
->flags
& TA_FLAG_INFLECTION
) ? 'i' : ' ',
221 (point
->flags
& TA_FLAG_EXTREMA_X
) ? '<' : ' ',
222 (point
->flags
& TA_FLAG_EXTREMA_Y
) ? 'v' : ' ',
223 (point
->flags
& TA_FLAG_ROUND_X
) ? '(' : ' ',
224 (point
->flags
& TA_FLAG_ROUND_Y
) ? 'u' : ' '));
230 ta_edge_flags_to_string(FT_Byte flags
)
232 static char temp
[32];
236 if (flags
& TA_EDGE_ROUND
)
238 memcpy(temp
+ pos
, "round", 5);
241 if (flags
& TA_EDGE_SERIF
)
245 memcpy(temp
+ pos
, "serif", 5);
257 /* dump the array of linked segments */
260 ta_glyph_hints_dump_segments(TA_GlyphHints hints
)
265 for (dimension
= TA_DEBUG_STARTDIM
;
266 dimension
>= TA_DEBUG_ENDDIM
;
269 TA_AxisHints axis
= &hints
->axis
[dimension
];
270 TA_Point points
= hints
->points
;
271 TA_Edge edges
= axis
->edges
;
272 TA_Segment segments
= axis
->segments
;
273 TA_Segment limit
= segments
+ axis
->num_segments
;
277 TA_LOG(("Table of %s segments:\n",
278 dimension
== TA_DIMENSION_HORZ
? "vertical"
280 if (axis
->num_segments
)
281 TA_LOG((" [ index | pos | dir | from"
282 " | to | link | serif | edge"
283 " | height | extra | flags ]\n"));
285 TA_LOG((" (none)\n"));
287 for (seg
= segments
; seg
< limit
; seg
++)
288 TA_LOG((" [ %5d | %5.2g | %5s | %4d"
289 " | %4d | %4d | %5d | %4d"
290 " | %6d | %5d | %11s ]\n",
292 dimension
== TA_DIMENSION_HORZ
? (int)seg
->first
->ox
/ 64.0
293 : (int)seg
->first
->oy
/ 64.0,
294 ta_dir_str((TA_Direction
)seg
->dir
),
295 TA_INDEX_NUM(seg
->first
, points
),
296 TA_INDEX_NUM(seg
->last
, points
),
297 TA_INDEX_NUM(seg
->link
, segments
),
298 TA_INDEX_NUM(seg
->serif
, segments
),
299 TA_INDEX_NUM(seg
->edge
, edges
),
301 seg
->height
- (seg
->max_coord
- seg
->min_coord
),
302 ta_edge_flags_to_string(seg
->flags
)));
308 /* dump the array of linked edges */
311 ta_glyph_hints_dump_edges(TA_GlyphHints hints
)
316 for (dimension
= TA_DEBUG_STARTDIM
;
317 dimension
>= TA_DEBUG_ENDDIM
;
320 TA_AxisHints axis
= &hints
->axis
[dimension
];
321 TA_Edge edges
= axis
->edges
;
322 TA_Edge limit
= edges
+ axis
->num_edges
;
326 /* note that TA_DIMENSION_HORZ corresponds to _vertical_ edges */
327 /* since they have a constant X coordinate */
328 TA_LOG(("Table of %s edges:\n",
329 dimension
== TA_DIMENSION_HORZ
? "vertical"
332 TA_LOG((" [ index | pos | dir | link"
333 " | serif | blue | opos | pos | flags ]\n"));
335 TA_LOG((" (none)\n"));
337 for (edge
= edges
; edge
< limit
; edge
++)
338 TA_LOG((" [ %5d | %5.2g | %5s | %4d"
339 " | %5d | %c | %5.2f | %5.2f | %11s ]\n",
341 (int)edge
->opos
/ 64.0,
342 ta_dir_str((TA_Direction
)edge
->dir
),
343 TA_INDEX_NUM(edge
->link
, edges
),
344 TA_INDEX_NUM(edge
->serif
, edges
),
345 edge
->blue_edge
? 'y' : 'n',
348 ta_edge_flags_to_string(edge
->flags
)));
353 #endif /* TA_DEBUG */
356 /* compute the direction value of a given vector */
359 ta_direction_compute(FT_Pos dx
,
362 FT_Pos ll
, ss
; /* long and short arm lengths */
363 TA_Direction dir
; /* candidate direction */
397 /* return no direction if arm lengths differ too much */
398 /* (value 14 is heuristic, corresponding to approx. 4.1 degrees) */
400 if (TA_ABS(ll
) <= TA_ABS(ss
))
408 ta_glyph_hints_init(TA_GlyphHints hints
)
410 memset(hints
, 0, sizeof (TA_GlyphHintsRec
));
415 ta_glyph_hints_done(TA_GlyphHints hints
)
423 /* we don't need to free the segment and edge buffers */
424 /* since they are really within the hints->points array */
425 for (dim
= 0; dim
< TA_DIMENSION_MAX
; dim
++)
427 TA_AxisHints axis
= &hints
->axis
[dim
];
430 axis
->num_segments
= 0;
431 axis
->max_segments
= 0;
432 free(axis
->segments
);
433 axis
->segments
= NULL
;
441 free(hints
->contours
);
442 hints
->contours
= NULL
;
443 hints
->max_contours
= 0;
444 hints
->num_contours
= 0;
447 hints
->points
= NULL
;
448 hints
->num_points
= 0;
449 hints
->max_points
= 0;
456 ta_glyph_hints_rescale(TA_GlyphHints hints
,
457 TA_StyleMetrics metrics
)
459 hints
->metrics
= metrics
;
460 hints
->scaler_flags
= metrics
->scaler
.flags
;
464 /* from FreeType's ftcalc.c */
467 ta_corner_is_flat(FT_Pos in_x
,
475 FT_Pos d_in
, d_out
, d_corner
;
500 return (d_in
+ d_out
- d_corner
) < (d_corner
>> 4);
504 /* recompute all TA_Point in TA_GlyphHints */
505 /* from the definitions in a source outline */
508 ta_glyph_hints_reload(TA_GlyphHints hints
,
511 FT_Error error
= FT_Err_Ok
;
513 FT_UInt old_max
, new_max
;
515 FT_Fixed x_scale
= hints
->x_scale
;
516 FT_Fixed y_scale
= hints
->y_scale
;
517 FT_Pos x_delta
= hints
->x_delta
;
518 FT_Pos y_delta
= hints
->y_delta
;
521 hints
->num_points
= 0;
522 hints
->num_contours
= 0;
524 hints
->axis
[0].num_segments
= 0;
525 hints
->axis
[0].num_edges
= 0;
526 hints
->axis
[1].num_segments
= 0;
527 hints
->axis
[1].num_edges
= 0;
529 /* first of all, reallocate the contours array if necessary */
530 new_max
= (FT_UInt
)outline
->n_contours
;
531 old_max
= hints
->max_contours
;
532 if (new_max
> old_max
)
534 TA_Point
* contours_new
;
537 new_max
= (new_max
+ 3) & ~3; /* round up to a multiple of 4 */
539 contours_new
= (TA_Point
*)realloc(hints
->contours
,
540 new_max
* sizeof (TA_Point
));
542 return FT_Err_Out_Of_Memory
;
544 hints
->contours
= contours_new
;
545 hints
->max_contours
= new_max
;
548 /* reallocate the points arrays if necessary -- we reserve */
549 /* two additional point positions, used to hint metrics appropriately */
550 new_max
= (FT_UInt
)(outline
->n_points
+ 2);
551 old_max
= hints
->max_points
;
552 if (new_max
> old_max
)
557 new_max
= (new_max
+ 2 + 7) & ~7; /* round up to a multiple of 8 */
559 points_new
= (TA_Point
)realloc(hints
->points
,
560 new_max
* sizeof (TA_PointRec
));
562 return FT_Err_Out_Of_Memory
;
564 hints
->points
= points_new
;
565 hints
->max_points
= new_max
;
568 hints
->num_points
= outline
->n_points
;
569 hints
->num_contours
= outline
->n_contours
;
571 /* we can't rely on the value of `FT_Outline.flags' to know the fill */
572 /* direction used for a glyph, given that some fonts are broken */
573 /* (e.g. the Arphic ones); we thus recompute it each time we need to */
575 hints
->axis
[TA_DIMENSION_HORZ
].major_dir
= TA_DIR_UP
;
576 hints
->axis
[TA_DIMENSION_VERT
].major_dir
= TA_DIR_LEFT
;
578 if (FT_Outline_Get_Orientation(outline
) == FT_ORIENTATION_POSTSCRIPT
)
580 hints
->axis
[TA_DIMENSION_HORZ
].major_dir
= TA_DIR_DOWN
;
581 hints
->axis
[TA_DIMENSION_VERT
].major_dir
= TA_DIR_RIGHT
;
584 hints
->x_scale
= x_scale
;
585 hints
->y_scale
= y_scale
;
586 hints
->x_delta
= x_delta
;
587 hints
->y_delta
= y_delta
;
589 hints
->xmin_delta
= 0;
590 hints
->xmax_delta
= 0;
592 points
= hints
->points
;
593 if (hints
->num_points
== 0)
598 TA_Point point_limit
= points
+ hints
->num_points
;
601 /* compute coordinates & Bezier flags, next and prev */
603 FT_Vector
* vec
= outline
->points
;
604 char* tag
= outline
->tags
;
606 TA_Point end
= points
+ outline
->contours
[0];
609 FT_Int contour_index
= 0;
612 for (point
= points
; point
< point_limit
; point
++, vec
++, tag
++)
614 point
->fx
= (FT_Short
)vec
->x
;
615 point
->fy
= (FT_Short
)vec
->y
;
616 point
->ox
= point
->x
= FT_MulFix(vec
->x
, x_scale
) + x_delta
;
617 point
->oy
= point
->y
= FT_MulFix(vec
->y
, y_scale
) + y_delta
;
619 switch (FT_CURVE_TAG(*tag
))
621 case FT_CURVE_TAG_CONIC
:
622 point
->flags
= TA_FLAG_CONIC
;
624 case FT_CURVE_TAG_CUBIC
:
625 point
->flags
= TA_FLAG_CUBIC
;
628 point
->flags
= TA_FLAG_NONE
;
637 if (++contour_index
< outline
->n_contours
)
639 end
= points
+ outline
->contours
[contour_index
];
646 /* set up the contours array */
648 TA_Point
* contour
= hints
->contours
;
649 TA_Point
* contour_limit
= contour
+ hints
->num_contours
;
651 short* end
= outline
->contours
;
655 for (; contour
< contour_limit
; contour
++, end
++)
657 contour
[0] = points
+ idx
;
658 idx
= (short)(end
[0] + 1);
662 /* compute directions of in & out vectors */
664 TA_Point first
= points
;
665 TA_Point prev
= NULL
;
670 TA_Direction in_dir
= TA_DIR_NONE
;
672 FT_Pos last_good_in_x
= 0;
673 FT_Pos last_good_in_y
= 0;
675 FT_UInt units_per_em
= hints
->metrics
->scaler
.face
->units_per_EM
;
676 FT_Int near_limit
= 20 * units_per_em
/ 2048;
679 for (point
= points
; point
< point_limit
; point
++)
689 in_x
= first
->fx
- prev
->fx
;
690 in_y
= first
->fy
- prev
->fy
;
692 last_good_in_x
= in_x
;
693 last_good_in_y
= in_y
;
695 if (TA_ABS(in_x
) + TA_ABS(in_y
) < near_limit
)
697 /* search first non-near point to get a good `in_dir' value */
699 TA_Point point_
= prev
;
702 while (point_
!= first
)
704 TA_Point prev_
= point_
->prev
;
706 FT_Pos in_x_
= point_
->fx
- prev_
->fx
;
707 FT_Pos in_y_
= point_
->fy
- prev_
->fy
;
710 if (TA_ABS(in_x_
) + TA_ABS(in_y_
) >= near_limit
)
712 last_good_in_x
= in_x_
;
713 last_good_in_y
= in_y_
;
722 in_dir
= ta_direction_compute(in_x
, in_y
);
726 point
->in_dir
= (FT_Char
)in_dir
;
728 /* check whether the current point is near to the previous one */
729 /* (value 20 in `near_limit' is heuristic; we use Taxicab */
730 /* metrics for the test) */
732 if (TA_ABS(in_x
) + TA_ABS(in_y
) < near_limit
)
733 point
->flags
|= TA_FLAG_NEAR
;
736 last_good_in_x
= in_x
;
737 last_good_in_y
= in_y
;
741 out_x
= next
->fx
- point
->fx
;
742 out_y
= next
->fy
- point
->fy
;
744 in_dir
= ta_direction_compute(out_x
, out_y
);
745 point
->out_dir
= (FT_Char
)in_dir
;
747 /* Check for weak points. The remaining points not collected */
748 /* in edges are then implicitly classified as strong points. */
750 if (point
->flags
& TA_FLAG_CONTROL
)
752 /* control points are always weak */
754 point
->flags
|= TA_FLAG_WEAK_INTERPOLATION
;
756 else if (point
->out_dir
== point
->in_dir
)
758 if (point
->out_dir
!= TA_DIR_NONE
)
760 /* current point lies on a horizontal or */
761 /* vertical segment (but doesn't start or end it) */
765 /* test whether `in' and `out' direction is approximately */
766 /* the same (and use the last good `in' vector in case */
767 /* the current point is near to the previous one) */
768 if (ta_corner_is_flat(point
->flags
& TA_FLAG_NEAR
? last_good_in_x
770 point
->flags
& TA_FLAG_NEAR
? last_good_in_y
775 /* current point lies on a straight, diagonal line */
780 else if (point
->in_dir
== -point
->out_dir
)
782 /* current point forms a spike */
798 /* store the hinted outline in an FT_Outline structure */
801 ta_glyph_hints_save(TA_GlyphHints hints
,
804 TA_Point point
= hints
->points
;
805 TA_Point limit
= point
+ hints
->num_points
;
807 FT_Vector
* vec
= outline
->points
;
808 char* tag
= outline
->tags
;
811 for (; point
< limit
; point
++, vec
++, tag
++)
816 if (point
->flags
& TA_FLAG_CONIC
)
817 tag
[0] = FT_CURVE_TAG_CONIC
;
818 else if (point
->flags
& TA_FLAG_CUBIC
)
819 tag
[0] = FT_CURVE_TAG_CUBIC
;
821 tag
[0] = FT_CURVE_TAG_ON
;
826 /****************************************************************
828 * EDGE POINT GRID-FITTING
830 ****************************************************************/
833 /* align all points of an edge to the same coordinate value, */
834 /* either horizontally or vertically */
837 ta_glyph_hints_align_edge_points(TA_GlyphHints hints
,
840 TA_AxisHints axis
= &hints
->axis
[dim
];
841 TA_Segment segments
= axis
->segments
;
842 TA_Segment segment_limit
= segments
+ axis
->num_segments
;
846 if (dim
== TA_DIMENSION_HORZ
)
848 for (seg
= segments
; seg
< segment_limit
; seg
++)
850 TA_Edge edge
= seg
->edge
;
851 TA_Point point
, first
, last
;
862 point
->x
= edge
->pos
;
863 point
->flags
|= TA_FLAG_TOUCH_X
;
874 for (seg
= segments
; seg
< segment_limit
; seg
++)
876 TA_Edge edge
= seg
->edge
;
877 TA_Point point
, first
, last
;
888 point
->y
= edge
->pos
;
889 point
->flags
|= TA_FLAG_TOUCH_Y
;
901 /****************************************************************
903 * STRONG POINT INTERPOLATION
905 ****************************************************************/
908 /* hint the strong points -- */
909 /* this is equivalent to the TrueType `IP' hinting instruction */
912 ta_glyph_hints_align_strong_points(TA_GlyphHints hints
,
915 TA_Point points
= hints
->points
;
916 TA_Point point_limit
= points
+ hints
->num_points
;
918 TA_AxisHints axis
= &hints
->axis
[dim
];
920 TA_Edge edges
= axis
->edges
;
921 TA_Edge edge_limit
= edges
+ axis
->num_edges
;
923 FT_UShort touch_flag
;
926 if (dim
== TA_DIMENSION_HORZ
)
927 touch_flag
= TA_FLAG_TOUCH_X
;
929 touch_flag
= TA_FLAG_TOUCH_Y
;
931 if (edges
< edge_limit
)
937 for (point
= points
; point
< point_limit
; point
++)
939 FT_Pos u
, ou
, fu
; /* point position */
943 if (point
->flags
& touch_flag
)
946 /* if this point is candidate to weak interpolation, we */
947 /* interpolate it after all strong points have been processed */
949 if ((point
->flags
& TA_FLAG_WEAK_INTERPOLATION
)
950 && !(point
->flags
& TA_FLAG_INFLECTION
))
953 if (dim
== TA_DIMENSION_VERT
)
966 /* is the point before the first edge? */
968 delta
= edge
->fpos
- u
;
971 u
= edge
->pos
- (edge
->opos
- ou
);
974 hints
->recorder(ta_ip_before
, hints
, dim
,
975 point
, NULL
, NULL
, NULL
, NULL
);
980 /* is the point after the last edge? */
981 edge
= edge_limit
- 1;
982 delta
= u
- edge
->fpos
;
985 u
= edge
->pos
+ (ou
- edge
->opos
);
988 hints
->recorder(ta_ip_after
, hints
, dim
,
989 point
, NULL
, NULL
, NULL
, NULL
);
995 FT_PtrDist min
, max
, mid
;
999 /* find enclosing edges */
1001 max
= edge_limit
- edges
;
1003 /* for a small number of edges, a linear search is better */
1009 for (nn
= 0; nn
< max
; nn
++)
1010 if (edges
[nn
].fpos
>= u
)
1013 if (edges
[nn
].fpos
== u
)
1017 if (hints
->recorder
)
1018 hints
->recorder(ta_ip_on
, hints
, dim
,
1019 point
, &edges
[nn
], NULL
, NULL
, NULL
);
1028 mid
= (max
+ min
) >> 1;
1038 /* we are on the edge */
1041 if (hints
->recorder
)
1042 hints
->recorder(ta_ip_on
, hints
, dim
,
1043 point
, edge
, NULL
, NULL
, NULL
);
1049 /* point is not on an edge */
1051 TA_Edge before
= edges
+ min
- 1;
1052 TA_Edge after
= edges
+ min
+ 0;
1055 /* assert(before && after && before != after) */
1056 if (before
->scale
== 0)
1057 before
->scale
= FT_DivFix(after
->pos
- before
->pos
,
1058 after
->fpos
- before
->fpos
);
1060 u
= before
->pos
+ FT_MulFix(fu
- before
->fpos
,
1063 if (hints
->recorder
)
1064 hints
->recorder(ta_ip_between
, hints
, dim
,
1065 point
, before
, after
, NULL
, NULL
);
1070 /* save the point position */
1071 if (dim
== TA_DIMENSION_HORZ
)
1076 point
->flags
|= touch_flag
;
1082 /****************************************************************
1084 * WEAK POINT INTERPOLATION
1086 ****************************************************************/
1089 /* shift the original coordinates of all points between `p1' and */
1090 /* `p2' to get hinted coordinates, using the same difference as */
1091 /* given by `ref' */
1094 ta_iup_shift(TA_Point p1
,
1099 FT_Pos delta
= ref
->u
- ref
->v
;
1105 for (p
= p1
; p
< ref
; p
++)
1106 p
->u
= p
->v
+ delta
;
1108 for (p
= ref
+ 1; p
<= p2
; p
++)
1109 p
->u
= p
->v
+ delta
;
1113 /* interpolate the original coordinates of all points between `p1' and */
1114 /* `p2' to get hinted coordinates, using `ref1' and `ref2' as the */
1115 /* reference points; the `u' and `v' members are the current and */
1116 /* original coordinate values, respectively. */
1118 /* details can be found in the TrueType bytecode specification */
1121 ta_iup_interp(TA_Point p1
,
1128 FT_Pos v1
= ref1
->v
;
1129 FT_Pos v2
= ref2
->v
;
1130 FT_Pos d1
= ref1
->u
- v1
;
1131 FT_Pos d2
= ref2
->u
- v2
;
1139 for (p
= p1
; p
<= p2
; p
++)
1155 for (p
= p1
; p
<= p2
; p
++)
1164 u
= ref1
->u
+ FT_MulDiv(u
- v1
, ref2
->u
- ref1
->u
, v2
- v1
);
1171 for (p
= p1
; p
<= p2
; p
++)
1180 u
= ref1
->u
+ FT_MulDiv(u
- v1
, ref2
->u
- ref1
->u
, v2
- v1
);
1188 /* hint the weak points -- */
1189 /* this is equivalent to the TrueType `IUP' hinting instruction */
1192 ta_glyph_hints_align_weak_points(TA_GlyphHints hints
,
1195 TA_Point points
= hints
->points
;
1196 TA_Point point_limit
= points
+ hints
->num_points
;
1198 TA_Point
* contour
= hints
->contours
;
1199 TA_Point
* contour_limit
= contour
+ hints
->num_contours
;
1201 FT_UShort touch_flag
;
1204 TA_Point first_point
;
1207 /* pass 1: move segment points to edge positions */
1209 if (dim
== TA_DIMENSION_HORZ
)
1211 touch_flag
= TA_FLAG_TOUCH_X
;
1213 for (point
= points
; point
< point_limit
; point
++)
1215 point
->u
= point
->x
;
1216 point
->v
= point
->ox
;
1221 touch_flag
= TA_FLAG_TOUCH_Y
;
1223 for (point
= points
; point
< point_limit
; point
++)
1225 point
->u
= point
->y
;
1226 point
->v
= point
->oy
;
1232 for (; contour
< contour_limit
; contour
++)
1234 TA_Point first_touched
, last_touched
;
1238 end_point
= point
->prev
;
1239 first_point
= point
;
1241 /* find first touched point */
1244 if (point
> end_point
) /* no touched point in contour */
1247 if (point
->flags
& touch_flag
)
1253 first_touched
= point
;
1254 last_touched
= point
;
1258 /* skip any touched neighbours */
1259 while (point
< end_point
1260 && (point
[1].flags
& touch_flag
) != 0)
1263 last_touched
= point
;
1265 /* find the next touched point, if any */
1269 if (point
> end_point
)
1272 if ((point
->flags
& touch_flag
) != 0)
1278 /* interpolate between last_touched and point */
1279 ta_iup_interp(last_touched
+ 1, point
- 1,
1280 last_touched
, point
);
1284 /* special case: only one point was touched */
1285 if (last_touched
== first_touched
)
1286 ta_iup_shift(first_point
, end_point
, first_touched
);
1288 else /* interpolate the last part */
1290 if (last_touched
< end_point
)
1291 ta_iup_interp(last_touched
+ 1, end_point
,
1292 last_touched
, first_touched
);
1294 if (first_touched
> points
)
1295 ta_iup_interp(first_point
, first_touched
- 1,
1296 last_touched
, first_touched
);
1303 /* now save the interpolated values back to x/y */
1304 if (dim
== TA_DIMENSION_HORZ
)
1306 for (point
= points
; point
< point_limit
; point
++)
1307 point
->x
= point
->u
;
1311 for (point
= points
; point
< point_limit
; point
++)
1312 point
->y
= point
->u
;
1317 #ifdef TA_CONFIG_OPTION_USE_WARPER
1319 /* apply (small) warp scale and warp delta for given dimension */
1322 ta_glyph_hints_scale_dim(TA_GlyphHints hints
,
1327 TA_Point points
= hints
->points
;
1328 TA_Point points_limit
= points
+ hints
->num_points
;
1332 if (dim
== TA_DIMENSION_HORZ
)
1334 for (point
= points
; point
< points_limit
; point
++)
1335 point
->x
= FT_MulFix(point
->fx
, scale
) + delta
;
1339 for (point
= points
; point
< points_limit
; point
++)
1340 point
->y
= FT_MulFix(point
->fy
, scale
) + delta
;
1344 #endif /* TA_CONFIG_OPTION_USE_WARPER */
1346 /* end of tahints.c */