File: tahints.h

package info (click to toggle)
ttfautohint 1.8.4-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 9,120 kB
  • sloc: ansic: 42,761; sh: 5,584; cpp: 4,222; perl: 340; javascript: 78; sed: 52; makefile: 34
file content (592 lines) | stat: -rw-r--r-- 16,646 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
/* tahints.h */

/*
 * Copyright (C) 2011-2021 by Werner Lemberg.
 *
 * This file is part of the ttfautohint library, and may only be used,
 * modified, and distributed under the terms given in `COPYING'.  By
 * continuing to use, modify, or distribute this file you indicate that you
 * have read `COPYING' and understand and accept it fully.
 *
 * The file `COPYING' mentioned in the previous paragraph is distributed
 * with the ttfautohint library.
 */


/* originally file `afhints.h' (2011-Mar-28) from FreeType */

/* heavily modified 2011 by Werner Lemberg <wl@gnu.org> */

#ifndef TAHINTS_H_
#define TAHINTS_H_

#include "tatypes.h"

#ifdef __cplusplus
extern "C" {
#endif

#define xxTA_SORT_SEGMENTS


/* the definition of outline glyph hints; these are shared */
/* by all writing system analysis routines (until now) */

typedef enum TA_Dimension_
{
  TA_DIMENSION_HORZ = 0, /* x coordinates, i.e. vert. segments & edges */
  TA_DIMENSION_VERT = 1, /* y coordinates, i.e. horz. segments & edges */
  TA_DIMENSION_MAX /* do not remove */
} TA_Dimension;


/* hint directions -- the values are computed so that two vectors */
/* are in opposite directions iff `dir1 + dir2 == 0' */

typedef enum TA_Direction_
{
  TA_DIR_NONE = 4,
  TA_DIR_RIGHT = 1,
  TA_DIR_LEFT= -1,
  TA_DIR_UP = 2,
  TA_DIR_DOWN = -2
} TA_Direction;


/*
 *  The following explanations are mostly taken from the article
 *
 *    Real-Time Grid Fitting of Typographic Outlines
 *
 *  by David Turner and Werner Lemberg
 *
 *    https://www.tug.org/TUGboat/Articles/tb24-3/lemberg.pdf
 *
 *  with appropriate updates.
 *
 *
 *  Segments
 *
 *    `ta_{cjk,latin,...}_hints_compute_segments' are the functions to
 *    find segments in an outline.
 *
 *    A segment is a series of at least two consecutive points that are
 *    approximately aligned along a coordinate axis.  The analysis to do
 *    so is specific to a writing system.
 *
 *
 *  Edges
 *
 *    `ta_{cjk,latin,...}_hints_compute_edges' are the functions to find
 *    edges.
 *
 *    As soon as segments are defined, the auto-hinter groups them into
 *    edges.  An edge corresponds to a single position on the main
 *    dimension that collects one or more segments (allowing for a small
 *    threshold).
 *
 *    As an example, the `latin' writing system first tries to grid-fit
 *    edges, then to align segments on the edges unless it detects that
 *    they form a serif.
 *
 *
 *                      A          H
 *                       |        |
 *                       |        |
 *                       |        |
 *                       |        |
 *         C             |        |             F
 *          +------<-----+        +-----<------+
 *          |             B      G             |
 *          |                                  |
 *          |                                  |
 *          +--------------->------------------+
 *         D                                    E
 *
 *
 *  Stems
 *
 *    Stems are detected by `ta_{cjk,latin,...}_hint_edges'.
 *
 *    Segments need to be `linked' to other ones in order to detect stems.
 *    A stem is made of two segments that face each other in opposite
 *    directions and that are sufficiently close to each other.  Using
 *    vocabulary from the TrueType specification, stem segments form a
 *    `black distance'.
 *
 *    In the above ASCII drawing, the horizontal segments are BC, DE, and
 *    FG; the vertical segments are AB, CD, EF, and GH.
 *
 *    Each segment has at most one `best' candidate to form a black
 *    distance, or no candidate at all.  Notice that two distinct segments
 *    can have the same candidate, which frequently means a serif.
 *
 *    A stem is recognized by the following condition:
 *
 *      best segment_1 = segment_2 && best segment_2 = segment_1
 *
 *    The best candidate is stored in field `link' in structure
 *    `TA_Segment'.
 *
 *    In the above ASCII drawing, the best candidate for both AB and CD is
 *    GH, while the best candidate for GH is AB.  Similarly, the best
 *    candidate for EF and GH is AB, while the best candidate for AB is
 *    GH.
 *
 *    The detection and handling of stems is dependent on the writing
 *    system.
 *
 *
 *  Serifs
 *
 *    Serifs are detected by `ta_{cjk,latin,...}_hint_edges'.
 *
 *    In comparison to a stem, a serif (as handled by the auto-hinter
 *    module that takes care of the `latin' writing system) has
 *
 *      best segment_1 = segment_2 && best segment_2 != segment_1
 *
 *    where segment_1 corresponds to the serif segment (CD and EF in the
 *    above ASCII drawing).
 *
 *    The best candidate is stored in field `serif' in structure
 *    `TA_Segment' (and `link' is set to NULL).
 *
 *
 *  Touched points
 *
 *    A point is called `touched' if it has been processed somehow by the
 *    auto-hinter.  It basically means that it shouldn't be moved again
 *    (or moved only under certain constraints to preserve the already
 *    applied processing).
 *
 *
 *  Flat and round segments
 *
 *    Segments are `round' or `flat', depending on the series of points
 *    that define them.  A segment is round if the next and previous point
 *    of an extremum (which can be either a single point or sequence of
 *    points) are both conic or cubic control points.  Otherwise, a
 *    segment with an extremum is flat.
 *
 *
 *  Strong Points
 *
 *    Experience has shown that points not part of an edge need to be
 *    interpolated linearly between their two closest edges, even if these
 *    are not part of the contour of those particular points.  Typical
 *    candidates for this are
 *
 *    - angle points (i.e., points where the `in' and `out' direction
 *      differ greatly)
 *
 *    - inflection points (i.e., where the `in' and `out' angles are the
 *      same, but the curvature changes sign) [currently, such points
 *      aren't handled specially in the auto-hinter]
 *
 *    `ta_glyph_hints_align_strong_points' is the function that takes
 *    care of such situations; it is equivalent to the TrueType `IP'
 *    hinting instruction.
 *
 *
 *  Weak Points
 *
 *    Other points in the outline must be interpolated using the
 *    coordinates of their previous and next unfitted contour neighbours.
 *    These are called `weak points' and are touched by the function
 *    `ta_glyph_hints_align_weak_points', equivalent to the TrueType `IUP'
 *    hinting instruction.  Typical candidates are control points and
 *    points on the contour without a major direction.
 *
 *    The major effect is to reduce possible distortion caused by
 *    alignment of edges and strong points, thus weak points are processed
 *    after strong points.
 */


/* point hint flags */
#define TA_FLAG_NONE 0

/* point type flags */
#define TA_FLAG_CONIC (1U << 0)
#define TA_FLAG_CUBIC (1U << 1)
#define TA_FLAG_CONTROL (TA_FLAG_CONIC | TA_FLAG_CUBIC)

/* point touch flags */
#define TA_FLAG_TOUCH_X (1U << 2)
#define TA_FLAG_TOUCH_Y (1U << 3)

/* candidates for weak interpolation have this flag set */
#define TA_FLAG_WEAK_INTERPOLATION (1U << 4)


/* edge hint flags */
#define TA_EDGE_NORMAL 0
#define TA_EDGE_ROUND (1U << 0)
#define TA_EDGE_SERIF (1U << 1)
#define TA_EDGE_DONE (1U << 2)
#define TA_EDGE_NEUTRAL (1U << 3)


typedef struct TA_PointRec_* TA_Point;
typedef struct TA_SegmentRec_* TA_Segment;
typedef struct TA_EdgeRec_* TA_Edge;


typedef struct TA_PointRec_
{
  FT_UShort flags; /* point flags used by hinter */
  FT_Char in_dir; /* direction of inwards vector */
  FT_Char out_dir; /* direction of outwards vector */

  FT_Pos ox, oy; /* original, scaled position */
  FT_Short fx, fy; /* original, unscaled position (in font units) */
  FT_Pos x, y; /* current position */
  FT_Pos u, v; /* current (x,y) or (y,x) depending on context */

  FT_Short left_offset; /* left offset in one-point segments */
  FT_Short right_offset; /* right offset in one-point segments */

  TA_Point next; /* next point in contour */
  TA_Point prev; /* previous point in contour */

#ifdef TA_DEBUG
  /* track `before' and `after' edges for strong points */
  TA_Edge before[2];
  TA_Edge after[2];
#endif
} TA_PointRec;


typedef struct TA_SegmentRec_
{
  FT_Byte flags; /* edge/segment flags for this segment */
  FT_Char dir; /* segment direction */
  FT_Short pos; /* position of segment */
  FT_Short delta; /* deviation from segment position */
  FT_Short min_coord; /* minimum coordinate of segment */
  FT_Short max_coord; /* maximum coordinate of segment */
  FT_Short height; /* the hinted segment height */

  TA_Edge edge; /* the segment's parent edge */
  TA_Segment edge_next; /* link to next segment in parent edge */

  TA_Segment link; /* (stem) link segment */
  TA_Segment serif; /* primary segment for serifs */
  FT_Pos score; /* used during stem matching */
  FT_Pos len; /* used during stem matching */

  TA_Point first; /* first point in edge segment */
  TA_Point last; /* last point in edge segment */
} TA_SegmentRec;


typedef struct TA_EdgeRec_
{
  FT_Short fpos; /* original, unscaled position (in font units) */
  FT_Pos opos; /* original, scaled position */
  FT_Pos pos; /* current position */

  FT_Byte flags; /* edge flags */
  FT_Char dir; /* edge direction */
  FT_Fixed scale; /* used to speed up interpolation between edges */

  TA_Width blue_edge; /* non-NULL if this is a blue edge */
  FT_UInt best_blue_idx; /* for the hinting recorder callback */
  FT_Bool best_blue_is_shoot; /* for the hinting recorder callback */

  TA_Edge link; /* link edge */
  TA_Edge serif; /* primary edge for serifs */
  FT_Int score; /* used during stem matching */

  TA_Segment first; /* first segment in edge */
  TA_Segment last; /* last segment in edge */
} TA_EdgeRec;


#define TA_SEGMENTS_EMBEDDED 18 /* number of embedded segments */
#define TA_EDGES_EMBEDDED 12 /* number of embedded edges */

typedef struct TA_AxisHintsRec_
{
  FT_Int num_segments; /* number of used segments */
  FT_Int max_segments; /* number of allocated segments */
  TA_Segment segments; /* segments array */
#ifdef TA_SORT_SEGMENTS
  FT_Int mid_segments;
#endif

  FT_Int num_edges; /* number of used edges */
  FT_Int max_edges; /* number of allocated edges */
  TA_Edge edges; /* edges array */

  TA_Direction major_dir; /* either vertical or horizontal */

  /* two arrays to avoid allocation penalty */
  struct
  {
    TA_SegmentRec segments[TA_SEGMENTS_EMBEDDED];
    TA_EdgeRec edges[TA_EDGES_EMBEDDED];
  } embedded;
} TA_AxisHintsRec, *TA_AxisHints;


typedef enum TA_Action_
{
  /* point actions */

  ta_ip_before,
  ta_ip_after,
  ta_ip_on,
  ta_ip_between,

  /* edge actions */

  ta_blue,
  ta_blue_anchor,

  ta_anchor,
  ta_anchor_serif,
  ta_anchor_round,
  ta_anchor_round_serif,

  ta_adjust,
  ta_adjust_serif,
  ta_adjust_round,
  ta_adjust_round_serif,
  ta_adjust_bound,
  ta_adjust_bound_serif,
  ta_adjust_bound_round,
  ta_adjust_bound_round_serif,
  ta_adjust_down_bound,
  ta_adjust_down_bound_serif,
  ta_adjust_down_bound_round,
  ta_adjust_down_bound_round_serif,

  ta_link,
  ta_link_serif,
  ta_link_round,
  ta_link_round_serif,

  ta_stem,
  ta_stem_serif,
  ta_stem_round,
  ta_stem_round_serif,
  ta_stem_bound,
  ta_stem_bound_serif,
  ta_stem_bound_round,
  ta_stem_bound_round_serif,
  ta_stem_down_bound,
  ta_stem_down_bound_serif,
  ta_stem_down_bound_round,
  ta_stem_down_bound_round_serif,

  ta_serif,
  ta_serif_lower_bound,
  ta_serif_upper_bound,
  ta_serif_upper_lower_bound,
  ta_serif_down_lower_bound,
  ta_serif_down_upper_bound,
  ta_serif_down_upper_lower_bound,

  ta_serif_anchor,
  ta_serif_anchor_lower_bound,
  ta_serif_anchor_upper_bound,
  ta_serif_anchor_upper_lower_bound,
  ta_serif_anchor_down_lower_bound,
  ta_serif_anchor_down_upper_bound,
  ta_serif_anchor_down_upper_lower_bound,

  ta_serif_link1,
  ta_serif_link1_lower_bound,
  ta_serif_link1_upper_bound,
  ta_serif_link1_upper_lower_bound,
  ta_serif_link1_down_lower_bound,
  ta_serif_link1_down_upper_bound,
  ta_serif_link1_down_upper_lower_bound,

  ta_serif_link2,
  ta_serif_link2_lower_bound,
  ta_serif_link2_upper_bound,
  ta_serif_link2_upper_lower_bound,
  ta_serif_link2_down_lower_bound,
  ta_serif_link2_down_upper_bound,
  ta_serif_link2_down_upper_lower_bound,

  ta_bound
} TA_Action;


typedef void
(*TA_Hints_Recorder)(TA_Action action,
                     TA_GlyphHints hints,
                     TA_Dimension dim,
                     void* arg1, /* TA_Point or TA_Edge */
                     TA_Edge arg2,
                     TA_Edge arg3,
                     TA_Edge lower_bound,
                     TA_Edge upper_bound);


#define TA_POINTS_EMBEDDED 96 /* number of embedded points */
#define TA_CONTOURS_EMBEDDED 8 /* number of embedded contours */

typedef struct TA_GlyphHintsRec_
{
  FT_Fixed x_scale;
  FT_Pos x_delta;

  FT_Fixed y_scale;
  FT_Pos y_delta;

  FT_Int max_points; /* number of allocated points */
  FT_Int num_points; /* number of used points */
  TA_Point points; /* points array */

  FT_Int max_contours; /* number of allocated contours */
  FT_Int num_contours; /* number of used contours */
  TA_Point* contours; /* contours array */

  TA_AxisHintsRec axis[TA_DIMENSION_MAX];

  FT_UInt32 scaler_flags; /* copy of scaler flags */
  FT_UInt32 other_flags; /* free for style-specific implementations */
  TA_StyleMetrics metrics;

  FT_Pos xmin_delta; /* used for warping */
  FT_Pos xmax_delta;

  TA_Hints_Recorder recorder;
  void* user;

  /* two arrays to avoid allocation penalty; */
  /* the `embedded' structure must be the last element! */
  struct
  {
    TA_Point contours[TA_CONTOURS_EMBEDDED];
    TA_PointRec points[TA_POINTS_EMBEDDED];
  } embedded;
} TA_GlyphHintsRec;


#define TA_HINTS_TEST_SCALER(h, f) \
          ((h)->scaler_flags & (f))
#define TA_HINTS_TEST_OTHER(h, f) \
          ((h)->other_flags & (f))


#ifdef TA_DEBUG

#define TA_HINTS_DO_HORIZONTAL(h) \
          (!_ta_debug_disable_horz_hints \
           && !TA_HINTS_TEST_SCALER(h, TA_SCALER_FLAG_NO_HORIZONTAL))

#define TA_HINTS_DO_VERTICAL(h) \
          (!_ta_debug_disable_vert_hints \
           && !TA_HINTS_TEST_SCALER(h, TA_SCALER_FLAG_NO_VERTICAL))

#define TA_HINTS_DO_BLUES(h) \
          (!_ta_debug_disable_blue_hints)

#else /* !TA_DEBUG */

#define TA_HINTS_DO_HORIZONTAL(h) \
          !TA_HINTS_TEST_SCALER(h, TA_SCALER_FLAG_NO_HORIZONTAL)

#define TA_HINTS_DO_VERTICAL(h) \
          !TA_HINTS_TEST_SCALER(h, TA_SCALER_FLAG_NO_VERTICAL)

#define TA_HINTS_DO_BLUES(h) \
          1

#endif /* !TA_DEBUG */


#define TA_HINTS_DO_ADVANCE(h) \
          !TA_HINTS_TEST_SCALER(h, TA_SCALER_FLAG_NO_ADVANCE)

#define TA_HINTS_DO_WARP(h) \
          !TA_HINTS_TEST_SCALER(h, TA_SCALER_FLAG_NO_WARPER)


TA_Direction
ta_direction_compute(FT_Pos dx,
                     FT_Pos dy);


FT_Error
ta_axis_hints_new_segment(TA_AxisHints axis,
                          TA_Segment* asegment);

FT_Error
ta_axis_hints_new_edge(TA_AxisHints axis,
                       FT_Int fpos,
                       TA_Direction dir,
                       FT_Bool top_to_bottom_hinting,
                       TA_Edge* edge);

#ifdef TA_DEBUG
void
ta_glyph_hints_dump_points(TA_GlyphHints hints);

void
ta_glyph_hints_dump_segments(TA_GlyphHints hints);

void
ta_glyph_hints_dump_edges(TA_GlyphHints hints);
#endif

void
ta_glyph_hints_init(TA_GlyphHints hints);

void
ta_glyph_hints_rescale(TA_GlyphHints hints,
                       TA_StyleMetrics metrics);

FT_Error
ta_glyph_hints_reload(TA_GlyphHints hints,
                      FT_Outline* outline);

void
ta_glyph_hints_save(TA_GlyphHints hints,
                    FT_Outline* outline);

void
ta_glyph_hints_align_edge_points(TA_GlyphHints hints,
                                 TA_Dimension dim);

void
ta_glyph_hints_align_strong_points(TA_GlyphHints hints,
                                   TA_Dimension dim);

void
ta_glyph_hints_align_weak_points(TA_GlyphHints hints,
                                 TA_Dimension dim);

#ifdef TA_CONFIG_OPTION_USE_WARPER
void
ta_glyph_hints_scale_dim(TA_GlyphHints hints,
                         TA_Dimension dim,
                         FT_Fixed scale,
                         FT_Pos delta);
#endif

void
ta_glyph_hints_done(TA_GlyphHints hints);


#define TA_SEGMENT_LEN(seg) \
          ((seg)->max_coord - (seg)->min_coord)

#define TA_SEGMENT_DIST(seg1, seg2) \
          (((seg1)->pos > (seg2)->pos) ? (seg1)->pos - (seg2)->pos \
                                       : (seg2)->pos - (seg1)->pos)

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* TAHINTS_H_ */


/* end of tahints.h */