Imported Upstream version 8.2.2
[platform/upstream/harfbuzz.git] / src / OT / glyf / path-builder.hh
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     optional_point_t () {}
20     optional_point_t (float x_, float y_) : has_data (true), x (x_), y (y_) {}
21     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     { 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     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   {
43     bool is_on_curve = point.flag & glyf_impl::SimpleGlyph::FLAG_ON_CURVE;
44 #ifdef HB_NO_CUBIC_GLYF
45     bool is_cubic = false;
46 #else
47     bool is_cubic = !is_on_curve && (point.flag & glyf_impl::SimpleGlyph::FLAG_CUBIC);
48 #endif
49     optional_point_t p (font->em_fscalef_x (point.x), font->em_fscalef_y (point.y));
50     if (unlikely (!first_oncurve))
51     {
52       if (is_on_curve)
53       {
54         first_oncurve = p;
55         draw_session->move_to (p.x, p.y);
56       }
57       else
58       {
59         if (is_cubic && !first_offcurve2)
60         {
61           first_offcurve2 = first_offcurve;
62           first_offcurve = p;
63         }
64         else if (first_offcurve)
65         {
66           optional_point_t mid = first_offcurve.mid (p);
67           first_oncurve = mid;
68           last_offcurve = p;
69           draw_session->move_to (mid.x, mid.y);
70         }
71         else
72           first_offcurve = p;
73       }
74     }
75     else
76     {
77       if (last_offcurve)
78       {
79         if (is_on_curve)
80         {
81           if (last_offcurve2)
82           {
83             draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y,
84                                     last_offcurve.x, last_offcurve.y,
85                                     p.x, p.y);
86             last_offcurve2 = optional_point_t ();
87           }
88           else
89             draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
90                                        p.x, p.y);
91           last_offcurve = optional_point_t ();
92         }
93         else
94         {
95           if (is_cubic && !last_offcurve2)
96           {
97             last_offcurve2 = last_offcurve;
98             last_offcurve = p;
99           }
100           else
101           {
102             optional_point_t mid = last_offcurve.mid (p);
103
104             if (is_cubic)
105             {
106               draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y,
107                                       last_offcurve.x, last_offcurve.y,
108                                       mid.x, mid.y);
109               last_offcurve2 = optional_point_t ();
110             }
111             else
112               draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
113                                          mid.x, mid.y);
114             last_offcurve = p;
115           }
116         }
117       }
118       else
119       {
120         if (is_on_curve)
121           draw_session->line_to (p.x, p.y);
122         else
123           last_offcurve = p;
124       }
125     }
126
127     if (unlikely (point.is_end_point))
128     {
129       if (first_offcurve && last_offcurve)
130       {
131         optional_point_t mid = last_offcurve.mid (first_offcurve2 ?
132                                                   first_offcurve2 :
133                                                   first_offcurve);
134         if (last_offcurve2)
135           draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y,
136                                   last_offcurve.x, last_offcurve.y,
137                                   mid.x, mid.y);
138         else
139           draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
140                                      mid.x, mid.y);
141         last_offcurve = optional_point_t ();
142       }
143       /* now check the rest */
144
145       if (first_offcurve && first_oncurve)
146       {
147         if (first_offcurve2)
148           draw_session->cubic_to (first_offcurve2.x, first_offcurve2.y,
149                                   first_offcurve.x, first_offcurve.y,
150                                   first_oncurve.x, first_oncurve.y);
151         else
152           draw_session->quadratic_to (first_offcurve.x, first_offcurve.y,
153                                      first_oncurve.x, first_oncurve.y);
154       }
155       else if (last_offcurve && first_oncurve)
156       {
157         if (last_offcurve2)
158           draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y,
159                                   last_offcurve.x, last_offcurve.y,
160                                   first_oncurve.x, first_oncurve.y);
161         else
162           draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
163                                      first_oncurve.x, first_oncurve.y);
164       }
165       else if (first_oncurve)
166         draw_session->line_to (first_oncurve.x, first_oncurve.y);
167       else if (first_offcurve)
168       {
169         float x = first_offcurve.x, y = first_offcurve.y;
170         draw_session->move_to (x, y);
171         draw_session->quadratic_to (x, y, x, y);
172       }
173
174       /* Getting ready for the next contour */
175       first_oncurve = first_offcurve = last_offcurve = last_offcurve2 = optional_point_t ();
176       draw_session->close_path ();
177     }
178   }
179   void points_end () {}
180
181   bool is_consuming_contour_points () { return true; }
182   contour_point_t *get_phantoms_sink () { return nullptr; }
183 };
184
185
186 } /* namespace glyf_impl */
187 } /* namespace OT */
188
189
190 #endif /* OT_GLYF_PATH_BUILDER_HH */