tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

afhints.h (16428B)


      1 /****************************************************************************
      2 *
      3 * afhints.h
      4 *
      5 *   Auto-fitter hinting routines (specification).
      6 *
      7 * Copyright (C) 2003-2025 by
      8 * David Turner, Robert Wilhelm, and Werner Lemberg.
      9 *
     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.
     15 *
     16 */
     17 
     18 
     19 #ifndef AFHINTS_H_
     20 #define AFHINTS_H_
     21 
     22 #include "aftypes.h"
     23 
     24 FT_BEGIN_HEADER
     25 
     26  /*
     27   * The definition of outline glyph hints.  These are shared by all
     28   * writing system analysis routines (until now).
     29   */
     30 
     31  typedef enum  AF_Dimension_
     32  {
     33    AF_DIMENSION_HORZ = 0,  /* x coordinates,                    */
     34                            /* i.e., vertical segments & edges   */
     35    AF_DIMENSION_VERT = 1,  /* y coordinates,                    */
     36                            /* i.e., horizontal segments & edges */
     37 
     38    AF_DIMENSION_MAX  /* do not remove */
     39 
     40  } AF_Dimension;
     41 
     42 
     43  /* hint directions -- the values are computed so that two vectors are */
     44  /* in opposite directions iff `dir1 + dir2 == 0'                      */
     45  typedef enum  AF_Direction_
     46  {
     47    AF_DIR_NONE  =  4,
     48    AF_DIR_RIGHT =  1,
     49    AF_DIR_LEFT  = -1,
     50    AF_DIR_UP    =  2,
     51    AF_DIR_DOWN  = -2
     52 
     53  } AF_Direction;
     54 
     55 
     56  /*
     57   * The following explanations are mostly taken from the article
     58   *
     59   *   Real-Time Grid Fitting of Typographic Outlines
     60   *
     61   * by David Turner and Werner Lemberg
     62   *
     63   *   https://www.tug.org/TUGboat/Articles/tb24-3/lemberg.pdf
     64   *
     65   * with appropriate updates.
     66   *
     67   *
     68   * Segments
     69   *
     70   *   `af_{cjk,latin,...}_hints_compute_segments' are the functions to
     71   *   find segments in an outline.
     72   *
     73   *   A segment is a series of at least two consecutive points that are
     74   *   approximately aligned along a coordinate axis.  The analysis to do
     75   *   so is specific to a writing system.
     76   *
     77   *
     78   * Edges
     79   *
     80   *   `af_{cjk,latin,...}_hints_compute_edges' are the functions to find
     81   *   edges.
     82   *
     83   *   As soon as segments are defined, the auto-hinter groups them into
     84   *   edges.  An edge corresponds to a single position on the main
     85   *   dimension that collects one or more segments (allowing for a small
     86   *   threshold).
     87   *
     88   *   As an example, the `latin' writing system first tries to grid-fit
     89   *   edges, then to align segments on the edges unless it detects that
     90   *   they form a serif.
     91   *
     92   *
     93   *                     A          H
     94   *                      |        |
     95   *                      |        |
     96   *                      |        |
     97   *                      |        |
     98   *        C             |        |             F
     99   *         +------<-----+        +-----<------+
    100   *         |             B      G             |
    101   *         |                                  |
    102   *         |                                  |
    103   *         +--------------->------------------+
    104   *        D                                    E
    105   *
    106   *
    107   * Stems
    108   *
    109   *   Stems are detected by `af_{cjk,latin,...}_hint_edges'.
    110   *
    111   *   Segments need to be `linked' to other ones in order to detect stems.
    112   *   A stem is made of two segments that face each other in opposite
    113   *   directions and that are sufficiently close to each other.  Using
    114   *   vocabulary from the TrueType specification, stem segments form a
    115   *   `black distance'.
    116   *
    117   *   In the above ASCII drawing, the horizontal segments are BC, DE, and
    118   *   FG; the vertical segments are AB, CD, EF, and GH.
    119   *
    120   *   Each segment has at most one `best' candidate to form a black
    121   *   distance, or no candidate at all.  Notice that two distinct segments
    122   *   can have the same candidate, which frequently means a serif.
    123   *
    124   *   A stem is recognized by the following condition:
    125   *
    126   *     best segment_1 = segment_2 && best segment_2 = segment_1
    127   *
    128   *   The best candidate is stored in field `link' in structure
    129   *   `AF_Segment'.
    130   *
    131   *   In the above ASCII drawing, the best candidate for both AB and CD is
    132   *   GH, while the best candidate for GH is AB.  Similarly, the best
    133   *   candidate for EF and GH is AB, while the best candidate for AB is
    134   *   GH.
    135   *
    136   *   The detection and handling of stems is dependent on the writing
    137   *   system.
    138   *
    139   *
    140   * Serifs
    141   *
    142   *   Serifs are detected by `af_{cjk,latin,...}_hint_edges'.
    143   *
    144   *   In comparison to a stem, a serif (as handled by the auto-hinter
    145   *   module that takes care of the `latin' writing system) has
    146   *
    147   *     best segment_1 = segment_2 && best segment_2 != segment_1
    148   *
    149   *   where segment_1 corresponds to the serif segment (CD and EF in the
    150   *   above ASCII drawing).
    151   *
    152   *   The best candidate is stored in field `serif' in structure
    153   *   `AF_Segment' (and `link' is set to NULL).
    154   *
    155   *
    156   * Touched points
    157   *
    158   *   A point is called `touched' if it has been processed somehow by the
    159   *   auto-hinter.  It basically means that it shouldn't be moved again
    160   *   (or moved only under certain constraints to preserve the already
    161   *   applied processing).
    162   *
    163   *
    164   * Flat and round segments
    165   *
    166   *   Segments are `round' or `flat', depending on the series of points
    167   *   that define them.  A segment is round if the next and previous point
    168   *   of an extremum (which can be either a single point or sequence of
    169   *   points) are both conic or cubic control points.  Otherwise, a
    170   *   segment with an extremum is flat.
    171   *
    172   *
    173   * Strong Points
    174   *
    175   *   Experience has shown that points not part of an edge need to be
    176   *   interpolated linearly between their two closest edges, even if these
    177   *   are not part of the contour of those particular points.  Typical
    178   *   candidates for this are
    179   *
    180   *   - angle points (i.e., points where the `in' and `out' direction
    181   *     differ greatly)
    182   *
    183   *   - inflection points (i.e., where the `in' and `out' angles are the
    184   *     same, but the curvature changes sign) [currently, such points
    185   *     aren't handled specially in the auto-hinter]
    186   *
    187   *   `af_glyph_hints_align_strong_points' is the function that takes
    188   *   care of such situations; it is equivalent to the TrueType `IP'
    189   *   hinting instruction.
    190   *
    191   *
    192   * Weak Points
    193   *
    194   *   Other points in the outline must be interpolated using the
    195   *   coordinates of their previous and next unfitted contour neighbours.
    196   *   These are called `weak points' and are touched by the function
    197   *   `af_glyph_hints_align_weak_points', equivalent to the TrueType `IUP'
    198   *   hinting instruction.  Typical candidates are control points and
    199   *   points on the contour without a major direction.
    200   *
    201   *   The major effect is to reduce possible distortion caused by
    202   *   alignment of edges and strong points, thus weak points are processed
    203   *   after strong points.
    204   */
    205 
    206 
    207  /* point hint flags */
    208 #define AF_FLAG_NONE  0
    209 
    210  /* point type flags */
    211 #define AF_FLAG_CONIC    ( 1U << 0 )
    212 #define AF_FLAG_CUBIC    ( 1U << 1 )
    213 #define AF_FLAG_CONTROL  ( AF_FLAG_CONIC | AF_FLAG_CUBIC )
    214 
    215  /* point touch flags */
    216 #define AF_FLAG_TOUCH_X  ( 1U << 2 )
    217 #define AF_FLAG_TOUCH_Y  ( 1U << 3 )
    218 
    219  /* candidates for weak interpolation have this flag set */
    220 #define AF_FLAG_WEAK_INTERPOLATION  ( 1U << 4 )
    221 
    222  /* the distance to the next point is very small */
    223 #define AF_FLAG_NEAR  ( 1U << 5 )
    224 
    225  /* prevent the auto-hinter from adding such a point to a segment */
    226 #define AF_FLAG_IGNORE  ( 1U << 6 )
    227 
    228 
    229  /* edge hint flags */
    230 #define AF_EDGE_NORMAL  0
    231 #define AF_EDGE_ROUND    ( 1U << 0 )
    232 #define AF_EDGE_SERIF    ( 1U << 1 )
    233 #define AF_EDGE_DONE     ( 1U << 2 )
    234 #define AF_EDGE_NEUTRAL  ( 1U << 3 ) /* edge aligns to a neutral blue zone */
    235 #define AF_EDGE_NO_BLUE  ( 1U << 4 ) /* do not align edge to blue zone     */
    236 
    237 
    238  typedef struct AF_PointRec_*    AF_Point;
    239  typedef struct AF_SegmentRec_*  AF_Segment;
    240  typedef struct AF_EdgeRec_*     AF_Edge;
    241 
    242 
    243  typedef struct  AF_PointRec_
    244  {
    245    FT_UShort  flags;    /* point flags used by hinter   */
    246    FT_Char    in_dir;   /* direction of inwards vector  */
    247    FT_Char    out_dir;  /* direction of outwards vector */
    248 
    249    FT_Pos     ox, oy;   /* original, scaled position                   */
    250    FT_Short   fx, fy;   /* original, unscaled position (in font units) */
    251    FT_Pos     x, y;     /* current position                            */
    252    FT_Pos     u, v;     /* current (x,y) or (y,x) depending on context */
    253 
    254    AF_Point   next;     /* next point in contour     */
    255    AF_Point   prev;     /* previous point in contour */
    256 
    257 #ifdef FT_DEBUG_AUTOFIT
    258    /* track `before' and `after' edges for strong points */
    259    AF_Edge    before[2];
    260    AF_Edge    after[2];
    261 #endif
    262 
    263  } AF_PointRec;
    264 
    265 
    266  typedef struct  AF_SegmentRec_
    267  {
    268    FT_Byte     flags;       /* edge/segment flags for this segment */
    269    FT_Char     dir;         /* segment direction                   */
    270    FT_Short    pos;         /* position of segment                 */
    271    FT_Short    delta;       /* deviation from segment position     */
    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           */
    275 
    276    AF_Edge     edge;        /* the segment's parent edge           */
    277    AF_Segment  edge_next;   /* link to next segment in parent edge */
    278 
    279    AF_Segment  link;        /* (stem) link segment        */
    280    AF_Segment  serif;       /* primary segment for serifs */
    281    FT_Pos      score;       /* used during stem matching  */
    282    FT_Pos      len;         /* used during stem matching  */
    283 
    284    AF_Point    first;       /* first point in edge segment */
    285    AF_Point    last;        /* last point in edge segment  */
    286 
    287  } AF_SegmentRec;
    288 
    289 
    290  typedef struct  AF_EdgeRec_
    291  {
    292    FT_Short    fpos;       /* original, unscaled position (in font units) */
    293    FT_Pos      opos;       /* original, scaled position                   */
    294    FT_Pos      pos;        /* current position                            */
    295 
    296    FT_Byte     flags;      /* edge flags                                   */
    297    FT_Char     dir;        /* edge direction                               */
    298    FT_Fixed    scale;      /* used to speed up interpolation between edges */
    299 
    300    AF_Width    blue_edge;  /* non-NULL if this is a blue edge */
    301    AF_Edge     link;       /* link edge                       */
    302    AF_Edge     serif;      /* primary edge for serifs         */
    303    FT_Int      score;      /* used during stem matching       */
    304 
    305    AF_Segment  first;      /* first segment in edge */
    306    AF_Segment  last;       /* last segment in edge  */
    307 
    308  } AF_EdgeRec;
    309 
    310 
    311 #define AF_SEGMENTS_EMBEDDED  18   /* number of embedded segments   */
    312 #define AF_EDGES_EMBEDDED     12   /* number of embedded edges      */
    313 
    314  typedef struct  AF_AxisHintsRec_
    315  {
    316    FT_UInt       num_segments; /* number of used segments      */
    317    FT_UInt       max_segments; /* number of allocated segments */
    318    AF_Segment    segments;     /* segments array               */
    319 
    320    FT_UInt       num_edges;    /* number of used edges      */
    321    FT_UInt       max_edges;    /* number of allocated edges */
    322    AF_Edge       edges;        /* edges array               */
    323 
    324    AF_Direction  major_dir;    /* either vertical or horizontal */
    325 
    326    /* two arrays to avoid allocation penalty */
    327    struct
    328    {
    329      AF_SegmentRec  segments[AF_SEGMENTS_EMBEDDED];
    330      AF_EdgeRec     edges[AF_EDGES_EMBEDDED];
    331    } embedded;
    332 
    333 
    334  } AF_AxisHintsRec, *AF_AxisHints;
    335 
    336 
    337 #define AF_POINTS_EMBEDDED     96   /* number of embedded points   */
    338 #define AF_CONTOURS_EMBEDDED    8   /* number of embedded contours */
    339 
    340  typedef struct  AF_GlyphHintsRec_
    341  {
    342    FT_Memory        memory;
    343 
    344    FT_Fixed         x_scale;
    345    FT_Pos           x_delta;
    346 
    347    FT_Fixed         y_scale;
    348    FT_Pos           y_delta;
    349 
    350    FT_Int           max_points;    /* number of allocated points */
    351    FT_Int           num_points;    /* number of used points      */
    352    AF_Point         points;        /* points array               */
    353 
    354    FT_Int           max_contours;     /* number of allocated contours    */
    355    FT_Int           num_contours;     /* number of used contours         */
    356    AF_Point*        contours;         /* contours array                  */
    357    FT_Pos*          contour_y_minima; /* array with y maxima of contours */
    358    FT_Pos*          contour_y_maxima; /* array with y minima of contours */
    359 
    360    AF_AxisHintsRec  axis[AF_DIMENSION_MAX];
    361 
    362    FT_UInt32        scaler_flags;  /* copy of scaler flags    */
    363    FT_UInt32        other_flags;   /* free for style-specific */
    364                                    /* implementations         */
    365    AF_StyleMetrics  metrics;
    366 
    367    /* Some arrays to avoid allocation penalty.           */
    368    /* The `embedded' structure must be the last element! */
    369    struct
    370    {
    371      AF_Point       contours[AF_CONTOURS_EMBEDDED];
    372      FT_Pos         contour_y_minima[AF_CONTOURS_EMBEDDED];
    373      FT_Pos         contour_y_maxima[AF_CONTOURS_EMBEDDED];
    374      AF_PointRec    points[AF_POINTS_EMBEDDED];
    375    } embedded;
    376 
    377  } AF_GlyphHintsRec;
    378 
    379 
    380 #define AF_HINTS_TEST_SCALER( h, f )  ( (h)->scaler_flags & (f) )
    381 #define AF_HINTS_TEST_OTHER( h, f )   ( (h)->other_flags  & (f) )
    382 
    383 
    384 #ifdef FT_DEBUG_AUTOFIT
    385 
    386 #define AF_HINTS_DO_HORIZONTAL( h )                                     \
    387          ( !af_debug_disable_horz_hints_                            && \
    388            !AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_HORIZONTAL ) )
    389 
    390 #define AF_HINTS_DO_VERTICAL( h )                                     \
    391          ( !af_debug_disable_vert_hints_                          && \
    392            !AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_VERTICAL ) )
    393 
    394 #define AF_HINTS_DO_BLUES( h )  ( !af_debug_disable_blue_hints_ )
    395 
    396 #else /* !FT_DEBUG_AUTOFIT */
    397 
    398 #define AF_HINTS_DO_HORIZONTAL( h )                                \
    399          !AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_HORIZONTAL )
    400 
    401 #define AF_HINTS_DO_VERTICAL( h )                                \
    402          !AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_VERTICAL )
    403 
    404 #define AF_HINTS_DO_BLUES( h )  1
    405 
    406 #endif /* !FT_DEBUG_AUTOFIT */
    407 
    408 
    409 #define AF_HINTS_DO_ADVANCE( h )                                \
    410          !AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_ADVANCE )
    411 
    412 
    413  FT_LOCAL( AF_Direction )
    414  af_direction_compute( FT_Pos  dx,
    415                        FT_Pos  dy );
    416 
    417 
    418  FT_LOCAL( FT_Error )
    419  af_axis_hints_new_segment( AF_AxisHints  axis,
    420                             FT_Memory     memory,
    421                             AF_Segment   *asegment );
    422 
    423  FT_LOCAL( FT_Error)
    424  af_axis_hints_new_edge( AF_AxisHints  axis,
    425                          FT_Int        fpos,
    426                          AF_Direction  dir,
    427                          FT_Bool       top_to_bottom_hinting,
    428                          FT_Memory     memory,
    429                          AF_Edge      *edge );
    430 
    431  FT_LOCAL( void )
    432  af_glyph_hints_init( AF_GlyphHints  hints,
    433                       FT_Memory      memory );
    434 
    435  FT_LOCAL( void )
    436  af_glyph_hints_rescale( AF_GlyphHints    hints,
    437                          AF_StyleMetrics  metrics );
    438 
    439  FT_LOCAL( FT_Error )
    440  af_glyph_hints_reload( AF_GlyphHints  hints,
    441                         FT_Outline*    outline );
    442 
    443  FT_LOCAL( void )
    444  af_glyph_hints_save( AF_GlyphHints  hints,
    445                       FT_Outline*    outline );
    446 
    447  FT_LOCAL( void )
    448  af_glyph_hints_align_edge_points( AF_GlyphHints  hints,
    449                                    AF_Dimension   dim );
    450 
    451  FT_LOCAL( void )
    452  af_glyph_hints_align_strong_points( AF_GlyphHints  hints,
    453                                      AF_Dimension   dim );
    454 
    455  FT_LOCAL( void )
    456  af_glyph_hints_align_weak_points( AF_GlyphHints  hints,
    457                                    AF_Dimension   dim );
    458 
    459  FT_LOCAL( void )
    460  af_glyph_hints_done( AF_GlyphHints  hints );
    461 
    462 /* */
    463 
    464 #define AF_SEGMENT_LEN( seg )          ( (seg)->max_coord - (seg)->min_coord )
    465 
    466 #define AF_SEGMENT_DIST( seg1, seg2 )  ( ( (seg1)->pos > (seg2)->pos )   \
    467                                           ? (seg1)->pos - (seg2)->pos   \
    468                                           : (seg2)->pos - (seg1)->pos )
    469 
    470 
    471 FT_END_HEADER
    472 
    473 #endif /* AFHINTS_H_ */
    474 
    475 
    476 /* END */