xref: /aosp_15_r20/external/harfbuzz_ng/src/hb-outline.cc (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
1*2d1272b8SAndroid Build Coastguard Worker /*
2*2d1272b8SAndroid Build Coastguard Worker  * Copyright © 2023  Behdad Esfahbod
3*2d1272b8SAndroid Build Coastguard Worker  * Copyright © 1999  David Turner
4*2d1272b8SAndroid Build Coastguard Worker  * Copyright © 2005  Werner Lemberg
5*2d1272b8SAndroid Build Coastguard Worker  * Copyright © 2013-2015  Alexei Podtelezhnikov
6*2d1272b8SAndroid Build Coastguard Worker  *
7*2d1272b8SAndroid Build Coastguard Worker  *  This is part of HarfBuzz, a text shaping library.
8*2d1272b8SAndroid Build Coastguard Worker  *
9*2d1272b8SAndroid Build Coastguard Worker  * Permission is hereby granted, without written agreement and without
10*2d1272b8SAndroid Build Coastguard Worker  * license or royalty fees, to use, copy, modify, and distribute this
11*2d1272b8SAndroid Build Coastguard Worker  * software and its documentation for any purpose, provided that the
12*2d1272b8SAndroid Build Coastguard Worker  * above copyright notice and the following two paragraphs appear in
13*2d1272b8SAndroid Build Coastguard Worker  * all copies of this software.
14*2d1272b8SAndroid Build Coastguard Worker  *
15*2d1272b8SAndroid Build Coastguard Worker  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
16*2d1272b8SAndroid Build Coastguard Worker  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
17*2d1272b8SAndroid Build Coastguard Worker  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
18*2d1272b8SAndroid Build Coastguard Worker  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
19*2d1272b8SAndroid Build Coastguard Worker  * DAMAGE.
20*2d1272b8SAndroid Build Coastguard Worker  *
21*2d1272b8SAndroid Build Coastguard Worker  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
22*2d1272b8SAndroid Build Coastguard Worker  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
23*2d1272b8SAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
24*2d1272b8SAndroid Build Coastguard Worker  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
25*2d1272b8SAndroid Build Coastguard Worker  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
26*2d1272b8SAndroid Build Coastguard Worker  */
27*2d1272b8SAndroid Build Coastguard Worker 
28*2d1272b8SAndroid Build Coastguard Worker #include "hb.hh"
29*2d1272b8SAndroid Build Coastguard Worker 
30*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_NO_OUTLINE
31*2d1272b8SAndroid Build Coastguard Worker 
32*2d1272b8SAndroid Build Coastguard Worker #include "hb-outline.hh"
33*2d1272b8SAndroid Build Coastguard Worker 
34*2d1272b8SAndroid Build Coastguard Worker #include "hb-machinery.hh"
35*2d1272b8SAndroid Build Coastguard Worker 
36*2d1272b8SAndroid Build Coastguard Worker 
replay(hb_draw_funcs_t * pen,void * pen_data) const37*2d1272b8SAndroid Build Coastguard Worker void hb_outline_t::replay (hb_draw_funcs_t *pen, void *pen_data) const
38*2d1272b8SAndroid Build Coastguard Worker {
39*2d1272b8SAndroid Build Coastguard Worker   hb_draw_state_t st = HB_DRAW_STATE_DEFAULT;
40*2d1272b8SAndroid Build Coastguard Worker 
41*2d1272b8SAndroid Build Coastguard Worker   unsigned first = 0;
42*2d1272b8SAndroid Build Coastguard Worker   for (unsigned contour : contours)
43*2d1272b8SAndroid Build Coastguard Worker   {
44*2d1272b8SAndroid Build Coastguard Worker     auto it = points.as_array ().sub_array (first, contour - first);
45*2d1272b8SAndroid Build Coastguard Worker     while (it)
46*2d1272b8SAndroid Build Coastguard Worker     {
47*2d1272b8SAndroid Build Coastguard Worker       hb_outline_point_t p1 = *it++;
48*2d1272b8SAndroid Build Coastguard Worker       switch (p1.type)
49*2d1272b8SAndroid Build Coastguard Worker       {
50*2d1272b8SAndroid Build Coastguard Worker 	case hb_outline_point_t::type_t::MOVE_TO:
51*2d1272b8SAndroid Build Coastguard Worker 	{
52*2d1272b8SAndroid Build Coastguard Worker 	  pen->move_to (pen_data, st,
53*2d1272b8SAndroid Build Coastguard Worker 			   p1.x, p1.y);
54*2d1272b8SAndroid Build Coastguard Worker 	}
55*2d1272b8SAndroid Build Coastguard Worker 	break;
56*2d1272b8SAndroid Build Coastguard Worker 	case hb_outline_point_t::type_t::LINE_TO:
57*2d1272b8SAndroid Build Coastguard Worker 	{
58*2d1272b8SAndroid Build Coastguard Worker 	  pen->line_to (pen_data, st,
59*2d1272b8SAndroid Build Coastguard Worker 			   p1.x, p1.y);
60*2d1272b8SAndroid Build Coastguard Worker 	}
61*2d1272b8SAndroid Build Coastguard Worker 	break;
62*2d1272b8SAndroid Build Coastguard Worker 	case hb_outline_point_t::type_t::QUADRATIC_TO:
63*2d1272b8SAndroid Build Coastguard Worker 	{
64*2d1272b8SAndroid Build Coastguard Worker 	  hb_outline_point_t p2 = *it++;
65*2d1272b8SAndroid Build Coastguard Worker 	  pen->quadratic_to (pen_data, st,
66*2d1272b8SAndroid Build Coastguard Worker 				p1.x, p1.y,
67*2d1272b8SAndroid Build Coastguard Worker 				p2.x, p2.y);
68*2d1272b8SAndroid Build Coastguard Worker 	}
69*2d1272b8SAndroid Build Coastguard Worker 	break;
70*2d1272b8SAndroid Build Coastguard Worker 	case hb_outline_point_t::type_t::CUBIC_TO:
71*2d1272b8SAndroid Build Coastguard Worker 	{
72*2d1272b8SAndroid Build Coastguard Worker 	  hb_outline_point_t p2 = *it++;
73*2d1272b8SAndroid Build Coastguard Worker 	  hb_outline_point_t p3 = *it++;
74*2d1272b8SAndroid Build Coastguard Worker 	  pen->cubic_to (pen_data, st,
75*2d1272b8SAndroid Build Coastguard Worker 			    p1.x, p1.y,
76*2d1272b8SAndroid Build Coastguard Worker 			    p2.x, p2.y,
77*2d1272b8SAndroid Build Coastguard Worker 			    p3.x, p3.y);
78*2d1272b8SAndroid Build Coastguard Worker 	}
79*2d1272b8SAndroid Build Coastguard Worker 	break;
80*2d1272b8SAndroid Build Coastguard Worker       }
81*2d1272b8SAndroid Build Coastguard Worker     }
82*2d1272b8SAndroid Build Coastguard Worker     pen->close_path (pen_data, st);
83*2d1272b8SAndroid Build Coastguard Worker     first = contour;
84*2d1272b8SAndroid Build Coastguard Worker   }
85*2d1272b8SAndroid Build Coastguard Worker }
86*2d1272b8SAndroid Build Coastguard Worker 
control_area() const87*2d1272b8SAndroid Build Coastguard Worker float hb_outline_t::control_area () const
88*2d1272b8SAndroid Build Coastguard Worker {
89*2d1272b8SAndroid Build Coastguard Worker   float a = 0;
90*2d1272b8SAndroid Build Coastguard Worker   unsigned first = 0;
91*2d1272b8SAndroid Build Coastguard Worker   for (unsigned contour : contours)
92*2d1272b8SAndroid Build Coastguard Worker   {
93*2d1272b8SAndroid Build Coastguard Worker     for (unsigned i = first; i < contour; i++)
94*2d1272b8SAndroid Build Coastguard Worker     {
95*2d1272b8SAndroid Build Coastguard Worker       unsigned j = i + 1 < contour ? i + 1 : first;
96*2d1272b8SAndroid Build Coastguard Worker 
97*2d1272b8SAndroid Build Coastguard Worker       auto &pi = points[i];
98*2d1272b8SAndroid Build Coastguard Worker       auto &pj = points[j];
99*2d1272b8SAndroid Build Coastguard Worker       a += pi.x * pj.y - pi.y * pj.x;
100*2d1272b8SAndroid Build Coastguard Worker     }
101*2d1272b8SAndroid Build Coastguard Worker 
102*2d1272b8SAndroid Build Coastguard Worker     first = contour;
103*2d1272b8SAndroid Build Coastguard Worker   }
104*2d1272b8SAndroid Build Coastguard Worker   return a * .5f;
105*2d1272b8SAndroid Build Coastguard Worker }
106*2d1272b8SAndroid Build Coastguard Worker 
embolden(float x_strength,float y_strength,float x_shift,float y_shift)107*2d1272b8SAndroid Build Coastguard Worker void hb_outline_t::embolden (float x_strength, float y_strength,
108*2d1272b8SAndroid Build Coastguard Worker 			     float x_shift, float y_shift)
109*2d1272b8SAndroid Build Coastguard Worker {
110*2d1272b8SAndroid Build Coastguard Worker   /* This function is a straight port of FreeType's FT_Outline_EmboldenXY.
111*2d1272b8SAndroid Build Coastguard Worker    * Permission has been obtained from the FreeType authors of the code
112*2d1272b8SAndroid Build Coastguard Worker    * to relicense it under the HarfBuzz license. */
113*2d1272b8SAndroid Build Coastguard Worker 
114*2d1272b8SAndroid Build Coastguard Worker   if (!x_strength && !y_strength) return;
115*2d1272b8SAndroid Build Coastguard Worker   if (!points) return;
116*2d1272b8SAndroid Build Coastguard Worker 
117*2d1272b8SAndroid Build Coastguard Worker   x_strength /= 2.f;
118*2d1272b8SAndroid Build Coastguard Worker   y_strength /= 2.f;
119*2d1272b8SAndroid Build Coastguard Worker 
120*2d1272b8SAndroid Build Coastguard Worker   bool orientation_negative = control_area () < 0;
121*2d1272b8SAndroid Build Coastguard Worker 
122*2d1272b8SAndroid Build Coastguard Worker   signed first = 0;
123*2d1272b8SAndroid Build Coastguard Worker   for (unsigned c = 0; c < contours.length; c++)
124*2d1272b8SAndroid Build Coastguard Worker   {
125*2d1272b8SAndroid Build Coastguard Worker     hb_outline_vector_t in, out, anchor, shift;
126*2d1272b8SAndroid Build Coastguard Worker     float l_in, l_out, l_anchor = 0, l, q, d;
127*2d1272b8SAndroid Build Coastguard Worker 
128*2d1272b8SAndroid Build Coastguard Worker     l_in = 0;
129*2d1272b8SAndroid Build Coastguard Worker     signed last = (int) contours[c] - 1;
130*2d1272b8SAndroid Build Coastguard Worker 
131*2d1272b8SAndroid Build Coastguard Worker     /* pacify compiler */
132*2d1272b8SAndroid Build Coastguard Worker     in.x = in.y = anchor.x = anchor.y = 0;
133*2d1272b8SAndroid Build Coastguard Worker 
134*2d1272b8SAndroid Build Coastguard Worker     /* Counter j cycles though the points; counter i advances only  */
135*2d1272b8SAndroid Build Coastguard Worker     /* when points are moved; anchor k marks the first moved point. */
136*2d1272b8SAndroid Build Coastguard Worker     for ( signed i = last, j = first, k = -1;
137*2d1272b8SAndroid Build Coastguard Worker 	  j != i && i != k;
138*2d1272b8SAndroid Build Coastguard Worker 	  j = j < last ? j + 1 : first )
139*2d1272b8SAndroid Build Coastguard Worker     {
140*2d1272b8SAndroid Build Coastguard Worker       if ( j != k )
141*2d1272b8SAndroid Build Coastguard Worker       {
142*2d1272b8SAndroid Build Coastguard Worker 	out.x = points[j].x - points[i].x;
143*2d1272b8SAndroid Build Coastguard Worker 	out.y = points[j].y - points[i].y;
144*2d1272b8SAndroid Build Coastguard Worker 	l_out = out.normalize_len ();
145*2d1272b8SAndroid Build Coastguard Worker 
146*2d1272b8SAndroid Build Coastguard Worker 	if ( l_out == 0 )
147*2d1272b8SAndroid Build Coastguard Worker 	  continue;
148*2d1272b8SAndroid Build Coastguard Worker       }
149*2d1272b8SAndroid Build Coastguard Worker       else
150*2d1272b8SAndroid Build Coastguard Worker       {
151*2d1272b8SAndroid Build Coastguard Worker 	out   = anchor;
152*2d1272b8SAndroid Build Coastguard Worker 	l_out = l_anchor;
153*2d1272b8SAndroid Build Coastguard Worker       }
154*2d1272b8SAndroid Build Coastguard Worker 
155*2d1272b8SAndroid Build Coastguard Worker       if ( l_in != 0 )
156*2d1272b8SAndroid Build Coastguard Worker       {
157*2d1272b8SAndroid Build Coastguard Worker 	if ( k < 0 )
158*2d1272b8SAndroid Build Coastguard Worker 	{
159*2d1272b8SAndroid Build Coastguard Worker 	  k        = i;
160*2d1272b8SAndroid Build Coastguard Worker 	  anchor   = in;
161*2d1272b8SAndroid Build Coastguard Worker 	  l_anchor = l_in;
162*2d1272b8SAndroid Build Coastguard Worker 	}
163*2d1272b8SAndroid Build Coastguard Worker 
164*2d1272b8SAndroid Build Coastguard Worker 	d = in.x * out.x + in.y * out.y;
165*2d1272b8SAndroid Build Coastguard Worker 
166*2d1272b8SAndroid Build Coastguard Worker 	/* shift only if turn is less than ~160 degrees */
167*2d1272b8SAndroid Build Coastguard Worker 	if ( d > -15.f/16.f )
168*2d1272b8SAndroid Build Coastguard Worker 	{
169*2d1272b8SAndroid Build Coastguard Worker 	  d = d + 1.f;
170*2d1272b8SAndroid Build Coastguard Worker 
171*2d1272b8SAndroid Build Coastguard Worker 	  /* shift components along lateral bisector in proper orientation */
172*2d1272b8SAndroid Build Coastguard Worker 	  shift.x = in.y + out.y;
173*2d1272b8SAndroid Build Coastguard Worker 	  shift.y = in.x + out.x;
174*2d1272b8SAndroid Build Coastguard Worker 
175*2d1272b8SAndroid Build Coastguard Worker 	  if ( orientation_negative )
176*2d1272b8SAndroid Build Coastguard Worker 	    shift.x = -shift.x;
177*2d1272b8SAndroid Build Coastguard Worker 	  else
178*2d1272b8SAndroid Build Coastguard Worker 	    shift.y = -shift.y;
179*2d1272b8SAndroid Build Coastguard Worker 
180*2d1272b8SAndroid Build Coastguard Worker 	  /* restrict shift magnitude to better handle collapsing segments */
181*2d1272b8SAndroid Build Coastguard Worker 	  q = out.x * in.y - out.y * in.x;
182*2d1272b8SAndroid Build Coastguard Worker 	  if ( orientation_negative )
183*2d1272b8SAndroid Build Coastguard Worker 	    q = -q;
184*2d1272b8SAndroid Build Coastguard Worker 
185*2d1272b8SAndroid Build Coastguard Worker 	  l = hb_min (l_in, l_out);
186*2d1272b8SAndroid Build Coastguard Worker 
187*2d1272b8SAndroid Build Coastguard Worker 	  /* non-strict inequalities avoid divide-by-zero when q == l == 0 */
188*2d1272b8SAndroid Build Coastguard Worker 	  if (x_strength * q <= l * d)
189*2d1272b8SAndroid Build Coastguard Worker 	    shift.x = shift.x * x_strength / d;
190*2d1272b8SAndroid Build Coastguard Worker 	  else
191*2d1272b8SAndroid Build Coastguard Worker 	    shift.x = shift.x * l / q;
192*2d1272b8SAndroid Build Coastguard Worker 
193*2d1272b8SAndroid Build Coastguard Worker 
194*2d1272b8SAndroid Build Coastguard Worker 	  if (y_strength * q <= l * d)
195*2d1272b8SAndroid Build Coastguard Worker 	    shift.y = shift.y * y_strength / d;
196*2d1272b8SAndroid Build Coastguard Worker 	  else
197*2d1272b8SAndroid Build Coastguard Worker 	    shift.y = shift.y * l / q;
198*2d1272b8SAndroid Build Coastguard Worker 	}
199*2d1272b8SAndroid Build Coastguard Worker 	else
200*2d1272b8SAndroid Build Coastguard Worker 	  shift.x = shift.y = 0;
201*2d1272b8SAndroid Build Coastguard Worker 
202*2d1272b8SAndroid Build Coastguard Worker 	for ( ;
203*2d1272b8SAndroid Build Coastguard Worker 	      i != j;
204*2d1272b8SAndroid Build Coastguard Worker 	      i = i < last ? i + 1 : first )
205*2d1272b8SAndroid Build Coastguard Worker 	{
206*2d1272b8SAndroid Build Coastguard Worker 	  points[i].x += x_shift + shift.x;
207*2d1272b8SAndroid Build Coastguard Worker 	  points[i].y += y_shift + shift.y;
208*2d1272b8SAndroid Build Coastguard Worker 	}
209*2d1272b8SAndroid Build Coastguard Worker       }
210*2d1272b8SAndroid Build Coastguard Worker       else
211*2d1272b8SAndroid Build Coastguard Worker 	i = j;
212*2d1272b8SAndroid Build Coastguard Worker 
213*2d1272b8SAndroid Build Coastguard Worker       in   = out;
214*2d1272b8SAndroid Build Coastguard Worker       l_in = l_out;
215*2d1272b8SAndroid Build Coastguard Worker     }
216*2d1272b8SAndroid Build Coastguard Worker 
217*2d1272b8SAndroid Build Coastguard Worker     first = last + 1;
218*2d1272b8SAndroid Build Coastguard Worker   }
219*2d1272b8SAndroid Build Coastguard Worker }
220*2d1272b8SAndroid Build Coastguard Worker 
221*2d1272b8SAndroid Build Coastguard Worker static void
hb_outline_recording_pen_move_to(hb_draw_funcs_t * dfuncs HB_UNUSED,void * data,hb_draw_state_t * st,float to_x,float to_y,void * user_data HB_UNUSED)222*2d1272b8SAndroid Build Coastguard Worker hb_outline_recording_pen_move_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
223*2d1272b8SAndroid Build Coastguard Worker 				  void *data,
224*2d1272b8SAndroid Build Coastguard Worker 				  hb_draw_state_t *st,
225*2d1272b8SAndroid Build Coastguard Worker 				  float to_x, float to_y,
226*2d1272b8SAndroid Build Coastguard Worker 				  void *user_data HB_UNUSED)
227*2d1272b8SAndroid Build Coastguard Worker {
228*2d1272b8SAndroid Build Coastguard Worker   hb_outline_t *c = (hb_outline_t *) data;
229*2d1272b8SAndroid Build Coastguard Worker 
230*2d1272b8SAndroid Build Coastguard Worker   c->points.push (hb_outline_point_t {to_x, to_y, hb_outline_point_t::type_t::MOVE_TO});
231*2d1272b8SAndroid Build Coastguard Worker }
232*2d1272b8SAndroid Build Coastguard Worker 
233*2d1272b8SAndroid Build Coastguard Worker static void
hb_outline_recording_pen_line_to(hb_draw_funcs_t * dfuncs HB_UNUSED,void * data,hb_draw_state_t * st,float to_x,float to_y,void * user_data HB_UNUSED)234*2d1272b8SAndroid Build Coastguard Worker hb_outline_recording_pen_line_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
235*2d1272b8SAndroid Build Coastguard Worker 				  void *data,
236*2d1272b8SAndroid Build Coastguard Worker 				  hb_draw_state_t *st,
237*2d1272b8SAndroid Build Coastguard Worker 				  float to_x, float to_y,
238*2d1272b8SAndroid Build Coastguard Worker 				  void *user_data HB_UNUSED)
239*2d1272b8SAndroid Build Coastguard Worker {
240*2d1272b8SAndroid Build Coastguard Worker   hb_outline_t *c = (hb_outline_t *) data;
241*2d1272b8SAndroid Build Coastguard Worker 
242*2d1272b8SAndroid Build Coastguard Worker   c->points.push (hb_outline_point_t {to_x, to_y, hb_outline_point_t::type_t::LINE_TO});
243*2d1272b8SAndroid Build Coastguard Worker }
244*2d1272b8SAndroid Build Coastguard Worker 
245*2d1272b8SAndroid Build Coastguard Worker static void
hb_outline_recording_pen_quadratic_to(hb_draw_funcs_t * dfuncs HB_UNUSED,void * data,hb_draw_state_t * st,float control_x,float control_y,float to_x,float to_y,void * user_data HB_UNUSED)246*2d1272b8SAndroid Build Coastguard Worker hb_outline_recording_pen_quadratic_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
247*2d1272b8SAndroid Build Coastguard Worker 				       void *data,
248*2d1272b8SAndroid Build Coastguard Worker 				       hb_draw_state_t *st,
249*2d1272b8SAndroid Build Coastguard Worker 				       float control_x, float control_y,
250*2d1272b8SAndroid Build Coastguard Worker 				       float to_x, float to_y,
251*2d1272b8SAndroid Build Coastguard Worker 				       void *user_data HB_UNUSED)
252*2d1272b8SAndroid Build Coastguard Worker {
253*2d1272b8SAndroid Build Coastguard Worker   hb_outline_t *c = (hb_outline_t *) data;
254*2d1272b8SAndroid Build Coastguard Worker 
255*2d1272b8SAndroid Build Coastguard Worker   c->points.push (hb_outline_point_t {control_x, control_y, hb_outline_point_t::type_t::QUADRATIC_TO});
256*2d1272b8SAndroid Build Coastguard Worker   c->points.push (hb_outline_point_t {to_x, to_y, hb_outline_point_t::type_t::QUADRATIC_TO});
257*2d1272b8SAndroid Build Coastguard Worker }
258*2d1272b8SAndroid Build Coastguard Worker 
259*2d1272b8SAndroid Build Coastguard Worker static void
hb_outline_recording_pen_cubic_to(hb_draw_funcs_t * dfuncs HB_UNUSED,void * data,hb_draw_state_t * st,float control1_x,float control1_y,float control2_x,float control2_y,float to_x,float to_y,void * user_data HB_UNUSED)260*2d1272b8SAndroid Build Coastguard Worker hb_outline_recording_pen_cubic_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
261*2d1272b8SAndroid Build Coastguard Worker 				   void *data,
262*2d1272b8SAndroid Build Coastguard Worker 				   hb_draw_state_t *st,
263*2d1272b8SAndroid Build Coastguard Worker 				   float control1_x, float control1_y,
264*2d1272b8SAndroid Build Coastguard Worker 				   float control2_x, float control2_y,
265*2d1272b8SAndroid Build Coastguard Worker 				   float to_x, float to_y,
266*2d1272b8SAndroid Build Coastguard Worker 				   void *user_data HB_UNUSED)
267*2d1272b8SAndroid Build Coastguard Worker {
268*2d1272b8SAndroid Build Coastguard Worker   hb_outline_t *c = (hb_outline_t *) data;
269*2d1272b8SAndroid Build Coastguard Worker 
270*2d1272b8SAndroid Build Coastguard Worker   c->points.push (hb_outline_point_t {control1_x, control1_y, hb_outline_point_t::type_t::CUBIC_TO});
271*2d1272b8SAndroid Build Coastguard Worker   c->points.push (hb_outline_point_t {control2_x, control2_y, hb_outline_point_t::type_t::CUBIC_TO});
272*2d1272b8SAndroid Build Coastguard Worker   c->points.push (hb_outline_point_t {to_x, to_y, hb_outline_point_t::type_t::CUBIC_TO});
273*2d1272b8SAndroid Build Coastguard Worker }
274*2d1272b8SAndroid Build Coastguard Worker 
275*2d1272b8SAndroid Build Coastguard Worker static void
hb_outline_recording_pen_close_path(hb_draw_funcs_t * dfuncs HB_UNUSED,void * data,hb_draw_state_t * st,void * user_data HB_UNUSED)276*2d1272b8SAndroid Build Coastguard Worker hb_outline_recording_pen_close_path (hb_draw_funcs_t *dfuncs HB_UNUSED,
277*2d1272b8SAndroid Build Coastguard Worker 				     void *data,
278*2d1272b8SAndroid Build Coastguard Worker 				     hb_draw_state_t *st,
279*2d1272b8SAndroid Build Coastguard Worker 				     void *user_data HB_UNUSED)
280*2d1272b8SAndroid Build Coastguard Worker {
281*2d1272b8SAndroid Build Coastguard Worker   hb_outline_t *c = (hb_outline_t *) data;
282*2d1272b8SAndroid Build Coastguard Worker 
283*2d1272b8SAndroid Build Coastguard Worker   c->contours.push (c->points.length);
284*2d1272b8SAndroid Build Coastguard Worker }
285*2d1272b8SAndroid Build Coastguard Worker 
286*2d1272b8SAndroid Build Coastguard Worker static inline void free_static_outline_recording_pen_funcs ();
287*2d1272b8SAndroid Build Coastguard Worker 
288*2d1272b8SAndroid Build Coastguard Worker static struct hb_outline_recording_pen_funcs_lazy_loader_t : hb_draw_funcs_lazy_loader_t<hb_outline_recording_pen_funcs_lazy_loader_t>
289*2d1272b8SAndroid Build Coastguard Worker {
createhb_outline_recording_pen_funcs_lazy_loader_t290*2d1272b8SAndroid Build Coastguard Worker   static hb_draw_funcs_t *create ()
291*2d1272b8SAndroid Build Coastguard Worker   {
292*2d1272b8SAndroid Build Coastguard Worker     hb_draw_funcs_t *funcs = hb_draw_funcs_create ();
293*2d1272b8SAndroid Build Coastguard Worker 
294*2d1272b8SAndroid Build Coastguard Worker     hb_draw_funcs_set_move_to_func (funcs, hb_outline_recording_pen_move_to, nullptr, nullptr);
295*2d1272b8SAndroid Build Coastguard Worker     hb_draw_funcs_set_line_to_func (funcs, hb_outline_recording_pen_line_to, nullptr, nullptr);
296*2d1272b8SAndroid Build Coastguard Worker     hb_draw_funcs_set_quadratic_to_func (funcs, hb_outline_recording_pen_quadratic_to, nullptr, nullptr);
297*2d1272b8SAndroid Build Coastguard Worker     hb_draw_funcs_set_cubic_to_func (funcs, hb_outline_recording_pen_cubic_to, nullptr, nullptr);
298*2d1272b8SAndroid Build Coastguard Worker     hb_draw_funcs_set_close_path_func (funcs, hb_outline_recording_pen_close_path, nullptr, nullptr);
299*2d1272b8SAndroid Build Coastguard Worker 
300*2d1272b8SAndroid Build Coastguard Worker     hb_draw_funcs_make_immutable (funcs);
301*2d1272b8SAndroid Build Coastguard Worker 
302*2d1272b8SAndroid Build Coastguard Worker     hb_atexit (free_static_outline_recording_pen_funcs);
303*2d1272b8SAndroid Build Coastguard Worker 
304*2d1272b8SAndroid Build Coastguard Worker     return funcs;
305*2d1272b8SAndroid Build Coastguard Worker   }
306*2d1272b8SAndroid Build Coastguard Worker } static_outline_recording_pen_funcs;
307*2d1272b8SAndroid Build Coastguard Worker 
308*2d1272b8SAndroid Build Coastguard Worker static inline
free_static_outline_recording_pen_funcs()309*2d1272b8SAndroid Build Coastguard Worker void free_static_outline_recording_pen_funcs ()
310*2d1272b8SAndroid Build Coastguard Worker {
311*2d1272b8SAndroid Build Coastguard Worker   static_outline_recording_pen_funcs.free_instance ();
312*2d1272b8SAndroid Build Coastguard Worker }
313*2d1272b8SAndroid Build Coastguard Worker 
314*2d1272b8SAndroid Build Coastguard Worker hb_draw_funcs_t *
hb_outline_recording_pen_get_funcs()315*2d1272b8SAndroid Build Coastguard Worker hb_outline_recording_pen_get_funcs ()
316*2d1272b8SAndroid Build Coastguard Worker {
317*2d1272b8SAndroid Build Coastguard Worker   return static_outline_recording_pen_funcs.get_unconst ();
318*2d1272b8SAndroid Build Coastguard Worker }
319*2d1272b8SAndroid Build Coastguard Worker 
320*2d1272b8SAndroid Build Coastguard Worker 
321*2d1272b8SAndroid Build Coastguard Worker #endif
322