Coverage Report

Created: 2025-07-23 07:07

/src/harfbuzz/src/OT/glyf/path-builder.hh
Line
Count
Source (jump to first uncovered line)
1
#ifndef OT_GLYF_PATH_BUILDER_HH
2
#define OT_GLYF_PATH_BUILDER_HH
3
4
5
#include "../../hb.hh"
6
7
8
namespace OT {
9
namespace glyf_impl {
10
11
12
struct path_builder_t
13
{
14
  hb_font_t *font;
15
  hb_draw_session_t *draw_session;
16
17
  struct optional_point_t
18
  {
19
0
    optional_point_t () {}
20
0
    optional_point_t (float x_, float y_) : has_data (true), x (x_), y (y_) {}
21
0
    operator bool () const { return has_data; }
22
23
    bool has_data = false;
24
    float x;
25
    float y;
26
27
    optional_point_t mid (optional_point_t p)
28
0
    { return optional_point_t ((x + p.x) * 0.5f, (y + p.y) * 0.5f); }
29
  } first_oncurve, first_offcurve, first_offcurve2, last_offcurve, last_offcurve2;
30
31
  path_builder_t (hb_font_t *font_, hb_draw_session_t &draw_session_) :
32
0
    font (font_), draw_session (&draw_session_) {}
33
34
  /* based on https://github.com/RazrFalcon/ttf-parser/blob/4f32821/src/glyf.rs#L287
35
     See also:
36
     * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM01/Chap1.html
37
     * https://stackoverflow.com/a/20772557
38
     *
39
     * Cubic support added. */
40
  HB_ALWAYS_INLINE
41
  void consume_point (const contour_point_t &point)
42
0
  {
43
0
    bool is_on_curve = point.flag & glyf_impl::SimpleGlyph::FLAG_ON_CURVE;
44
#ifdef HB_NO_CUBIC_GLYF
45
    constexpr bool is_cubic = false;
46
#else
47
0
    bool is_cubic = !is_on_curve && (point.flag & glyf_impl::SimpleGlyph::FLAG_CUBIC);
48
0
#endif
49
0
    optional_point_t p (font->em_fscalef_x (point.x), font->em_fscalef_y (point.y));
50
0
    if (unlikely (!first_oncurve))
51
0
    {
52
0
      if (is_on_curve)
53
0
      {
54
0
  first_oncurve = p;
55
0
  draw_session->move_to (p.x, p.y);
56
0
      }
57
0
      else
58
0
      {
59
0
  if (is_cubic && !first_offcurve2)
60
0
  {
61
0
    first_offcurve2 = first_offcurve;
62
0
    first_offcurve = p;
63
0
  }
64
0
  else if (first_offcurve)
65
0
  {
66
0
    optional_point_t mid = first_offcurve.mid (p);
67
0
    first_oncurve = mid;
68
0
    last_offcurve = p;
69
0
    draw_session->move_to (mid.x, mid.y);
70
0
  }
71
0
  else
72
0
    first_offcurve = p;
73
0
      }
74
0
    }
75
0
    else
76
0
    {
77
0
      if (last_offcurve)
78
0
      {
79
0
  if (is_on_curve)
80
0
  {
81
0
    if (last_offcurve2)
82
0
    {
83
0
      draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y,
84
0
            last_offcurve.x, last_offcurve.y,
85
0
            p.x, p.y);
86
0
      last_offcurve2 = optional_point_t ();
87
0
    }
88
0
    else
89
0
      draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
90
0
               p.x, p.y);
91
0
    last_offcurve = optional_point_t ();
92
0
  }
93
0
  else
94
0
  {
95
0
    if (is_cubic && !last_offcurve2)
96
0
    {
97
0
      last_offcurve2 = last_offcurve;
98
0
      last_offcurve = p;
99
0
    }
100
0
    else
101
0
    {
102
0
      optional_point_t mid = last_offcurve.mid (p);
103
104
0
      if (is_cubic)
105
0
      {
106
0
        draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y,
107
0
              last_offcurve.x, last_offcurve.y,
108
0
              mid.x, mid.y);
109
0
        last_offcurve2 = optional_point_t ();
110
0
      }
111
0
      else
112
0
        draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
113
0
           mid.x, mid.y);
114
0
      last_offcurve = p;
115
0
    }
116
0
  }
117
0
      }
118
0
      else
119
0
      {
120
0
  if (is_on_curve)
121
0
    draw_session->line_to (p.x, p.y);
122
0
  else
123
0
    last_offcurve = p;
124
0
      }
125
0
    }
126
127
0
  }
128
129
  void contour_end ()
130
0
  {
131
0
    if (first_offcurve && last_offcurve)
132
0
    {
133
0
      optional_point_t mid = last_offcurve.mid (first_offcurve2 ?
134
0
            first_offcurve2 :
135
0
            first_offcurve);
136
0
      if (last_offcurve2)
137
0
  draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y,
138
0
        last_offcurve.x, last_offcurve.y,
139
0
        mid.x, mid.y);
140
0
      else
141
0
  draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
142
0
           mid.x, mid.y);
143
0
      last_offcurve = optional_point_t ();
144
0
    }
145
    /* now check the rest */
146
147
0
    if (first_offcurve && first_oncurve)
148
0
    {
149
0
      if (first_offcurve2)
150
0
  draw_session->cubic_to (first_offcurve2.x, first_offcurve2.y,
151
0
        first_offcurve.x, first_offcurve.y,
152
0
        first_oncurve.x, first_oncurve.y);
153
0
      else
154
0
  draw_session->quadratic_to (first_offcurve.x, first_offcurve.y,
155
0
           first_oncurve.x, first_oncurve.y);
156
0
    }
157
0
    else if (last_offcurve && first_oncurve)
158
0
    {
159
0
      if (last_offcurve2)
160
0
  draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y,
161
0
        last_offcurve.x, last_offcurve.y,
162
0
        first_oncurve.x, first_oncurve.y);
163
0
      else
164
0
  draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
165
0
           first_oncurve.x, first_oncurve.y);
166
0
    }
167
0
    else if (first_oncurve)
168
0
      draw_session->line_to (first_oncurve.x, first_oncurve.y);
169
0
    else if (first_offcurve)
170
0
    {
171
0
      float x = first_offcurve.x, y = first_offcurve.y;
172
0
      draw_session->move_to (x, y);
173
0
      draw_session->quadratic_to (x, y, x, y);
174
0
    }
175
176
    /* Getting ready for the next contour */
177
0
    first_oncurve = first_offcurve = last_offcurve = last_offcurve2 = optional_point_t ();
178
0
    draw_session->close_path ();
179
0
  }
180
181
0
  void points_end () {}
182
183
0
  bool is_consuming_contour_points () { return true; }
184
0
  contour_point_t *get_phantoms_sink () { return nullptr; }
185
};
186
187
188
} /* namespace glyf_impl */
189
} /* namespace OT */
190
191
192
#endif /* OT_GLYF_PATH_BUILDER_HH */