1 /***************************************************************************/
5 /* Auto-fitter hinting routines (specification). */
7 /* Copyright 2003-2008, 2010-2011 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 /***************************************************************************/
24 #define xxAF_SORT_SEGMENTS
29 * The definition of outline glyph hints. These are shared by all
30 * script analysis routines (until now).
33 typedef enum AF_Dimension_
35 AF_DIMENSION_HORZ = 0, /* x coordinates, */
36 /* i.e., vertical segments & edges */
37 AF_DIMENSION_VERT = 1, /* y coordinates, */
38 /* i.e., horizontal segments & edges */
40 AF_DIMENSION_MAX /* do not remove */
45 /* hint directions -- the values are computed so that two vectors are */
46 /* in opposite directions iff `dir1 + dir2 == 0' */
47 typedef enum AF_Direction_
59 * The following explanations are mostly taken from the article
61 * Real-Time Grid Fitting of Typographic Outlines
63 * by David Turner and Werner Lemberg
65 * http://www.tug.org/TUGboat/Articles/tb24-3/lemberg.pdf
70 * `af_{cjk,latin,...}_hints_compute_segments' are the functions to
71 * find segments in an outline. A segment is a series of consecutive
72 * points that are approximately aligned along a coordinate axis. The
73 * analysis to do so is specific to a script.
75 * A segment must have at least two points, except in the case of
76 * `fake' segments that are generated to hint metrics appropriately,
77 * and which consist of a single point.
82 * As soon as segments are defined, the auto-hinter groups them into
83 * edges. An edge corresponds to a single position on the main
84 * dimension that collects one or more segments (allowing for a small
87 * The auto-hinter first tries to grid fit edges, then to align
88 * segments on the edges unless it detects that they form a serif.
90 * `af_{cjk,latin,...}_hints_compute_edges' are the functions to find
91 * edges; they are specific to a script.
100 * +------<-----+ +-----<------+
104 * +--------------->------------------+
110 * Segments need to be `linked' to other ones in order to detect stems.
111 * A stem is made of two segments that face each other in opposite
112 * directions and that are sufficiently close to each other. Using
113 * vocabulary from the TrueType specification, stem segments form a
116 * In the above ASCII drawing, the horizontal segments are BC, DE, and
117 * FG; the vertical segments are AB, CD, EF, and GH.
119 * Each segment has at most one `best' candidate to form a black
120 * distance, or no candidate at all. Notice that two distinct segments
121 * can have the same candidate, which frequently means a serif.
123 * A stem is recognized by the following condition:
125 * best segment_1 = segment_2 && best segment_2 = segment_1
127 * The best candidate is stored in field `link' in structure
130 * Stems are detected by `af_{cjk,latin,...}_hint_edges'.
132 * In the above ASCII drawing, the best candidate for both AB and CD is
133 * GH, while the best candidate for GH is AB. Similarly, the best
134 * candidate for EF and GH is AB, while the best candidate for AB is
140 * On the opposite, a serif has
142 * best segment_1 = segment_2 && best segment_2 != segment_1
144 * where segment_1 corresponds to the serif segment (CD and EF in the
145 * above ASCII drawing).
147 * The best candidate is stored in field `serif' in structure
148 * `AF_Segment' (and `link' is set to NULL).
150 * Serifs are detected by `af_{cjk,latin,...}_hint_edges'.
155 * A point is called `touched' if it has been processed somehow by the
156 * auto-hinter. It basically means that it shouldn't be moved again
157 * (or moved only under certain constraints to preserve the already
158 * applied processing).
161 * Flat and round segments
163 * Segments are `round' or `flat', depending on the series of points
164 * that define them. A segment is round if the next and previous point
165 * of an extremum (which can be either a single point or sequence of
166 * points) are both conic or cubic control points. Otherwise, a
167 * segment with an extremum is flat.
172 * Experience has shown that points which are not part of an edge need
173 * to be interpolated linearly between their two closest edges, even if
174 * these are not part of the contour of those particular points.
175 * Typical candidates for this are
177 * - angle points (i.e., points where the `in' and `out' direction
180 * - inflection points (i.e., where the `in' and `out' angles are the
181 * same, but the curvature changes sign)
183 * `af_glyph_hints_align_strong_points' is the function which takes
184 * care of such situations; it is equivalent to the TrueType `IP'
185 * hinting instruction.
190 * Other points in the outline must be interpolated using the
191 * coordinates of their previous and next unfitted contour neighbours.
192 * These are called `weak points' and are touched by the function
193 * `af_glyph_hints_align_weak_points', equivalent to the TrueType `IUP'
194 * hinting instruction. Typical candidates are control points and
195 * points on the contour without a major direction.
197 * The major effect is to reduce possible distortion caused by
198 * alignment of edges and strong points, thus weak points are processed
199 * after strong points.
203 /* point hint flags */
204 typedef enum AF_Flags_
208 /* point type flags */
209 AF_FLAG_CONIC = 1 << 0,
210 AF_FLAG_CUBIC = 1 << 1,
211 AF_FLAG_CONTROL = AF_FLAG_CONIC | AF_FLAG_CUBIC,
213 /* point extremum flags */
214 AF_FLAG_EXTREMA_X = 1 << 2,
215 AF_FLAG_EXTREMA_Y = 1 << 3,
217 /* point roundness flags */
218 AF_FLAG_ROUND_X = 1 << 4,
219 AF_FLAG_ROUND_Y = 1 << 5,
221 /* point touch flags */
222 AF_FLAG_TOUCH_X = 1 << 6,
223 AF_FLAG_TOUCH_Y = 1 << 7,
225 /* candidates for weak interpolation have this flag set */
226 AF_FLAG_WEAK_INTERPOLATION = 1 << 8,
228 /* all inflection points in the outline have this flag set */
229 AF_FLAG_INFLECTION = 1 << 9
234 /* edge hint flags */
235 typedef enum AF_Edge_Flags_
238 AF_EDGE_ROUND = 1 << 0,
239 AF_EDGE_SERIF = 1 << 1,
240 AF_EDGE_DONE = 1 << 2
245 typedef struct AF_PointRec_* AF_Point;
246 typedef struct AF_SegmentRec_* AF_Segment;
247 typedef struct AF_EdgeRec_* AF_Edge;
250 typedef struct AF_PointRec_
252 FT_UShort flags; /* point flags used by hinter */
253 FT_Char in_dir; /* direction of inwards vector */
254 FT_Char out_dir; /* direction of outwards vector */
256 FT_Pos ox, oy; /* original, scaled position */
257 FT_Short fx, fy; /* original, unscaled position (font units) */
258 FT_Pos x, y; /* current position */
259 FT_Pos u, v; /* current (x,y) or (y,x) depending on context */
261 AF_Point next; /* next point in contour */
262 AF_Point prev; /* previous point in contour */
267 typedef struct AF_SegmentRec_
269 FT_Byte flags; /* edge/segment flags for this segment */
270 FT_Char dir; /* segment direction */
271 FT_Short pos; /* position of segment */
272 FT_Short min_coord; /* minimum coordinate of segment */
273 FT_Short max_coord; /* maximum coordinate of segment */
274 FT_Short height; /* the hinted segment height */
276 AF_Edge edge; /* the segment's parent edge */
277 AF_Segment edge_next; /* link to next segment in parent edge */
279 AF_Segment link; /* (stem) link segment */
280 AF_Segment serif; /* primary segment for serifs */
281 FT_Pos num_linked; /* number of linked segments */
282 FT_Pos score; /* used during stem matching */
283 FT_Pos len; /* used during stem matching */
285 AF_Point first; /* first point in edge segment */
286 AF_Point last; /* last point in edge segment */
291 typedef struct AF_EdgeRec_
293 FT_Short fpos; /* original, unscaled position (font units) */
294 FT_Pos opos; /* original, scaled position */
295 FT_Pos pos; /* current position */
297 FT_Byte flags; /* edge flags */
298 FT_Char dir; /* edge direction */
299 FT_Fixed scale; /* used to speed up interpolation between edges */
300 AF_Width blue_edge; /* non-NULL if this is a blue edge */
302 AF_Edge link; /* link edge */
303 AF_Edge serif; /* primary edge for serifs */
304 FT_Short num_linked; /* number of linked edges */
305 FT_Int score; /* used during stem matching */
307 AF_Segment first; /* first segment in edge */
308 AF_Segment last; /* last segment in edge */
313 typedef struct AF_AxisHintsRec_
315 FT_Int num_segments; /* number of used segments */
316 FT_Int max_segments; /* number of allocated segments */
317 AF_Segment segments; /* segments array */
318 #ifdef AF_SORT_SEGMENTS
322 FT_Int num_edges; /* number of used edges */
323 FT_Int max_edges; /* number of allocated edges */
324 AF_Edge edges; /* edges array */
326 AF_Direction major_dir; /* either vertical or horizontal */
328 } AF_AxisHintsRec, *AF_AxisHints;
331 typedef struct AF_GlyphHintsRec_
341 FT_Int max_points; /* number of allocated points */
342 FT_Int num_points; /* number of used points */
343 AF_Point points; /* points array */
345 FT_Int max_contours; /* number of allocated contours */
346 FT_Int num_contours; /* number of used contours */
347 AF_Point* contours; /* contours array */
349 AF_AxisHintsRec axis[AF_DIMENSION_MAX];
351 FT_UInt32 scaler_flags; /* copy of scaler flags */
352 FT_UInt32 other_flags; /* free for script-specific */
353 /* implementations */
354 AF_ScriptMetrics metrics;
356 FT_Pos xmin_delta; /* used for warping */
362 #define AF_HINTS_TEST_SCALER( h, f ) ( (h)->scaler_flags & (f) )
363 #define AF_HINTS_TEST_OTHER( h, f ) ( (h)->other_flags & (f) )
366 #ifdef FT_DEBUG_AUTOFIT
368 #define AF_HINTS_DO_HORIZONTAL( h ) \
369 ( !_af_debug_disable_horz_hints && \
370 !AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_HORIZONTAL ) )
372 #define AF_HINTS_DO_VERTICAL( h ) \
373 ( !_af_debug_disable_vert_hints && \
374 !AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_VERTICAL ) )
376 #define AF_HINTS_DO_ADVANCE( h ) \
377 !AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_ADVANCE )
379 #define AF_HINTS_DO_BLUES( h ) ( !_af_debug_disable_blue_hints )
381 #else /* !FT_DEBUG_AUTOFIT */
383 #define AF_HINTS_DO_HORIZONTAL( h ) \
384 !AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_HORIZONTAL )
386 #define AF_HINTS_DO_VERTICAL( h ) \
387 !AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_VERTICAL )
389 #define AF_HINTS_DO_ADVANCE( h ) \
390 !AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_ADVANCE )
392 #define AF_HINTS_DO_BLUES( h ) 1
394 #endif /* !FT_DEBUG_AUTOFIT */
397 FT_LOCAL( AF_Direction )
398 af_direction_compute( FT_Pos dx,
403 af_axis_hints_new_segment( AF_AxisHints axis,
405 AF_Segment *asegment );
408 af_axis_hints_new_edge( AF_AxisHints axis,
415 af_glyph_hints_init( AF_GlyphHints hints,
419 af_glyph_hints_rescale( AF_GlyphHints hints,
420 AF_ScriptMetrics metrics );
423 af_glyph_hints_reload( AF_GlyphHints hints,
424 FT_Outline* outline );
427 af_glyph_hints_save( AF_GlyphHints hints,
428 FT_Outline* outline );
431 af_glyph_hints_align_edge_points( AF_GlyphHints hints,
435 af_glyph_hints_align_strong_points( AF_GlyphHints hints,
439 af_glyph_hints_align_weak_points( AF_GlyphHints hints,
442 #ifdef AF_CONFIG_OPTION_USE_WARPER
444 af_glyph_hints_scale_dim( AF_GlyphHints hints,
451 af_glyph_hints_done( AF_GlyphHints hints );
455 #define AF_SEGMENT_LEN( seg ) ( (seg)->max_coord - (seg)->min_coord )
457 #define AF_SEGMENT_DIST( seg1, seg2 ) ( ( (seg1)->pos > (seg2)->pos ) \
458 ? (seg1)->pos - (seg2)->pos \
459 : (seg2)->pos - (seg1)->pos )
464 #endif /* __AFHINTS_H__ */