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