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> */
27 /* get new segment for given axis */
30 ta_axis_hints_new_segment(TA_AxisHints axis
,
33 FT_Error error
= FT_Err_Ok
;
34 TA_Segment segment
= NULL
;
37 if (axis
->num_segments
>= axis
->max_segments
)
39 TA_Segment segments_new
;
41 FT_Int old_max
= axis
->max_segments
;
42 FT_Int new_max
= old_max
;
43 FT_Int big_max
= (FT_Int
)(FT_INT_MAX
/ sizeof (*segment
));
46 if (old_max
>= big_max
)
48 error
= FT_Err_Out_Of_Memory
;
52 new_max
+= (new_max
>> 2) + 4;
57 segments_new
= (TA_Segment
)realloc(axis
->segments
,
58 new_max
* sizeof (TA_SegmentRec
));
60 return FT_Err_Out_Of_Memory
;
62 axis
->segments
= segments_new
;
63 axis
->max_segments
= new_max
;
66 segment
= axis
->segments
+ axis
->num_segments
++;
74 /* get new edge for given axis, direction, and position, */
75 /* without initializing the edge itself */
78 ta_axis_hints_new_edge(TA_AxisHints axis
,
83 FT_Error error
= FT_Err_Ok
;
88 if (axis
->num_edges
>= axis
->max_edges
)
92 FT_Int old_max
= axis
->max_edges
;
93 FT_Int new_max
= old_max
;
94 FT_Int big_max
= (FT_Int
)(FT_INT_MAX
/ sizeof (*edge
));
97 if (old_max
>= big_max
)
99 error
= FT_Err_Out_Of_Memory
;
103 new_max
+= (new_max
>> 2) + 4;
104 if (new_max
< old_max
105 || new_max
> big_max
)
108 edges_new
= (TA_Edge
)realloc(axis
->edges
,
109 new_max
* sizeof (TA_EdgeRec
));
111 return FT_Err_Out_Of_Memory
;
113 axis
->edges
= edges_new
;
114 axis
->max_edges
= new_max
;
118 edge
= edges
+ axis
->num_edges
;
122 if (edge
[-1].fpos
< fpos
)
125 /* we want the edge with same position and minor direction */
126 /* to appear before those in the major one in the list */
127 if (edge
[-1].fpos
== fpos
128 && dir
== axis
->major_dir
)
151 _ta_message(const char* format
,
157 va_start(ap
, format
);
158 vfprintf(stderr
, format
, ap
);
164 ta_dir_str(TA_Direction dir
)
191 #define TA_INDEX_NUM(ptr, base) \
192 ((ptr) ? ((ptr) - (base)) \
197 ta_glyph_hints_dump_points(TA_GlyphHints hints
)
199 TA_Point points
= hints
->points
;
200 TA_Point limit
= points
+ hints
->num_points
;
204 TA_LOG(("Table of points:\n"
205 " [ index | xorg | yorg | xscale | yscale"
206 " | xfit | yfit | flags ]\n"));
208 for (point
= points
; point
< limit
; point
++)
209 TA_LOG((" [ %5d | %5d | %5d | %6.2f | %6.2f"
210 " | %5.2f | %5.2f | %c ]\n",
218 (point
->flags
& TA_FLAG_WEAK_INTERPOLATION
) ? 'w' : ' '));
224 ta_edge_flags_to_string(FT_Byte flags
)
226 static char temp
[32];
230 if (flags
& TA_EDGE_ROUND
)
232 memcpy(temp
+ pos
, "round", 5);
235 if (flags
& TA_EDGE_SERIF
)
239 memcpy(temp
+ pos
, "serif", 5);
251 /* dump the array of linked segments */
254 ta_glyph_hints_dump_segments(TA_GlyphHints hints
)
259 for (dimension
= TA_DEBUG_STARTDIM
;
260 dimension
>= TA_DEBUG_ENDDIM
;
263 TA_AxisHints axis
= &hints
->axis
[dimension
];
264 TA_Point points
= hints
->points
;
265 TA_Edge edges
= axis
->edges
;
266 TA_Segment segments
= axis
->segments
;
267 TA_Segment limit
= segments
+ axis
->num_segments
;
271 TA_LOG(("Table of %s segments:\n",
272 dimension
== TA_DIMENSION_HORZ
? "vertical"
274 if (axis
->num_segments
)
275 TA_LOG((" [ index | pos | dir | from"
276 " | to | link | serif | edge"
277 " | height | extra | flags ]\n"));
279 TA_LOG((" (none)\n"));
281 for (seg
= segments
; seg
< limit
; seg
++)
282 TA_LOG((" [ %5d | %5.2g | %5s | %4d"
283 " | %4d | %4d | %5d | %4d"
284 " | %6d | %5d | %11s ]\n",
286 dimension
== TA_DIMENSION_HORZ
? (int)seg
->first
->ox
/ 64.0
287 : (int)seg
->first
->oy
/ 64.0,
288 ta_dir_str((TA_Direction
)seg
->dir
),
289 TA_INDEX_NUM(seg
->first
, points
),
290 TA_INDEX_NUM(seg
->last
, points
),
291 TA_INDEX_NUM(seg
->link
, segments
),
292 TA_INDEX_NUM(seg
->serif
, segments
),
293 TA_INDEX_NUM(seg
->edge
, edges
),
295 seg
->height
- (seg
->max_coord
- seg
->min_coord
),
296 ta_edge_flags_to_string(seg
->flags
)));
302 /* dump the array of linked edges */
305 ta_glyph_hints_dump_edges(TA_GlyphHints hints
)
310 for (dimension
= TA_DEBUG_STARTDIM
;
311 dimension
>= TA_DEBUG_ENDDIM
;
314 TA_AxisHints axis
= &hints
->axis
[dimension
];
315 TA_Edge edges
= axis
->edges
;
316 TA_Edge limit
= edges
+ axis
->num_edges
;
320 /* note that TA_DIMENSION_HORZ corresponds to _vertical_ edges */
321 /* since they have a constant X coordinate */
322 TA_LOG(("Table of %s edges:\n",
323 dimension
== TA_DIMENSION_HORZ
? "vertical"
326 TA_LOG((" [ index | pos | dir | link"
327 " | serif | blue | opos | pos | flags ]\n"));
329 TA_LOG((" (none)\n"));
331 for (edge
= edges
; edge
< limit
; edge
++)
332 TA_LOG((" [ %5d | %5.2g | %5s | %4d"
333 " | %5d | %c | %5.2f | %5.2f | %11s ]\n",
335 (int)edge
->opos
/ 64.0,
336 ta_dir_str((TA_Direction
)edge
->dir
),
337 TA_INDEX_NUM(edge
->link
, edges
),
338 TA_INDEX_NUM(edge
->serif
, edges
),
339 edge
->blue_edge
? 'y' : 'n',
342 ta_edge_flags_to_string(edge
->flags
)));
347 #endif /* TA_DEBUG */
350 /* compute the direction value of a given vector */
353 ta_direction_compute(FT_Pos dx
,
356 FT_Pos ll
, ss
; /* long and short arm lengths */
357 TA_Direction dir
; /* candidate direction */
391 /* return no direction if arm lengths differ too much */
392 /* (value 14 is heuristic, corresponding to approx. 4.1 degrees) */
394 if (TA_ABS(ll
) <= TA_ABS(ss
))
402 ta_glyph_hints_init(TA_GlyphHints hints
)
404 memset(hints
, 0, sizeof (TA_GlyphHintsRec
));
409 ta_glyph_hints_done(TA_GlyphHints hints
)
417 /* we don't need to free the segment and edge buffers */
418 /* since they are really within the hints->points array */
419 for (dim
= 0; dim
< TA_DIMENSION_MAX
; dim
++)
421 TA_AxisHints axis
= &hints
->axis
[dim
];
424 axis
->num_segments
= 0;
425 axis
->max_segments
= 0;
426 free(axis
->segments
);
427 axis
->segments
= NULL
;
435 free(hints
->contours
);
436 hints
->contours
= NULL
;
437 hints
->max_contours
= 0;
438 hints
->num_contours
= 0;
441 hints
->points
= NULL
;
442 hints
->num_points
= 0;
443 hints
->max_points
= 0;
450 ta_glyph_hints_rescale(TA_GlyphHints hints
,
451 TA_StyleMetrics metrics
)
453 hints
->metrics
= metrics
;
454 hints
->scaler_flags
= metrics
->scaler
.flags
;
458 /* from FreeType's ftcalc.c */
461 ta_corner_is_flat(FT_Pos in_x
,
469 FT_Pos d_in
, d_out
, d_corner
;
494 return (d_in
+ d_out
- d_corner
) < (d_corner
>> 4);
498 /* recompute all TA_Point in TA_GlyphHints */
499 /* from the definitions in a source outline */
502 ta_glyph_hints_reload(TA_GlyphHints hints
,
505 FT_Error error
= FT_Err_Ok
;
507 FT_UInt old_max
, new_max
;
509 FT_Fixed x_scale
= hints
->x_scale
;
510 FT_Fixed y_scale
= hints
->y_scale
;
511 FT_Pos x_delta
= hints
->x_delta
;
512 FT_Pos y_delta
= hints
->y_delta
;
515 hints
->num_points
= 0;
516 hints
->num_contours
= 0;
518 hints
->axis
[0].num_segments
= 0;
519 hints
->axis
[0].num_edges
= 0;
520 hints
->axis
[1].num_segments
= 0;
521 hints
->axis
[1].num_edges
= 0;
523 /* first of all, reallocate the contours array if necessary */
524 new_max
= (FT_UInt
)outline
->n_contours
;
525 old_max
= hints
->max_contours
;
526 if (new_max
> old_max
)
528 TA_Point
* contours_new
;
531 new_max
= (new_max
+ 3) & ~3; /* round up to a multiple of 4 */
533 contours_new
= (TA_Point
*)realloc(hints
->contours
,
534 new_max
* sizeof (TA_Point
));
536 return FT_Err_Out_Of_Memory
;
538 hints
->contours
= contours_new
;
539 hints
->max_contours
= new_max
;
542 /* reallocate the points arrays if necessary -- we reserve */
543 /* two additional point positions, used to hint metrics appropriately */
544 new_max
= (FT_UInt
)(outline
->n_points
+ 2);
545 old_max
= hints
->max_points
;
546 if (new_max
> old_max
)
551 new_max
= (new_max
+ 2 + 7) & ~7; /* round up to a multiple of 8 */
553 points_new
= (TA_Point
)realloc(hints
->points
,
554 new_max
* sizeof (TA_PointRec
));
556 return FT_Err_Out_Of_Memory
;
558 hints
->points
= points_new
;
559 hints
->max_points
= new_max
;
562 hints
->num_points
= outline
->n_points
;
563 hints
->num_contours
= outline
->n_contours
;
565 /* we can't rely on the value of `FT_Outline.flags' to know the fill */
566 /* direction used for a glyph, given that some fonts are broken */
567 /* (e.g. the Arphic ones); we thus recompute it each time we need to */
569 hints
->axis
[TA_DIMENSION_HORZ
].major_dir
= TA_DIR_UP
;
570 hints
->axis
[TA_DIMENSION_VERT
].major_dir
= TA_DIR_LEFT
;
572 if (FT_Outline_Get_Orientation(outline
) == FT_ORIENTATION_POSTSCRIPT
)
574 hints
->axis
[TA_DIMENSION_HORZ
].major_dir
= TA_DIR_DOWN
;
575 hints
->axis
[TA_DIMENSION_VERT
].major_dir
= TA_DIR_RIGHT
;
578 hints
->x_scale
= x_scale
;
579 hints
->y_scale
= y_scale
;
580 hints
->x_delta
= x_delta
;
581 hints
->y_delta
= y_delta
;
583 hints
->xmin_delta
= 0;
584 hints
->xmax_delta
= 0;
586 points
= hints
->points
;
587 if (hints
->num_points
== 0)
592 TA_Point point_limit
= points
+ hints
->num_points
;
595 /* compute coordinates & Bezier flags, next and prev */
597 FT_Vector
* vec
= outline
->points
;
598 char* tag
= outline
->tags
;
600 TA_Point end
= points
+ outline
->contours
[0];
603 FT_Int contour_index
= 0;
606 for (point
= points
; point
< point_limit
; point
++, vec
++, tag
++)
608 point
->in_dir
= (FT_Char
)TA_DIR_NONE
;
609 point
->out_dir
= (FT_Char
)TA_DIR_NONE
;
611 point
->fx
= (FT_Short
)vec
->x
;
612 point
->fy
= (FT_Short
)vec
->y
;
613 point
->ox
= point
->x
= FT_MulFix(vec
->x
, x_scale
) + x_delta
;
614 point
->oy
= point
->y
= FT_MulFix(vec
->y
, y_scale
) + y_delta
;
616 switch (FT_CURVE_TAG(*tag
))
618 case FT_CURVE_TAG_CONIC
:
619 point
->flags
= TA_FLAG_CONIC
;
621 case FT_CURVE_TAG_CUBIC
:
622 point
->flags
= TA_FLAG_CUBIC
;
625 point
->flags
= TA_FLAG_NONE
;
634 if (++contour_index
< outline
->n_contours
)
636 end
= points
+ outline
->contours
[contour_index
];
643 /* set up the contours array */
645 TA_Point
* contour
= hints
->contours
;
646 TA_Point
* contour_limit
= contour
+ hints
->num_contours
;
648 short* end
= outline
->contours
;
652 for (; contour
< contour_limit
; contour
++, end
++)
654 contour
[0] = points
+ idx
;
655 idx
= (short)(end
[0] + 1);
661 * Compute directions of `in' and `out' vectors.
663 * Note that distances between points that are very near to each
664 * other are accumulated. In other words, the auto-hinter
665 * prepends the small vectors between near points to the first
666 * non-near vector. All intermediate points are tagged as
667 * weak; the directions are adjusted also to be equal to the
671 /* value 20 in `near_limit' is heuristic */
672 FT_UInt units_per_em
= hints
->metrics
->scaler
.face
->units_per_EM
;
673 FT_Int near_limit
= 20 * units_per_em
/ 2048;
674 FT_Int near_limit2
= 2 * near_limit
- 1;
677 TA_Point
* contour_limit
= hints
->contours
+ hints
->num_contours
;
680 for (contour
= hints
->contours
; contour
< contour_limit
; contour
++)
682 TA_Point first
= *contour
;
683 TA_Point next
, prev
, curr
;
690 /* since the first point of a contour could be part of a */
691 /* series of near points, go backwards to find the first */
692 /* non-near point and adjust `first' */
697 while (prev
!= first
)
699 out_x
= point
->fx
- prev
->fx
;
700 out_y
= point
->fy
- prev
->fy
;
703 * We use Taxicab metrics to measure the vector length.
705 * Note that the accumulated distances so far could have the
706 * opposite direction of the distance measured here. For this
707 * reason we use `near_limit2' for the comparison to get a
708 * non-near point even in the worst case.
710 if (TA_ABS(out_x
) + TA_ABS(out_y
) >= near_limit2
)
717 /* adjust first point */
720 /* now loop over all points of the contour to get */
721 /* `in' and `out' vector directions */
726 * We abuse the `u' and `v' fields to store index deltas to the
727 * next and previous non-near point, respectively.
729 * To avoid problems with not having non-near points, we point to
730 * `first' by default as the next non-near point.
732 curr
->u
= (FT_Pos
)(first
- curr
);
741 point
!= first
|| is_first
;
744 TA_Direction out_dir
;
751 out_x
+= next
->fx
- point
->fx
;
752 out_y
+= next
->fy
- point
->fy
;
754 if (TA_ABS(out_x
) + TA_ABS(out_y
) < near_limit
)
756 next
->flags
|= TA_FLAG_WEAK_INTERPOLATION
;
760 curr
->u
= (FT_Pos
)(next
- curr
);
763 out_dir
= ta_direction_compute(out_x
, out_y
);
765 /* adjust directions for all points inbetween; */
766 /* the loop also updates position of `curr' */
767 curr
->out_dir
= (FT_Char
)out_dir
;
768 for (curr
= curr
->next
; curr
!= next
; curr
= curr
->next
)
770 curr
->in_dir
= (FT_Char
)out_dir
;
771 curr
->out_dir
= (FT_Char
)out_dir
;
773 next
->in_dir
= (FT_Char
)out_dir
;
775 curr
->u
= (FT_Pos
)(first
- curr
);
784 * The next step is to `simplify' an outline's topology so that we
785 * can identify local extrema more reliably: A series of
786 * non-horizontal or non-vertical vectors pointing into the same
787 * quadrant are handled as a single, long vector. From a
788 * topological point of the view, the intermediate points are of no
789 * interest and thus tagged as weak.
792 for (point
= points
; point
< point_limit
; point
++)
794 if (point
->flags
& TA_FLAG_WEAK_INTERPOLATION
)
797 if (point
->in_dir
== TA_DIR_NONE
798 && point
->out_dir
== TA_DIR_NONE
)
800 /* check whether both vectors point into the same quadrant */
805 TA_Point next_u
= point
+ point
->u
;
806 TA_Point prev_v
= point
+ point
->v
;
809 in_x
= point
->fx
- prev_v
->fx
;
810 in_y
= point
->fy
- prev_v
->fy
;
812 out_x
= next_u
->fx
- point
->fx
;
813 out_y
= next_u
->fy
- point
->fy
;
815 if ((in_x
^ out_x
) >= 0 && (in_y
^ out_y
) >= 0)
817 /* yes, so tag current point as weak */
818 /* and update index deltas */
820 point
->flags
|= TA_FLAG_WEAK_INTERPOLATION
;
822 prev_v
->u
= (FT_Pos
)(next_u
- prev_v
);
823 next_u
->v
= -prev_v
->u
;
829 * Finally, check for remaining weak points. Everything else not
830 * collected in edges so far is then implicitly classified as strong
834 for (point
= points
; point
< point_limit
; point
++)
836 if (point
->flags
& TA_FLAG_WEAK_INTERPOLATION
)
839 if (point
->flags
& TA_FLAG_CONTROL
)
841 /* control points are always weak */
843 point
->flags
|= TA_FLAG_WEAK_INTERPOLATION
;
845 else if (point
->out_dir
== point
->in_dir
)
847 if (point
->out_dir
!= TA_DIR_NONE
)
849 /* current point lies on a horizontal or */
850 /* vertical segment (but doesn't start or end it) */
855 TA_Point next_u
= point
+ point
->u
;
856 TA_Point prev_v
= point
+ point
->v
;
859 if (ta_corner_is_flat(point
->fx
- prev_v
->fx
,
860 point
->fy
- prev_v
->fy
,
861 next_u
->fx
- point
->fx
,
862 next_u
->fy
- point
->fy
))
864 /* either the `in' or the `out' vector is much more */
865 /* dominant than the other one, so tag current point */
866 /* as weak and update index deltas */
868 prev_v
->u
= (FT_Pos
)(next_u
- prev_v
);
869 next_u
->v
= -prev_v
->u
;
875 else if (point
->in_dir
== -point
->out_dir
)
877 /* current point forms a spike */
884 /* change some directions at the user's request */
885 /* to make ttfautohint insert one-point segments */
886 /* or remove points from segments */
893 /* `globals' is not set up while initializing metrics, */
894 /* so exit early in this case */
895 if (!hints
->metrics
->globals
)
898 font
= hints
->metrics
->globals
->font
;
900 /* start conditions are set with `TA_control_point_dir_collect' */
901 while (TA_control_point_dir_get_next(font
, &idx
, &dir
))
903 TA_Point point
= &points
[idx
];
906 point
->out_dir
= dir
;
907 if (dir
== TA_DIR_NONE
)
908 point
->flags
|= TA_FLAG_WEAK_INTERPOLATION
;
910 point
->flags
&= ~TA_FLAG_WEAK_INTERPOLATION
;
919 /* store the hinted outline in an FT_Outline structure */
922 ta_glyph_hints_save(TA_GlyphHints hints
,
925 TA_Point point
= hints
->points
;
926 TA_Point limit
= point
+ hints
->num_points
;
928 FT_Vector
* vec
= outline
->points
;
929 char* tag
= outline
->tags
;
932 for (; point
< limit
; point
++, vec
++, tag
++)
937 if (point
->flags
& TA_FLAG_CONIC
)
938 tag
[0] = FT_CURVE_TAG_CONIC
;
939 else if (point
->flags
& TA_FLAG_CUBIC
)
940 tag
[0] = FT_CURVE_TAG_CUBIC
;
942 tag
[0] = FT_CURVE_TAG_ON
;
947 /****************************************************************
949 * EDGE POINT GRID-FITTING
951 ****************************************************************/
954 /* align all points of an edge to the same coordinate value, */
955 /* either horizontally or vertically */
958 ta_glyph_hints_align_edge_points(TA_GlyphHints hints
,
961 TA_AxisHints axis
= &hints
->axis
[dim
];
962 TA_Segment segments
= axis
->segments
;
963 TA_Segment segment_limit
= segments
+ axis
->num_segments
;
967 if (dim
== TA_DIMENSION_HORZ
)
969 for (seg
= segments
; seg
< segment_limit
; seg
++)
971 TA_Edge edge
= seg
->edge
;
972 TA_Point point
, first
, last
;
983 point
->x
= edge
->pos
;
984 point
->flags
|= TA_FLAG_TOUCH_X
;
995 for (seg
= segments
; seg
< segment_limit
; seg
++)
997 TA_Edge edge
= seg
->edge
;
998 TA_Point point
, first
, last
;
1009 point
->y
= edge
->pos
;
1010 point
->flags
|= TA_FLAG_TOUCH_Y
;
1015 point
= point
->next
;
1022 /****************************************************************
1024 * STRONG POINT INTERPOLATION
1026 ****************************************************************/
1029 /* hint the strong points -- */
1030 /* this is equivalent to the TrueType `IP' hinting instruction */
1033 ta_glyph_hints_align_strong_points(TA_GlyphHints hints
,
1036 TA_Point points
= hints
->points
;
1037 TA_Point point_limit
= points
+ hints
->num_points
;
1039 TA_AxisHints axis
= &hints
->axis
[dim
];
1041 TA_Edge edges
= axis
->edges
;
1042 TA_Edge edge_limit
= edges
+ axis
->num_edges
;
1044 FT_UShort touch_flag
;
1047 if (dim
== TA_DIMENSION_HORZ
)
1048 touch_flag
= TA_FLAG_TOUCH_X
;
1050 touch_flag
= TA_FLAG_TOUCH_Y
;
1052 if (edges
< edge_limit
)
1058 for (point
= points
; point
< point_limit
; point
++)
1060 FT_Pos u
, ou
, fu
; /* point position */
1064 if (point
->flags
& touch_flag
)
1067 /* if this point is candidate to weak interpolation, we */
1068 /* interpolate it after all strong points have been processed */
1070 if ((point
->flags
& TA_FLAG_WEAK_INTERPOLATION
))
1073 if (dim
== TA_DIMENSION_VERT
)
1086 /* is the point before the first edge? */
1088 delta
= edge
->fpos
- u
;
1091 u
= edge
->pos
- (edge
->opos
- ou
);
1093 if (hints
->recorder
)
1094 hints
->recorder(ta_ip_before
, hints
, dim
,
1095 point
, NULL
, NULL
, NULL
, NULL
);
1100 /* is the point after the last edge? */
1101 edge
= edge_limit
- 1;
1102 delta
= u
- edge
->fpos
;
1105 u
= edge
->pos
+ (ou
- edge
->opos
);
1107 if (hints
->recorder
)
1108 hints
->recorder(ta_ip_after
, hints
, dim
,
1109 point
, NULL
, NULL
, NULL
, NULL
);
1115 FT_PtrDist min
, max
, mid
;
1119 /* find enclosing edges */
1121 max
= edge_limit
- edges
;
1123 /* for a small number of edges, a linear search is better */
1129 for (nn
= 0; nn
< max
; nn
++)
1130 if (edges
[nn
].fpos
>= u
)
1133 if (edges
[nn
].fpos
== u
)
1137 if (hints
->recorder
)
1138 hints
->recorder(ta_ip_on
, hints
, dim
,
1139 point
, &edges
[nn
], NULL
, NULL
, NULL
);
1148 mid
= (max
+ min
) >> 1;
1158 /* we are on the edge */
1161 if (hints
->recorder
)
1162 hints
->recorder(ta_ip_on
, hints
, dim
,
1163 point
, edge
, NULL
, NULL
, NULL
);
1169 /* point is not on an edge */
1171 TA_Edge before
= edges
+ min
- 1;
1172 TA_Edge after
= edges
+ min
+ 0;
1175 /* assert(before && after && before != after) */
1176 if (before
->scale
== 0)
1177 before
->scale
= FT_DivFix(after
->pos
- before
->pos
,
1178 after
->fpos
- before
->fpos
);
1180 u
= before
->pos
+ FT_MulFix(fu
- before
->fpos
,
1183 if (hints
->recorder
)
1184 hints
->recorder(ta_ip_between
, hints
, dim
,
1185 point
, before
, after
, NULL
, NULL
);
1190 /* save the point position */
1191 if (dim
== TA_DIMENSION_HORZ
)
1196 point
->flags
|= touch_flag
;
1202 /****************************************************************
1204 * WEAK POINT INTERPOLATION
1206 ****************************************************************/
1209 /* shift the original coordinates of all points between `p1' and */
1210 /* `p2' to get hinted coordinates, using the same difference as */
1211 /* given by `ref' */
1214 ta_iup_shift(TA_Point p1
,
1219 FT_Pos delta
= ref
->u
- ref
->v
;
1225 for (p
= p1
; p
< ref
; p
++)
1226 p
->u
= p
->v
+ delta
;
1228 for (p
= ref
+ 1; p
<= p2
; p
++)
1229 p
->u
= p
->v
+ delta
;
1233 /* interpolate the original coordinates of all points between `p1' and */
1234 /* `p2' to get hinted coordinates, using `ref1' and `ref2' as the */
1235 /* reference points; the `u' and `v' members are the current and */
1236 /* original coordinate values, respectively. */
1238 /* details can be found in the TrueType bytecode specification */
1241 ta_iup_interp(TA_Point p1
,
1248 FT_Pos v1
= ref1
->v
;
1249 FT_Pos v2
= ref2
->v
;
1250 FT_Pos d1
= ref1
->u
- v1
;
1251 FT_Pos d2
= ref2
->u
- v2
;
1259 for (p
= p1
; p
<= p2
; p
++)
1275 for (p
= p1
; p
<= p2
; p
++)
1284 u
= ref1
->u
+ FT_MulDiv(u
- v1
, ref2
->u
- ref1
->u
, v2
- v1
);
1291 for (p
= p1
; p
<= p2
; p
++)
1300 u
= ref1
->u
+ FT_MulDiv(u
- v1
, ref2
->u
- ref1
->u
, v2
- v1
);
1308 /* hint the weak points -- */
1309 /* this is equivalent to the TrueType `IUP' hinting instruction */
1312 ta_glyph_hints_align_weak_points(TA_GlyphHints hints
,
1315 TA_Point points
= hints
->points
;
1316 TA_Point point_limit
= points
+ hints
->num_points
;
1318 TA_Point
* contour
= hints
->contours
;
1319 TA_Point
* contour_limit
= contour
+ hints
->num_contours
;
1321 FT_UShort touch_flag
;
1324 TA_Point first_point
;
1327 /* pass 1: move segment points to edge positions */
1329 if (dim
== TA_DIMENSION_HORZ
)
1331 touch_flag
= TA_FLAG_TOUCH_X
;
1333 for (point
= points
; point
< point_limit
; point
++)
1335 point
->u
= point
->x
;
1336 point
->v
= point
->ox
;
1341 touch_flag
= TA_FLAG_TOUCH_Y
;
1343 for (point
= points
; point
< point_limit
; point
++)
1345 point
->u
= point
->y
;
1346 point
->v
= point
->oy
;
1350 for (; contour
< contour_limit
; contour
++)
1352 TA_Point first_touched
, last_touched
;
1356 end_point
= point
->prev
;
1357 first_point
= point
;
1359 /* find first touched point */
1362 if (point
> end_point
) /* no touched point in contour */
1365 if (point
->flags
& touch_flag
)
1371 first_touched
= point
;
1375 /* skip any touched neighbours */
1376 while (point
< end_point
1377 && (point
[1].flags
& touch_flag
) != 0)
1380 last_touched
= point
;
1382 /* find the next touched point, if any */
1386 if (point
> end_point
)
1389 if ((point
->flags
& touch_flag
) != 0)
1395 /* interpolate between last_touched and point */
1396 ta_iup_interp(last_touched
+ 1, point
- 1,
1397 last_touched
, point
);
1401 /* special case: only one point was touched */
1402 if (last_touched
== first_touched
)
1403 ta_iup_shift(first_point
, end_point
, first_touched
);
1405 else /* interpolate the last part */
1407 if (last_touched
< end_point
)
1408 ta_iup_interp(last_touched
+ 1, end_point
,
1409 last_touched
, first_touched
);
1411 if (first_touched
> points
)
1412 ta_iup_interp(first_point
, first_touched
- 1,
1413 last_touched
, first_touched
);
1420 /* now save the interpolated values back to x/y */
1421 if (dim
== TA_DIMENSION_HORZ
)
1423 for (point
= points
; point
< point_limit
; point
++)
1424 point
->x
= point
->u
;
1428 for (point
= points
; point
< point_limit
; point
++)
1429 point
->y
= point
->u
;
1434 #ifdef TA_CONFIG_OPTION_USE_WARPER
1436 /* apply (small) warp scale and warp delta for given dimension */
1439 ta_glyph_hints_scale_dim(TA_GlyphHints hints
,
1444 TA_Point points
= hints
->points
;
1445 TA_Point points_limit
= points
+ hints
->num_points
;
1449 if (dim
== TA_DIMENSION_HORZ
)
1451 for (point
= points
; point
< points_limit
; point
++)
1452 point
->x
= FT_MulFix(point
->fx
, scale
) + delta
;
1456 for (point
= points
; point
< points_limit
; point
++)
1457 point
->y
= FT_MulFix(point
->fy
, scale
) + delta
;
1461 #endif /* TA_CONFIG_OPTION_USE_WARPER */
1463 /* end of tahints.c */