4 * Copyright (C) 2011-2015 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
< TA_SEGMENTS_EMBEDDED
)
39 if (axis
->segments
== NULL
)
41 axis
->segments
= axis
->embedded
.segments
;
42 axis
->max_segments
= TA_SEGMENTS_EMBEDDED
;
45 else if (axis
->num_segments
>= axis
->max_segments
)
47 TA_Segment segments_new
;
49 FT_Int old_max
= axis
->max_segments
;
50 FT_Int new_max
= old_max
;
51 FT_Int big_max
= (FT_Int
)(FT_INT_MAX
/ sizeof (*segment
));
54 if (old_max
>= big_max
)
56 error
= FT_Err_Out_Of_Memory
;
60 new_max
+= (new_max
>> 2) + 4;
65 if (axis
->segments
== axis
->embedded
.segments
)
67 axis
->segments
= (TA_Segment
)malloc(new_max
* sizeof (TA_SegmentRec
));
69 return FT_Err_Out_Of_Memory
;
71 memcpy(axis
->segments
, axis
->embedded
.segments
,
72 sizeof (axis
->embedded
.segments
));
76 segments_new
= (TA_Segment
)realloc(axis
->segments
,
77 new_max
* sizeof (TA_SegmentRec
));
79 return FT_Err_Out_Of_Memory
;
80 axis
->segments
= segments_new
;
83 axis
->max_segments
= new_max
;
86 segment
= axis
->segments
+ axis
->num_segments
++;
94 /* get new edge for given axis, direction, and position, */
95 /* without initializing the edge itself */
98 ta_axis_hints_new_edge(TA_AxisHints axis
,
103 FT_Error error
= FT_Err_Ok
;
108 if (axis
->num_edges
< TA_EDGES_EMBEDDED
)
110 if (axis
->edges
== NULL
)
112 axis
->edges
= axis
->embedded
.edges
;
113 axis
->max_edges
= TA_EDGES_EMBEDDED
;
116 else if (axis
->num_edges
>= axis
->max_edges
)
120 FT_Int old_max
= axis
->max_edges
;
121 FT_Int new_max
= old_max
;
122 FT_Int big_max
= (FT_Int
)(FT_INT_MAX
/ sizeof (*edge
));
125 if (old_max
>= big_max
)
127 error
= FT_Err_Out_Of_Memory
;
131 new_max
+= (new_max
>> 2) + 4;
132 if (new_max
< old_max
133 || new_max
> big_max
)
136 if (axis
->edges
== axis
->embedded
.edges
)
138 axis
->edges
= (TA_Edge
)malloc(new_max
* sizeof (TA_EdgeRec
));
140 return FT_Err_Out_Of_Memory
;
142 memcpy(axis
->edges
, axis
->embedded
.edges
,
143 sizeof (axis
->embedded
.edges
));
147 edges_new
= (TA_Edge
)realloc(axis
->edges
,
148 new_max
* sizeof (TA_EdgeRec
));
150 return FT_Err_Out_Of_Memory
;
151 axis
->edges
= edges_new
;
154 axis
->max_edges
= new_max
;
158 edge
= edges
+ axis
->num_edges
;
162 if (edge
[-1].fpos
< fpos
)
165 /* we want the edge with same position and minor direction */
166 /* to appear before those in the major one in the list */
167 if (edge
[-1].fpos
== fpos
168 && dir
== axis
->major_dir
)
191 _ta_message(const char* format
,
197 va_start(ap
, format
);
198 vfprintf(stderr
, format
, ap
);
204 ta_dir_str(TA_Direction dir
)
231 #define TA_INDEX_NUM(ptr, base) \
232 (int)((ptr) ? ((ptr) - (base)) \
237 ta_glyph_hints_dump_points(TA_GlyphHints hints
)
239 TA_Point points
= hints
->points
;
240 TA_Point limit
= points
+ hints
->num_points
;
244 TA_LOG(("Table of points:\n"
245 " [ index | xorg | yorg | xscale | yscale"
246 " | xfit | yfit | flags ]\n"));
248 for (point
= points
; point
< limit
; point
++)
249 TA_LOG((" [ %5d | %5d | %5d | %6.2f | %6.2f"
250 " | %5.2f | %5.2f | %c ]\n",
251 TA_INDEX_NUM(point
, points
),
258 (point
->flags
& TA_FLAG_WEAK_INTERPOLATION
) ? 'w' : ' '));
264 ta_edge_flags_to_string(FT_Byte flags
)
266 static char temp
[32];
270 if (flags
& TA_EDGE_ROUND
)
272 memcpy(temp
+ pos
, "round", 5);
275 if (flags
& TA_EDGE_SERIF
)
279 memcpy(temp
+ pos
, "serif", 5);
291 /* dump the array of linked segments */
294 ta_glyph_hints_dump_segments(TA_GlyphHints hints
)
299 for (dimension
= TA_DEBUG_STARTDIM
;
300 dimension
>= TA_DEBUG_ENDDIM
;
303 TA_AxisHints axis
= &hints
->axis
[dimension
];
304 TA_Point points
= hints
->points
;
305 TA_Edge edges
= axis
->edges
;
306 TA_Segment segments
= axis
->segments
;
307 TA_Segment limit
= segments
+ axis
->num_segments
;
311 TA_LOG(("Table of %s segments:\n",
312 dimension
== TA_DIMENSION_HORZ
? "vertical"
314 if (axis
->num_segments
)
315 TA_LOG((" [ index | pos | dir | from"
316 " | to | link | serif | edge"
317 " | height | extra | flags ]\n"));
319 TA_LOG((" (none)\n"));
321 for (seg
= segments
; seg
< limit
; seg
++)
322 TA_LOG((" [ %5d | %5.2g | %5s | %4d"
323 " | %4d | %4d | %5d | %4d"
324 " | %6d | %5d | %11s ]\n",
325 TA_INDEX_NUM(seg
, segments
),
326 dimension
== TA_DIMENSION_HORZ
? (int)seg
->first
->ox
/ 64.0
327 : (int)seg
->first
->oy
/ 64.0,
328 ta_dir_str((TA_Direction
)seg
->dir
),
329 TA_INDEX_NUM(seg
->first
, points
),
330 TA_INDEX_NUM(seg
->last
, points
),
331 TA_INDEX_NUM(seg
->link
, segments
),
332 TA_INDEX_NUM(seg
->serif
, segments
),
333 TA_INDEX_NUM(seg
->edge
, edges
),
335 seg
->height
- (seg
->max_coord
- seg
->min_coord
),
336 ta_edge_flags_to_string(seg
->flags
)));
342 /* dump the array of linked edges */
345 ta_glyph_hints_dump_edges(TA_GlyphHints hints
)
350 for (dimension
= TA_DEBUG_STARTDIM
;
351 dimension
>= TA_DEBUG_ENDDIM
;
354 TA_AxisHints axis
= &hints
->axis
[dimension
];
355 TA_Edge edges
= axis
->edges
;
356 TA_Edge limit
= edges
+ axis
->num_edges
;
360 /* note that TA_DIMENSION_HORZ corresponds to _vertical_ edges */
361 /* since they have a constant X coordinate */
362 TA_LOG(("Table of %s edges:\n",
363 dimension
== TA_DIMENSION_HORZ
? "vertical"
366 TA_LOG((" [ index | pos | dir | link"
367 " | serif | blue | opos | pos | flags ]\n"));
369 TA_LOG((" (none)\n"));
371 for (edge
= edges
; edge
< limit
; edge
++)
372 TA_LOG((" [ %5d | %5.2g | %5s | %4d"
373 " | %5d | %c | %5.2f | %5.2f | %11s ]\n",
374 TA_INDEX_NUM(edge
, edges
),
375 (int)edge
->opos
/ 64.0,
376 ta_dir_str((TA_Direction
)edge
->dir
),
377 TA_INDEX_NUM(edge
->link
, edges
),
378 TA_INDEX_NUM(edge
->serif
, edges
),
379 edge
->blue_edge
? 'y' : 'n',
382 ta_edge_flags_to_string(edge
->flags
)));
387 #endif /* TA_DEBUG */
390 /* compute the direction value of a given vector */
393 ta_direction_compute(FT_Pos dx
,
396 FT_Pos ll
, ss
; /* long and short arm lengths */
397 TA_Direction dir
; /* candidate direction */
431 /* return no direction if arm lengths differ too much */
432 /* (value 14 is heuristic, corresponding to approx. 4.1 degrees) */
434 if (TA_ABS(ll
) <= TA_ABS(ss
))
442 ta_glyph_hints_init(TA_GlyphHints hints
)
444 /* no need to initialize the embedded items */
445 memset(hints
, 0, sizeof (*hints
) - sizeof (hints
->embedded
));
450 ta_glyph_hints_done(TA_GlyphHints hints
)
458 /* we don't need to free the segment and edge buffers */
459 /* since they are really within the hints->points array */
460 for (dim
= 0; dim
< TA_DIMENSION_MAX
; dim
++)
462 TA_AxisHints axis
= &hints
->axis
[dim
];
465 axis
->num_segments
= 0;
466 axis
->max_segments
= 0;
467 if (axis
->segments
!= axis
->embedded
.segments
)
469 free(axis
->segments
);
470 axis
->segments
= NULL
;
475 if (axis
->edges
!= axis
->embedded
.edges
)
482 if (hints
->contours
!= hints
->embedded
.contours
)
484 free(hints
->contours
);
485 hints
->contours
= NULL
;
487 hints
->max_contours
= 0;
488 hints
->num_contours
= 0;
490 if (hints
->points
!= hints
->embedded
.points
)
493 hints
->points
= NULL
;
495 hints
->max_points
= 0;
496 hints
->num_points
= 0;
503 ta_glyph_hints_rescale(TA_GlyphHints hints
,
504 TA_StyleMetrics metrics
)
506 hints
->metrics
= metrics
;
507 hints
->scaler_flags
= metrics
->scaler
.flags
;
511 /* from FreeType's ftcalc.c */
514 ta_corner_is_flat(FT_Pos in_x
,
522 FT_Pos d_in
, d_out
, d_corner
;
547 return (d_in
+ d_out
- d_corner
) < (d_corner
>> 4);
551 /* recompute all TA_Point in TA_GlyphHints */
552 /* from the definitions in a source outline */
555 ta_glyph_hints_reload(TA_GlyphHints hints
,
558 FT_Error error
= FT_Err_Ok
;
560 FT_UInt old_max
, new_max
;
562 FT_Fixed x_scale
= hints
->x_scale
;
563 FT_Fixed y_scale
= hints
->y_scale
;
564 FT_Pos x_delta
= hints
->x_delta
;
565 FT_Pos y_delta
= hints
->y_delta
;
568 hints
->num_points
= 0;
569 hints
->num_contours
= 0;
571 hints
->axis
[0].num_segments
= 0;
572 hints
->axis
[0].num_edges
= 0;
573 hints
->axis
[1].num_segments
= 0;
574 hints
->axis
[1].num_edges
= 0;
576 /* first of all, reallocate the contours array if necessary */
577 new_max
= (FT_UInt
)outline
->n_contours
;
578 old_max
= hints
->max_contours
;
580 if (new_max
<= TA_CONTOURS_EMBEDDED
)
581 hints
->contours
= hints
->embedded
.contours
;
582 else if (new_max
> old_max
)
584 TA_Point
* contours_new
;
587 if (hints
->contours
== hints
->embedded
.contours
)
588 hints
->contours
= NULL
;
590 new_max
= (new_max
+ 3) & ~3; /* round up to a multiple of 4 */
592 contours_new
= (TA_Point
*)realloc(hints
->contours
,
593 new_max
* sizeof (TA_Point
));
595 return FT_Err_Out_Of_Memory
;
597 hints
->contours
= contours_new
;
598 hints
->max_contours
= new_max
;
601 /* reallocate the points arrays if necessary -- we reserve */
602 /* two additional point positions, used to hint metrics appropriately */
603 new_max
= (FT_UInt
)(outline
->n_points
+ 2);
604 old_max
= hints
->max_points
;
606 if (new_max
<= TA_POINTS_EMBEDDED
)
607 hints
->points
= hints
->embedded
.points
;
608 else if (new_max
> old_max
)
613 if (hints
->points
== hints
->embedded
.points
)
614 hints
->points
= NULL
;
616 new_max
= (new_max
+ 2 + 7) & ~7; /* round up to a multiple of 8 */
618 points_new
= (TA_Point
)realloc(hints
->points
,
619 new_max
* sizeof (TA_PointRec
));
621 return FT_Err_Out_Of_Memory
;
623 hints
->points
= points_new
;
624 hints
->max_points
= new_max
;
627 hints
->num_points
= outline
->n_points
;
628 hints
->num_contours
= outline
->n_contours
;
630 /* we can't rely on the value of `FT_Outline.flags' to know the fill */
631 /* direction used for a glyph, given that some fonts are broken */
632 /* (e.g. the Arphic ones); we thus recompute it each time we need to */
634 hints
->axis
[TA_DIMENSION_HORZ
].major_dir
= TA_DIR_UP
;
635 hints
->axis
[TA_DIMENSION_VERT
].major_dir
= TA_DIR_LEFT
;
637 if (FT_Outline_Get_Orientation(outline
) == FT_ORIENTATION_POSTSCRIPT
)
639 hints
->axis
[TA_DIMENSION_HORZ
].major_dir
= TA_DIR_DOWN
;
640 hints
->axis
[TA_DIMENSION_VERT
].major_dir
= TA_DIR_RIGHT
;
643 hints
->x_scale
= x_scale
;
644 hints
->y_scale
= y_scale
;
645 hints
->x_delta
= x_delta
;
646 hints
->y_delta
= y_delta
;
648 hints
->xmin_delta
= 0;
649 hints
->xmax_delta
= 0;
651 points
= hints
->points
;
652 if (hints
->num_points
== 0)
657 TA_Point point_limit
= points
+ hints
->num_points
;
660 /* compute coordinates & Bezier flags, next and prev */
662 FT_Vector
* vec
= outline
->points
;
663 char* tag
= outline
->tags
;
665 TA_Point end
= points
+ outline
->contours
[0];
668 FT_Int contour_index
= 0;
671 for (point
= points
; point
< point_limit
; point
++, vec
++, tag
++)
673 point
->in_dir
= (FT_Char
)TA_DIR_NONE
;
674 point
->out_dir
= (FT_Char
)TA_DIR_NONE
;
676 point
->fx
= (FT_Short
)vec
->x
;
677 point
->fy
= (FT_Short
)vec
->y
;
678 point
->ox
= point
->x
= FT_MulFix(vec
->x
, x_scale
) + x_delta
;
679 point
->oy
= point
->y
= FT_MulFix(vec
->y
, y_scale
) + y_delta
;
681 switch (FT_CURVE_TAG(*tag
))
683 case FT_CURVE_TAG_CONIC
:
684 point
->flags
= TA_FLAG_CONIC
;
686 case FT_CURVE_TAG_CUBIC
:
687 point
->flags
= TA_FLAG_CUBIC
;
690 point
->flags
= TA_FLAG_NONE
;
699 if (++contour_index
< outline
->n_contours
)
701 end
= points
+ outline
->contours
[contour_index
];
708 /* set up the contours array */
710 TA_Point
* contour
= hints
->contours
;
711 TA_Point
* contour_limit
= contour
+ hints
->num_contours
;
713 short* end
= outline
->contours
;
717 for (; contour
< contour_limit
; contour
++, end
++)
719 contour
[0] = points
+ idx
;
720 idx
= (short)(end
[0] + 1);
726 * Compute directions of `in' and `out' vectors.
728 * Note that distances between points that are very near to each
729 * other are accumulated. In other words, the auto-hinter
730 * prepends the small vectors between near points to the first
731 * non-near vector. All intermediate points are tagged as
732 * weak; the directions are adjusted also to be equal to the
736 /* value 20 in `near_limit' is heuristic */
737 FT_UInt units_per_em
= hints
->metrics
->scaler
.face
->units_per_EM
;
738 FT_Int near_limit
= 20 * units_per_em
/ 2048;
739 FT_Int near_limit2
= 2 * near_limit
- 1;
742 TA_Point
* contour_limit
= hints
->contours
+ hints
->num_contours
;
745 for (contour
= hints
->contours
; contour
< contour_limit
; contour
++)
747 TA_Point first
= *contour
;
748 TA_Point next
, prev
, curr
;
755 /* since the first point of a contour could be part of a */
756 /* series of near points, go backwards to find the first */
757 /* non-near point and adjust `first' */
762 while (prev
!= first
)
764 out_x
= point
->fx
- prev
->fx
;
765 out_y
= point
->fy
- prev
->fy
;
768 * We use Taxicab metrics to measure the vector length.
770 * Note that the accumulated distances so far could have the
771 * opposite direction of the distance measured here. For this
772 * reason we use `near_limit2' for the comparison to get a
773 * non-near point even in the worst case.
775 if (TA_ABS(out_x
) + TA_ABS(out_y
) >= near_limit2
)
782 /* adjust first point */
785 /* now loop over all points of the contour to get */
786 /* `in' and `out' vector directions */
791 * We abuse the `u' and `v' fields to store index deltas to the
792 * next and previous non-near point, respectively.
794 * To avoid problems with not having non-near points, we point to
795 * `first' by default as the next non-near point.
797 curr
->u
= (FT_Pos
)(first
- curr
);
806 point
!= first
|| is_first
;
809 TA_Direction out_dir
;
816 out_x
+= next
->fx
- point
->fx
;
817 out_y
+= next
->fy
- point
->fy
;
819 if (TA_ABS(out_x
) + TA_ABS(out_y
) < near_limit
)
821 next
->flags
|= TA_FLAG_WEAK_INTERPOLATION
;
825 curr
->u
= (FT_Pos
)(next
- curr
);
828 out_dir
= ta_direction_compute(out_x
, out_y
);
830 /* adjust directions for all points inbetween; */
831 /* the loop also updates position of `curr' */
832 curr
->out_dir
= (FT_Char
)out_dir
;
833 for (curr
= curr
->next
; curr
!= next
; curr
= curr
->next
)
835 curr
->in_dir
= (FT_Char
)out_dir
;
836 curr
->out_dir
= (FT_Char
)out_dir
;
838 next
->in_dir
= (FT_Char
)out_dir
;
840 curr
->u
= (FT_Pos
)(first
- curr
);
849 * The next step is to `simplify' an outline's topology so that we
850 * can identify local extrema more reliably: A series of
851 * non-horizontal or non-vertical vectors pointing into the same
852 * quadrant are handled as a single, long vector. From a
853 * topological point of the view, the intermediate points are of no
854 * interest and thus tagged as weak.
857 for (point
= points
; point
< point_limit
; point
++)
859 if (point
->flags
& TA_FLAG_WEAK_INTERPOLATION
)
862 if (point
->in_dir
== TA_DIR_NONE
863 && point
->out_dir
== TA_DIR_NONE
)
865 /* check whether both vectors point into the same quadrant */
870 TA_Point next_u
= point
+ point
->u
;
871 TA_Point prev_v
= point
+ point
->v
;
874 in_x
= point
->fx
- prev_v
->fx
;
875 in_y
= point
->fy
- prev_v
->fy
;
877 out_x
= next_u
->fx
- point
->fx
;
878 out_y
= next_u
->fy
- point
->fy
;
880 if ((in_x
^ out_x
) >= 0 && (in_y
^ out_y
) >= 0)
882 /* yes, so tag current point as weak */
883 /* and update index deltas */
885 point
->flags
|= TA_FLAG_WEAK_INTERPOLATION
;
887 prev_v
->u
= (FT_Pos
)(next_u
- prev_v
);
888 next_u
->v
= -prev_v
->u
;
894 * Finally, check for remaining weak points. Everything else not
895 * collected in edges so far is then implicitly classified as strong
899 for (point
= points
; point
< point_limit
; point
++)
901 if (point
->flags
& TA_FLAG_WEAK_INTERPOLATION
)
904 if (point
->flags
& TA_FLAG_CONTROL
)
906 /* control points are always weak */
908 point
->flags
|= TA_FLAG_WEAK_INTERPOLATION
;
910 else if (point
->out_dir
== point
->in_dir
)
912 if (point
->out_dir
!= TA_DIR_NONE
)
914 /* current point lies on a horizontal or */
915 /* vertical segment (but doesn't start or end it) */
920 TA_Point next_u
= point
+ point
->u
;
921 TA_Point prev_v
= point
+ point
->v
;
924 if (ta_corner_is_flat(point
->fx
- prev_v
->fx
,
925 point
->fy
- prev_v
->fy
,
926 next_u
->fx
- point
->fx
,
927 next_u
->fy
- point
->fy
))
929 /* either the `in' or the `out' vector is much more */
930 /* dominant than the other one, so tag current point */
931 /* as weak and update index deltas */
933 prev_v
->u
= (FT_Pos
)(next_u
- prev_v
);
934 next_u
->v
= -prev_v
->u
;
940 else if (point
->in_dir
== -point
->out_dir
)
942 /* current point forms a spike */
949 /* change some directions at the user's request */
950 /* to make ttfautohint insert one-point segments */
951 /* or remove points from segments */
960 /* `globals' is not set up while initializing metrics, */
961 /* so exit early in this case */
962 if (!hints
->metrics
->globals
)
965 font
= hints
->metrics
->globals
->font
;
967 /* start conditions are set with `TA_control_segment_dir_collect' */
968 while (TA_control_segment_dir_get_next(font
, &idx
, &dir
,
969 &left_offset
, &right_offset
))
971 TA_Point point
= &points
[idx
];
974 point
->out_dir
= dir
;
975 if (dir
== TA_DIR_NONE
)
976 point
->flags
|= TA_FLAG_WEAK_INTERPOLATION
;
978 point
->flags
&= ~TA_FLAG_WEAK_INTERPOLATION
;
979 point
->left_offset
= (FT_Short
)left_offset
;
980 point
->right_offset
= (FT_Short
)right_offset
;
989 /* store the hinted outline in an FT_Outline structure */
992 ta_glyph_hints_save(TA_GlyphHints hints
,
995 TA_Point point
= hints
->points
;
996 TA_Point limit
= point
+ hints
->num_points
;
998 FT_Vector
* vec
= outline
->points
;
999 char* tag
= outline
->tags
;
1002 for (; point
< limit
; point
++, vec
++, tag
++)
1007 if (point
->flags
& TA_FLAG_CONIC
)
1008 tag
[0] = FT_CURVE_TAG_CONIC
;
1009 else if (point
->flags
& TA_FLAG_CUBIC
)
1010 tag
[0] = FT_CURVE_TAG_CUBIC
;
1012 tag
[0] = FT_CURVE_TAG_ON
;
1017 /****************************************************************
1019 * EDGE POINT GRID-FITTING
1021 ****************************************************************/
1024 /* align all points of an edge to the same coordinate value, */
1025 /* either horizontally or vertically */
1028 ta_glyph_hints_align_edge_points(TA_GlyphHints hints
,
1031 TA_AxisHints axis
= &hints
->axis
[dim
];
1032 TA_Segment segments
= axis
->segments
;
1033 TA_Segment segment_limit
= segments
+ axis
->num_segments
;
1037 if (dim
== TA_DIMENSION_HORZ
)
1039 for (seg
= segments
; seg
< segment_limit
; seg
++)
1041 TA_Edge edge
= seg
->edge
;
1042 TA_Point point
, first
, last
;
1053 point
->x
= edge
->pos
;
1054 point
->flags
|= TA_FLAG_TOUCH_X
;
1059 point
= point
->next
;
1065 for (seg
= segments
; seg
< segment_limit
; seg
++)
1067 TA_Edge edge
= seg
->edge
;
1068 TA_Point point
, first
, last
;
1079 point
->y
= edge
->pos
;
1080 point
->flags
|= TA_FLAG_TOUCH_Y
;
1085 point
= point
->next
;
1092 /****************************************************************
1094 * STRONG POINT INTERPOLATION
1096 ****************************************************************/
1099 /* hint the strong points -- */
1100 /* this is equivalent to the TrueType `IP' hinting instruction */
1103 ta_glyph_hints_align_strong_points(TA_GlyphHints hints
,
1106 TA_Point points
= hints
->points
;
1107 TA_Point point_limit
= points
+ hints
->num_points
;
1109 TA_AxisHints axis
= &hints
->axis
[dim
];
1111 TA_Edge edges
= axis
->edges
;
1112 TA_Edge edge_limit
= edges
+ axis
->num_edges
;
1114 FT_UShort touch_flag
;
1117 if (dim
== TA_DIMENSION_HORZ
)
1118 touch_flag
= TA_FLAG_TOUCH_X
;
1120 touch_flag
= TA_FLAG_TOUCH_Y
;
1122 if (edges
< edge_limit
)
1128 for (point
= points
; point
< point_limit
; point
++)
1130 FT_Pos u
, ou
, fu
; /* point position */
1134 if (point
->flags
& touch_flag
)
1137 /* if this point is candidate to weak interpolation, we */
1138 /* interpolate it after all strong points have been processed */
1140 if ((point
->flags
& TA_FLAG_WEAK_INTERPOLATION
))
1143 if (dim
== TA_DIMENSION_VERT
)
1156 /* is the point before the first edge? */
1158 delta
= edge
->fpos
- u
;
1161 u
= edge
->pos
- (edge
->opos
- ou
);
1163 if (hints
->recorder
)
1164 hints
->recorder(ta_ip_before
, hints
, dim
,
1165 point
, NULL
, NULL
, NULL
, NULL
);
1170 /* is the point after the last edge? */
1171 edge
= edge_limit
- 1;
1172 delta
= u
- edge
->fpos
;
1175 u
= edge
->pos
+ (ou
- edge
->opos
);
1177 if (hints
->recorder
)
1178 hints
->recorder(ta_ip_after
, hints
, dim
,
1179 point
, NULL
, NULL
, NULL
, NULL
);
1185 FT_PtrDist min
, max
, mid
;
1189 /* find enclosing edges */
1191 max
= edge_limit
- edges
;
1193 /* for a small number of edges, a linear search is better */
1199 for (nn
= 0; nn
< max
; nn
++)
1200 if (edges
[nn
].fpos
>= u
)
1203 if (edges
[nn
].fpos
== u
)
1207 if (hints
->recorder
)
1208 hints
->recorder(ta_ip_on
, hints
, dim
,
1209 point
, &edges
[nn
], NULL
, NULL
, NULL
);
1218 mid
= (max
+ min
) >> 1;
1228 /* we are on the edge */
1231 if (hints
->recorder
)
1232 hints
->recorder(ta_ip_on
, hints
, dim
,
1233 point
, edge
, NULL
, NULL
, NULL
);
1239 /* point is not on an edge */
1241 TA_Edge before
= edges
+ min
- 1;
1242 TA_Edge after
= edges
+ min
+ 0;
1245 /* assert(before && after && before != after) */
1246 if (before
->scale
== 0)
1247 before
->scale
= FT_DivFix(after
->pos
- before
->pos
,
1248 after
->fpos
- before
->fpos
);
1250 u
= before
->pos
+ FT_MulFix(fu
- before
->fpos
,
1253 if (hints
->recorder
)
1254 hints
->recorder(ta_ip_between
, hints
, dim
,
1255 point
, before
, after
, NULL
, NULL
);
1260 /* save the point position */
1261 if (dim
== TA_DIMENSION_HORZ
)
1266 point
->flags
|= touch_flag
;
1272 /****************************************************************
1274 * WEAK POINT INTERPOLATION
1276 ****************************************************************/
1279 /* shift the original coordinates of all points between `p1' and */
1280 /* `p2' to get hinted coordinates, using the same difference as */
1281 /* given by `ref' */
1284 ta_iup_shift(TA_Point p1
,
1289 FT_Pos delta
= ref
->u
- ref
->v
;
1295 for (p
= p1
; p
< ref
; p
++)
1296 p
->u
= p
->v
+ delta
;
1298 for (p
= ref
+ 1; p
<= p2
; p
++)
1299 p
->u
= p
->v
+ delta
;
1303 /* interpolate the original coordinates of all points between `p1' and */
1304 /* `p2' to get hinted coordinates, using `ref1' and `ref2' as the */
1305 /* reference points; the `u' and `v' members are the current and */
1306 /* original coordinate values, respectively. */
1308 /* details can be found in the TrueType bytecode specification */
1311 ta_iup_interp(TA_Point p1
,
1318 FT_Pos v1
= ref1
->v
;
1319 FT_Pos v2
= ref2
->v
;
1320 FT_Pos d1
= ref1
->u
- v1
;
1321 FT_Pos d2
= ref2
->u
- v2
;
1329 for (p
= p1
; p
<= p2
; p
++)
1345 for (p
= p1
; p
<= p2
; p
++)
1354 u
= ref1
->u
+ FT_MulDiv(u
- v1
, ref2
->u
- ref1
->u
, v2
- v1
);
1361 for (p
= p1
; p
<= p2
; p
++)
1370 u
= ref1
->u
+ FT_MulDiv(u
- v1
, ref2
->u
- ref1
->u
, v2
- v1
);
1378 /* hint the weak points -- */
1379 /* this is equivalent to the TrueType `IUP' hinting instruction */
1382 ta_glyph_hints_align_weak_points(TA_GlyphHints hints
,
1385 TA_Point points
= hints
->points
;
1386 TA_Point point_limit
= points
+ hints
->num_points
;
1388 TA_Point
* contour
= hints
->contours
;
1389 TA_Point
* contour_limit
= contour
+ hints
->num_contours
;
1391 FT_UShort touch_flag
;
1394 TA_Point first_point
;
1397 /* pass 1: move segment points to edge positions */
1399 if (dim
== TA_DIMENSION_HORZ
)
1401 touch_flag
= TA_FLAG_TOUCH_X
;
1403 for (point
= points
; point
< point_limit
; point
++)
1405 point
->u
= point
->x
;
1406 point
->v
= point
->ox
;
1411 touch_flag
= TA_FLAG_TOUCH_Y
;
1413 for (point
= points
; point
< point_limit
; point
++)
1415 point
->u
= point
->y
;
1416 point
->v
= point
->oy
;
1420 for (; contour
< contour_limit
; contour
++)
1422 TA_Point first_touched
, last_touched
;
1426 end_point
= point
->prev
;
1427 first_point
= point
;
1429 /* find first touched point */
1432 if (point
> end_point
) /* no touched point in contour */
1435 if (point
->flags
& touch_flag
)
1441 first_touched
= point
;
1445 /* skip any touched neighbours */
1446 while (point
< end_point
1447 && (point
[1].flags
& touch_flag
) != 0)
1450 last_touched
= point
;
1452 /* find the next touched point, if any */
1456 if (point
> end_point
)
1459 if ((point
->flags
& touch_flag
) != 0)
1465 /* interpolate between last_touched and point */
1466 ta_iup_interp(last_touched
+ 1, point
- 1,
1467 last_touched
, point
);
1471 /* special case: only one point was touched */
1472 if (last_touched
== first_touched
)
1473 ta_iup_shift(first_point
, end_point
, first_touched
);
1475 else /* interpolate the last part */
1477 if (last_touched
< end_point
)
1478 ta_iup_interp(last_touched
+ 1, end_point
,
1479 last_touched
, first_touched
);
1481 if (first_touched
> points
)
1482 ta_iup_interp(first_point
, first_touched
- 1,
1483 last_touched
, first_touched
);
1490 /* now save the interpolated values back to x/y */
1491 if (dim
== TA_DIMENSION_HORZ
)
1493 for (point
= points
; point
< point_limit
; point
++)
1494 point
->x
= point
->u
;
1498 for (point
= points
; point
< point_limit
; point
++)
1499 point
->y
= point
->u
;
1504 #ifdef TA_CONFIG_OPTION_USE_WARPER
1506 /* apply (small) warp scale and warp delta for given dimension */
1509 ta_glyph_hints_scale_dim(TA_GlyphHints hints
,
1514 TA_Point points
= hints
->points
;
1515 TA_Point points_limit
= points
+ hints
->num_points
;
1519 if (dim
== TA_DIMENSION_HORZ
)
1521 for (point
= points
; point
< points_limit
; point
++)
1522 point
->x
= FT_MulFix(point
->fx
, scale
) + delta
;
1526 for (point
= points
; point
< points_limit
; point
++)
1527 point
->y
= FT_MulFix(point
->fy
, scale
) + delta
;
1531 #endif /* TA_CONFIG_OPTION_USE_WARPER */
1533 /* end of tahints.c */