xref: /aosp_15_r20/external/harfbuzz_ng/src/OT/glyf/path-builder.hh (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
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   {
optional_point_tOT::glyf_impl::path_builder_t::optional_point_t19     optional_point_t () {}
optional_point_tOT::glyf_impl::path_builder_t::optional_point_t20     optional_point_t (float x_, float y_) : has_data (true), x (x_), y (y_) {}
operator boolOT::glyf_impl::path_builder_t::optional_point_t21     operator bool () const { return has_data; }
22 
23     bool has_data = false;
24     float x;
25     float y;
26 
midOT::glyf_impl::path_builder_t::optional_point_t27     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 
path_builder_tOT::glyf_impl::path_builder_t31   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
consume_pointOT::glyf_impl::path_builder_t41   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   }
points_endOT::glyf_impl::path_builder_t179   void points_end () {}
180 
is_consuming_contour_pointsOT::glyf_impl::path_builder_t181   bool is_consuming_contour_points () { return true; }
get_phantoms_sinkOT::glyf_impl::path_builder_t182   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 */
191