xref: /aosp_15_r20/external/harfbuzz_ng/src/hb-shape-plan.cc (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
1*2d1272b8SAndroid Build Coastguard Worker /*
2*2d1272b8SAndroid Build Coastguard Worker  * Copyright © 2012  Google, Inc.
3*2d1272b8SAndroid Build Coastguard Worker  *
4*2d1272b8SAndroid Build Coastguard Worker  *  This is part of HarfBuzz, a text shaping library.
5*2d1272b8SAndroid Build Coastguard Worker  *
6*2d1272b8SAndroid Build Coastguard Worker  * Permission is hereby granted, without written agreement and without
7*2d1272b8SAndroid Build Coastguard Worker  * license or royalty fees, to use, copy, modify, and distribute this
8*2d1272b8SAndroid Build Coastguard Worker  * software and its documentation for any purpose, provided that the
9*2d1272b8SAndroid Build Coastguard Worker  * above copyright notice and the following two paragraphs appear in
10*2d1272b8SAndroid Build Coastguard Worker  * all copies of this software.
11*2d1272b8SAndroid Build Coastguard Worker  *
12*2d1272b8SAndroid Build Coastguard Worker  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13*2d1272b8SAndroid Build Coastguard Worker  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14*2d1272b8SAndroid Build Coastguard Worker  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15*2d1272b8SAndroid Build Coastguard Worker  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16*2d1272b8SAndroid Build Coastguard Worker  * DAMAGE.
17*2d1272b8SAndroid Build Coastguard Worker  *
18*2d1272b8SAndroid Build Coastguard Worker  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19*2d1272b8SAndroid Build Coastguard Worker  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20*2d1272b8SAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
21*2d1272b8SAndroid Build Coastguard Worker  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22*2d1272b8SAndroid Build Coastguard Worker  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23*2d1272b8SAndroid Build Coastguard Worker  *
24*2d1272b8SAndroid Build Coastguard Worker  * Google Author(s): Behdad Esfahbod
25*2d1272b8SAndroid Build Coastguard Worker  */
26*2d1272b8SAndroid Build Coastguard Worker 
27*2d1272b8SAndroid Build Coastguard Worker #include "hb.hh"
28*2d1272b8SAndroid Build Coastguard Worker #include "hb-shape-plan.hh"
29*2d1272b8SAndroid Build Coastguard Worker #include "hb-shaper.hh"
30*2d1272b8SAndroid Build Coastguard Worker #include "hb-font.hh"
31*2d1272b8SAndroid Build Coastguard Worker #include "hb-buffer.hh"
32*2d1272b8SAndroid Build Coastguard Worker 
33*2d1272b8SAndroid Build Coastguard Worker 
34*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_NO_SHAPER
35*2d1272b8SAndroid Build Coastguard Worker 
36*2d1272b8SAndroid Build Coastguard Worker /**
37*2d1272b8SAndroid Build Coastguard Worker  * SECTION:hb-shape-plan
38*2d1272b8SAndroid Build Coastguard Worker  * @title: hb-shape-plan
39*2d1272b8SAndroid Build Coastguard Worker  * @short_description: Object representing a shaping plan
40*2d1272b8SAndroid Build Coastguard Worker  * @include: hb.h
41*2d1272b8SAndroid Build Coastguard Worker  *
42*2d1272b8SAndroid Build Coastguard Worker  * Shape plans are an internal mechanism. Each plan contains state
43*2d1272b8SAndroid Build Coastguard Worker  * describing how HarfBuzz will shape a particular text segment, based on
44*2d1272b8SAndroid Build Coastguard Worker  * the combination of segment properties and the capabilities in the
45*2d1272b8SAndroid Build Coastguard Worker  * font face in use.
46*2d1272b8SAndroid Build Coastguard Worker  *
47*2d1272b8SAndroid Build Coastguard Worker  * Shape plans are not used for shaping directly, but can be queried to
48*2d1272b8SAndroid Build Coastguard Worker  * access certain information about how shaping will perform, given a set
49*2d1272b8SAndroid Build Coastguard Worker  * of specific input parameters (script, language, direction, features,
50*2d1272b8SAndroid Build Coastguard Worker  * etc.).
51*2d1272b8SAndroid Build Coastguard Worker  *
52*2d1272b8SAndroid Build Coastguard Worker  * Most client programs will not need to deal with shape plans directly.
53*2d1272b8SAndroid Build Coastguard Worker  **/
54*2d1272b8SAndroid Build Coastguard Worker 
55*2d1272b8SAndroid Build Coastguard Worker 
56*2d1272b8SAndroid Build Coastguard Worker /*
57*2d1272b8SAndroid Build Coastguard Worker  * hb_shape_plan_key_t
58*2d1272b8SAndroid Build Coastguard Worker  */
59*2d1272b8SAndroid Build Coastguard Worker 
60*2d1272b8SAndroid Build Coastguard Worker bool
init(bool copy,hb_face_t * face,const hb_segment_properties_t * props,const hb_feature_t * user_features,unsigned int num_user_features,const int * coords,unsigned int num_coords,const char * const * shaper_list)61*2d1272b8SAndroid Build Coastguard Worker hb_shape_plan_key_t::init (bool                           copy,
62*2d1272b8SAndroid Build Coastguard Worker 			   hb_face_t                     *face,
63*2d1272b8SAndroid Build Coastguard Worker 			   const hb_segment_properties_t *props,
64*2d1272b8SAndroid Build Coastguard Worker 			   const hb_feature_t            *user_features,
65*2d1272b8SAndroid Build Coastguard Worker 			   unsigned int                   num_user_features,
66*2d1272b8SAndroid Build Coastguard Worker 			   const int                     *coords,
67*2d1272b8SAndroid Build Coastguard Worker 			   unsigned int                   num_coords,
68*2d1272b8SAndroid Build Coastguard Worker 			   const char * const            *shaper_list)
69*2d1272b8SAndroid Build Coastguard Worker {
70*2d1272b8SAndroid Build Coastguard Worker   hb_feature_t *features = nullptr;
71*2d1272b8SAndroid Build Coastguard Worker   if (copy && num_user_features && !(features = (hb_feature_t *) hb_calloc (num_user_features, sizeof (hb_feature_t))))
72*2d1272b8SAndroid Build Coastguard Worker     goto bail;
73*2d1272b8SAndroid Build Coastguard Worker 
74*2d1272b8SAndroid Build Coastguard Worker   this->props = *props;
75*2d1272b8SAndroid Build Coastguard Worker   this->num_user_features = num_user_features;
76*2d1272b8SAndroid Build Coastguard Worker   this->user_features = copy ? features : user_features;
77*2d1272b8SAndroid Build Coastguard Worker   if (copy && num_user_features)
78*2d1272b8SAndroid Build Coastguard Worker   {
79*2d1272b8SAndroid Build Coastguard Worker     hb_memcpy (features, user_features, num_user_features * sizeof (hb_feature_t));
80*2d1272b8SAndroid Build Coastguard Worker     /* Make start/end uniform to easier catch bugs. */
81*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int i = 0; i < num_user_features; i++)
82*2d1272b8SAndroid Build Coastguard Worker     {
83*2d1272b8SAndroid Build Coastguard Worker       if (features[0].start != HB_FEATURE_GLOBAL_START)
84*2d1272b8SAndroid Build Coastguard Worker 	features[0].start = 1;
85*2d1272b8SAndroid Build Coastguard Worker       if (features[0].end   != HB_FEATURE_GLOBAL_END)
86*2d1272b8SAndroid Build Coastguard Worker 	features[0].end   = 2;
87*2d1272b8SAndroid Build Coastguard Worker     }
88*2d1272b8SAndroid Build Coastguard Worker   }
89*2d1272b8SAndroid Build Coastguard Worker   this->shaper_func = nullptr;
90*2d1272b8SAndroid Build Coastguard Worker   this->shaper_name = nullptr;
91*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_NO_OT_SHAPE
92*2d1272b8SAndroid Build Coastguard Worker   this->ot.init (face, coords, num_coords);
93*2d1272b8SAndroid Build Coastguard Worker #endif
94*2d1272b8SAndroid Build Coastguard Worker 
95*2d1272b8SAndroid Build Coastguard Worker   /*
96*2d1272b8SAndroid Build Coastguard Worker    * Choose shaper.
97*2d1272b8SAndroid Build Coastguard Worker    */
98*2d1272b8SAndroid Build Coastguard Worker 
99*2d1272b8SAndroid Build Coastguard Worker #define HB_SHAPER_PLAN(shaper) \
100*2d1272b8SAndroid Build Coastguard Worker 	HB_STMT_START { \
101*2d1272b8SAndroid Build Coastguard Worker 	  if (face->data.shaper) \
102*2d1272b8SAndroid Build Coastguard Worker 	  { \
103*2d1272b8SAndroid Build Coastguard Worker 	    this->shaper_func = _hb_##shaper##_shape; \
104*2d1272b8SAndroid Build Coastguard Worker 	    this->shaper_name = #shaper; \
105*2d1272b8SAndroid Build Coastguard Worker 	    return true; \
106*2d1272b8SAndroid Build Coastguard Worker 	  } \
107*2d1272b8SAndroid Build Coastguard Worker 	} HB_STMT_END
108*2d1272b8SAndroid Build Coastguard Worker 
109*2d1272b8SAndroid Build Coastguard Worker   if (unlikely (shaper_list))
110*2d1272b8SAndroid Build Coastguard Worker   {
111*2d1272b8SAndroid Build Coastguard Worker     for (; *shaper_list; shaper_list++)
112*2d1272b8SAndroid Build Coastguard Worker       if (false)
113*2d1272b8SAndroid Build Coastguard Worker 	;
114*2d1272b8SAndroid Build Coastguard Worker #define HB_SHAPER_IMPLEMENT(shaper) \
115*2d1272b8SAndroid Build Coastguard Worker       else if (0 == strcmp (*shaper_list, #shaper)) \
116*2d1272b8SAndroid Build Coastguard Worker 	HB_SHAPER_PLAN (shaper);
117*2d1272b8SAndroid Build Coastguard Worker #include "hb-shaper-list.hh"
118*2d1272b8SAndroid Build Coastguard Worker #undef HB_SHAPER_IMPLEMENT
119*2d1272b8SAndroid Build Coastguard Worker   }
120*2d1272b8SAndroid Build Coastguard Worker   else
121*2d1272b8SAndroid Build Coastguard Worker   {
122*2d1272b8SAndroid Build Coastguard Worker     const HB_UNUSED hb_shaper_entry_t *shapers = _hb_shapers_get ();
123*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int i = 0; i < HB_SHAPERS_COUNT; i++)
124*2d1272b8SAndroid Build Coastguard Worker       if (false)
125*2d1272b8SAndroid Build Coastguard Worker 	;
126*2d1272b8SAndroid Build Coastguard Worker #define HB_SHAPER_IMPLEMENT(shaper) \
127*2d1272b8SAndroid Build Coastguard Worker       else if (shapers[i].func == _hb_##shaper##_shape) \
128*2d1272b8SAndroid Build Coastguard Worker 	HB_SHAPER_PLAN (shaper);
129*2d1272b8SAndroid Build Coastguard Worker #include "hb-shaper-list.hh"
130*2d1272b8SAndroid Build Coastguard Worker #undef HB_SHAPER_IMPLEMENT
131*2d1272b8SAndroid Build Coastguard Worker   }
132*2d1272b8SAndroid Build Coastguard Worker #undef HB_SHAPER_PLAN
133*2d1272b8SAndroid Build Coastguard Worker 
134*2d1272b8SAndroid Build Coastguard Worker bail:
135*2d1272b8SAndroid Build Coastguard Worker   ::hb_free (features);
136*2d1272b8SAndroid Build Coastguard Worker   return false;
137*2d1272b8SAndroid Build Coastguard Worker }
138*2d1272b8SAndroid Build Coastguard Worker 
139*2d1272b8SAndroid Build Coastguard Worker bool
user_features_match(const hb_shape_plan_key_t * other)140*2d1272b8SAndroid Build Coastguard Worker hb_shape_plan_key_t::user_features_match (const hb_shape_plan_key_t *other)
141*2d1272b8SAndroid Build Coastguard Worker {
142*2d1272b8SAndroid Build Coastguard Worker   if (this->num_user_features != other->num_user_features)
143*2d1272b8SAndroid Build Coastguard Worker     return false;
144*2d1272b8SAndroid Build Coastguard Worker   for (unsigned int i = 0; i < num_user_features; i++)
145*2d1272b8SAndroid Build Coastguard Worker   {
146*2d1272b8SAndroid Build Coastguard Worker     if (this->user_features[i].tag   != other->user_features[i].tag   ||
147*2d1272b8SAndroid Build Coastguard Worker 	this->user_features[i].value != other->user_features[i].value ||
148*2d1272b8SAndroid Build Coastguard Worker 	(this->user_features[i].start == HB_FEATURE_GLOBAL_START &&
149*2d1272b8SAndroid Build Coastguard Worker 	 this->user_features[i].end   == HB_FEATURE_GLOBAL_END) !=
150*2d1272b8SAndroid Build Coastguard Worker 	(other->user_features[i].start == HB_FEATURE_GLOBAL_START &&
151*2d1272b8SAndroid Build Coastguard Worker 	 other->user_features[i].end   == HB_FEATURE_GLOBAL_END))
152*2d1272b8SAndroid Build Coastguard Worker       return false;
153*2d1272b8SAndroid Build Coastguard Worker   }
154*2d1272b8SAndroid Build Coastguard Worker   return true;
155*2d1272b8SAndroid Build Coastguard Worker }
156*2d1272b8SAndroid Build Coastguard Worker 
157*2d1272b8SAndroid Build Coastguard Worker bool
equal(const hb_shape_plan_key_t * other)158*2d1272b8SAndroid Build Coastguard Worker hb_shape_plan_key_t::equal (const hb_shape_plan_key_t *other)
159*2d1272b8SAndroid Build Coastguard Worker {
160*2d1272b8SAndroid Build Coastguard Worker   return hb_segment_properties_equal (&this->props, &other->props) &&
161*2d1272b8SAndroid Build Coastguard Worker 	 this->user_features_match (other) &&
162*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_NO_OT_SHAPE
163*2d1272b8SAndroid Build Coastguard Worker 	 this->ot.equal (&other->ot) &&
164*2d1272b8SAndroid Build Coastguard Worker #endif
165*2d1272b8SAndroid Build Coastguard Worker 	 this->shaper_func == other->shaper_func;
166*2d1272b8SAndroid Build Coastguard Worker }
167*2d1272b8SAndroid Build Coastguard Worker 
168*2d1272b8SAndroid Build Coastguard Worker 
169*2d1272b8SAndroid Build Coastguard Worker /*
170*2d1272b8SAndroid Build Coastguard Worker  * hb_shape_plan_t
171*2d1272b8SAndroid Build Coastguard Worker  */
172*2d1272b8SAndroid Build Coastguard Worker 
173*2d1272b8SAndroid Build Coastguard Worker 
174*2d1272b8SAndroid Build Coastguard Worker /**
175*2d1272b8SAndroid Build Coastguard Worker  * hb_shape_plan_create:
176*2d1272b8SAndroid Build Coastguard Worker  * @face: #hb_face_t to use
177*2d1272b8SAndroid Build Coastguard Worker  * @props: The #hb_segment_properties_t of the segment
178*2d1272b8SAndroid Build Coastguard Worker  * @user_features: (array length=num_user_features): The list of user-selected features
179*2d1272b8SAndroid Build Coastguard Worker  * @num_user_features: The number of user-selected features
180*2d1272b8SAndroid Build Coastguard Worker  * @shaper_list: (array zero-terminated=1): List of shapers to try
181*2d1272b8SAndroid Build Coastguard Worker  *
182*2d1272b8SAndroid Build Coastguard Worker  * Constructs a shaping plan for a combination of @face, @user_features, @props,
183*2d1272b8SAndroid Build Coastguard Worker  * and @shaper_list.
184*2d1272b8SAndroid Build Coastguard Worker  *
185*2d1272b8SAndroid Build Coastguard Worker  * Return value: (transfer full): The shaping plan
186*2d1272b8SAndroid Build Coastguard Worker  *
187*2d1272b8SAndroid Build Coastguard Worker  * Since: 0.9.7
188*2d1272b8SAndroid Build Coastguard Worker  **/
189*2d1272b8SAndroid Build Coastguard Worker hb_shape_plan_t *
hb_shape_plan_create(hb_face_t * face,const hb_segment_properties_t * props,const hb_feature_t * user_features,unsigned int num_user_features,const char * const * shaper_list)190*2d1272b8SAndroid Build Coastguard Worker hb_shape_plan_create (hb_face_t                     *face,
191*2d1272b8SAndroid Build Coastguard Worker 		      const hb_segment_properties_t *props,
192*2d1272b8SAndroid Build Coastguard Worker 		      const hb_feature_t            *user_features,
193*2d1272b8SAndroid Build Coastguard Worker 		      unsigned int                   num_user_features,
194*2d1272b8SAndroid Build Coastguard Worker 		      const char * const            *shaper_list)
195*2d1272b8SAndroid Build Coastguard Worker {
196*2d1272b8SAndroid Build Coastguard Worker   return hb_shape_plan_create2 (face, props,
197*2d1272b8SAndroid Build Coastguard Worker 				user_features, num_user_features,
198*2d1272b8SAndroid Build Coastguard Worker 				nullptr, 0,
199*2d1272b8SAndroid Build Coastguard Worker 				shaper_list);
200*2d1272b8SAndroid Build Coastguard Worker }
201*2d1272b8SAndroid Build Coastguard Worker 
202*2d1272b8SAndroid Build Coastguard Worker /**
203*2d1272b8SAndroid Build Coastguard Worker  * hb_shape_plan_create2:
204*2d1272b8SAndroid Build Coastguard Worker  * @face: #hb_face_t to use
205*2d1272b8SAndroid Build Coastguard Worker  * @props: The #hb_segment_properties_t of the segment
206*2d1272b8SAndroid Build Coastguard Worker  * @user_features: (array length=num_user_features): The list of user-selected features
207*2d1272b8SAndroid Build Coastguard Worker  * @num_user_features: The number of user-selected features
208*2d1272b8SAndroid Build Coastguard Worker  * @coords: (array length=num_coords): The list of variation-space coordinates
209*2d1272b8SAndroid Build Coastguard Worker  * @num_coords: The number of variation-space coordinates
210*2d1272b8SAndroid Build Coastguard Worker  * @shaper_list: (array zero-terminated=1): List of shapers to try
211*2d1272b8SAndroid Build Coastguard Worker  *
212*2d1272b8SAndroid Build Coastguard Worker  * The variable-font version of #hb_shape_plan_create.
213*2d1272b8SAndroid Build Coastguard Worker  * Constructs a shaping plan for a combination of @face, @user_features, @props,
214*2d1272b8SAndroid Build Coastguard Worker  * and @shaper_list, plus the variation-space coordinates @coords.
215*2d1272b8SAndroid Build Coastguard Worker  *
216*2d1272b8SAndroid Build Coastguard Worker  * Return value: (transfer full): The shaping plan
217*2d1272b8SAndroid Build Coastguard Worker  *
218*2d1272b8SAndroid Build Coastguard Worker  * Since: 1.4.0
219*2d1272b8SAndroid Build Coastguard Worker  **/
220*2d1272b8SAndroid Build Coastguard Worker hb_shape_plan_t *
hb_shape_plan_create2(hb_face_t * face,const hb_segment_properties_t * props,const hb_feature_t * user_features,unsigned int num_user_features,const int * coords,unsigned int num_coords,const char * const * shaper_list)221*2d1272b8SAndroid Build Coastguard Worker hb_shape_plan_create2 (hb_face_t                     *face,
222*2d1272b8SAndroid Build Coastguard Worker 		       const hb_segment_properties_t *props,
223*2d1272b8SAndroid Build Coastguard Worker 		       const hb_feature_t            *user_features,
224*2d1272b8SAndroid Build Coastguard Worker 		       unsigned int                   num_user_features,
225*2d1272b8SAndroid Build Coastguard Worker 		       const int                     *coords,
226*2d1272b8SAndroid Build Coastguard Worker 		       unsigned int                   num_coords,
227*2d1272b8SAndroid Build Coastguard Worker 		       const char * const            *shaper_list)
228*2d1272b8SAndroid Build Coastguard Worker {
229*2d1272b8SAndroid Build Coastguard Worker   DEBUG_MSG_FUNC (SHAPE_PLAN, nullptr,
230*2d1272b8SAndroid Build Coastguard Worker 		  "face=%p num_features=%u num_coords=%u shaper_list=%p",
231*2d1272b8SAndroid Build Coastguard Worker 		  face,
232*2d1272b8SAndroid Build Coastguard Worker 		  num_user_features,
233*2d1272b8SAndroid Build Coastguard Worker 		  num_coords,
234*2d1272b8SAndroid Build Coastguard Worker 		  shaper_list);
235*2d1272b8SAndroid Build Coastguard Worker 
236*2d1272b8SAndroid Build Coastguard Worker   if (unlikely (props->direction == HB_DIRECTION_INVALID))
237*2d1272b8SAndroid Build Coastguard Worker     return hb_shape_plan_get_empty ();
238*2d1272b8SAndroid Build Coastguard Worker 
239*2d1272b8SAndroid Build Coastguard Worker   hb_shape_plan_t *shape_plan;
240*2d1272b8SAndroid Build Coastguard Worker 
241*2d1272b8SAndroid Build Coastguard Worker   if (unlikely (!props))
242*2d1272b8SAndroid Build Coastguard Worker     goto bail;
243*2d1272b8SAndroid Build Coastguard Worker   if (!(shape_plan = hb_object_create<hb_shape_plan_t> ()))
244*2d1272b8SAndroid Build Coastguard Worker     goto bail;
245*2d1272b8SAndroid Build Coastguard Worker 
246*2d1272b8SAndroid Build Coastguard Worker   if (unlikely (!face))
247*2d1272b8SAndroid Build Coastguard Worker     face = hb_face_get_empty ();
248*2d1272b8SAndroid Build Coastguard Worker   hb_face_make_immutable (face);
249*2d1272b8SAndroid Build Coastguard Worker   shape_plan->face_unsafe = face;
250*2d1272b8SAndroid Build Coastguard Worker 
251*2d1272b8SAndroid Build Coastguard Worker   if (unlikely (!shape_plan->key.init (true,
252*2d1272b8SAndroid Build Coastguard Worker 				       face,
253*2d1272b8SAndroid Build Coastguard Worker 				       props,
254*2d1272b8SAndroid Build Coastguard Worker 				       user_features,
255*2d1272b8SAndroid Build Coastguard Worker 				       num_user_features,
256*2d1272b8SAndroid Build Coastguard Worker 				       coords,
257*2d1272b8SAndroid Build Coastguard Worker 				       num_coords,
258*2d1272b8SAndroid Build Coastguard Worker 				       shaper_list)))
259*2d1272b8SAndroid Build Coastguard Worker     goto bail2;
260*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_NO_OT_SHAPE
261*2d1272b8SAndroid Build Coastguard Worker   if (unlikely (!shape_plan->ot.init0 (face, &shape_plan->key)))
262*2d1272b8SAndroid Build Coastguard Worker     goto bail3;
263*2d1272b8SAndroid Build Coastguard Worker #endif
264*2d1272b8SAndroid Build Coastguard Worker 
265*2d1272b8SAndroid Build Coastguard Worker   return shape_plan;
266*2d1272b8SAndroid Build Coastguard Worker 
267*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_NO_OT_SHAPE
268*2d1272b8SAndroid Build Coastguard Worker bail3:
269*2d1272b8SAndroid Build Coastguard Worker #endif
270*2d1272b8SAndroid Build Coastguard Worker   shape_plan->key.fini ();
271*2d1272b8SAndroid Build Coastguard Worker bail2:
272*2d1272b8SAndroid Build Coastguard Worker   hb_free (shape_plan);
273*2d1272b8SAndroid Build Coastguard Worker bail:
274*2d1272b8SAndroid Build Coastguard Worker   return hb_shape_plan_get_empty ();
275*2d1272b8SAndroid Build Coastguard Worker }
276*2d1272b8SAndroid Build Coastguard Worker 
277*2d1272b8SAndroid Build Coastguard Worker /**
278*2d1272b8SAndroid Build Coastguard Worker  * hb_shape_plan_get_empty:
279*2d1272b8SAndroid Build Coastguard Worker  *
280*2d1272b8SAndroid Build Coastguard Worker  * Fetches the singleton empty shaping plan.
281*2d1272b8SAndroid Build Coastguard Worker  *
282*2d1272b8SAndroid Build Coastguard Worker  * Return value: (transfer full): The empty shaping plan
283*2d1272b8SAndroid Build Coastguard Worker  *
284*2d1272b8SAndroid Build Coastguard Worker  * Since: 0.9.7
285*2d1272b8SAndroid Build Coastguard Worker  **/
286*2d1272b8SAndroid Build Coastguard Worker hb_shape_plan_t *
hb_shape_plan_get_empty()287*2d1272b8SAndroid Build Coastguard Worker hb_shape_plan_get_empty ()
288*2d1272b8SAndroid Build Coastguard Worker {
289*2d1272b8SAndroid Build Coastguard Worker   return const_cast<hb_shape_plan_t *> (&Null (hb_shape_plan_t));
290*2d1272b8SAndroid Build Coastguard Worker }
291*2d1272b8SAndroid Build Coastguard Worker 
292*2d1272b8SAndroid Build Coastguard Worker /**
293*2d1272b8SAndroid Build Coastguard Worker  * hb_shape_plan_reference: (skip)
294*2d1272b8SAndroid Build Coastguard Worker  * @shape_plan: A shaping plan
295*2d1272b8SAndroid Build Coastguard Worker  *
296*2d1272b8SAndroid Build Coastguard Worker  * Increases the reference count on the given shaping plan.
297*2d1272b8SAndroid Build Coastguard Worker  *
298*2d1272b8SAndroid Build Coastguard Worker  * Return value: (transfer full): @shape_plan
299*2d1272b8SAndroid Build Coastguard Worker  *
300*2d1272b8SAndroid Build Coastguard Worker  * Since: 0.9.7
301*2d1272b8SAndroid Build Coastguard Worker  **/
302*2d1272b8SAndroid Build Coastguard Worker hb_shape_plan_t *
hb_shape_plan_reference(hb_shape_plan_t * shape_plan)303*2d1272b8SAndroid Build Coastguard Worker hb_shape_plan_reference (hb_shape_plan_t *shape_plan)
304*2d1272b8SAndroid Build Coastguard Worker {
305*2d1272b8SAndroid Build Coastguard Worker   return hb_object_reference (shape_plan);
306*2d1272b8SAndroid Build Coastguard Worker }
307*2d1272b8SAndroid Build Coastguard Worker 
308*2d1272b8SAndroid Build Coastguard Worker /**
309*2d1272b8SAndroid Build Coastguard Worker  * hb_shape_plan_destroy: (skip)
310*2d1272b8SAndroid Build Coastguard Worker  * @shape_plan: A shaping plan
311*2d1272b8SAndroid Build Coastguard Worker  *
312*2d1272b8SAndroid Build Coastguard Worker  * Decreases the reference count on the given shaping plan. When the
313*2d1272b8SAndroid Build Coastguard Worker  * reference count reaches zero, the shaping plan is destroyed,
314*2d1272b8SAndroid Build Coastguard Worker  * freeing all memory.
315*2d1272b8SAndroid Build Coastguard Worker  *
316*2d1272b8SAndroid Build Coastguard Worker  * Since: 0.9.7
317*2d1272b8SAndroid Build Coastguard Worker  **/
318*2d1272b8SAndroid Build Coastguard Worker void
hb_shape_plan_destroy(hb_shape_plan_t * shape_plan)319*2d1272b8SAndroid Build Coastguard Worker hb_shape_plan_destroy (hb_shape_plan_t *shape_plan)
320*2d1272b8SAndroid Build Coastguard Worker {
321*2d1272b8SAndroid Build Coastguard Worker   if (!hb_object_destroy (shape_plan)) return;
322*2d1272b8SAndroid Build Coastguard Worker 
323*2d1272b8SAndroid Build Coastguard Worker   hb_free (shape_plan);
324*2d1272b8SAndroid Build Coastguard Worker }
325*2d1272b8SAndroid Build Coastguard Worker 
326*2d1272b8SAndroid Build Coastguard Worker /**
327*2d1272b8SAndroid Build Coastguard Worker  * hb_shape_plan_set_user_data: (skip)
328*2d1272b8SAndroid Build Coastguard Worker  * @shape_plan: A shaping plan
329*2d1272b8SAndroid Build Coastguard Worker  * @key: The user-data key to set
330*2d1272b8SAndroid Build Coastguard Worker  * @data: A pointer to the user data
331*2d1272b8SAndroid Build Coastguard Worker  * @destroy: (nullable): A callback to call when @data is not needed anymore
332*2d1272b8SAndroid Build Coastguard Worker  * @replace: Whether to replace an existing data with the same key
333*2d1272b8SAndroid Build Coastguard Worker  *
334*2d1272b8SAndroid Build Coastguard Worker  * Attaches a user-data key/data pair to the given shaping plan.
335*2d1272b8SAndroid Build Coastguard Worker  *
336*2d1272b8SAndroid Build Coastguard Worker  * Return value: `true` if success, `false` otherwise.
337*2d1272b8SAndroid Build Coastguard Worker  *
338*2d1272b8SAndroid Build Coastguard Worker  * Since: 0.9.7
339*2d1272b8SAndroid Build Coastguard Worker  **/
340*2d1272b8SAndroid Build Coastguard Worker hb_bool_t
hb_shape_plan_set_user_data(hb_shape_plan_t * shape_plan,hb_user_data_key_t * key,void * data,hb_destroy_func_t destroy,hb_bool_t replace)341*2d1272b8SAndroid Build Coastguard Worker hb_shape_plan_set_user_data (hb_shape_plan_t    *shape_plan,
342*2d1272b8SAndroid Build Coastguard Worker 			     hb_user_data_key_t *key,
343*2d1272b8SAndroid Build Coastguard Worker 			     void *              data,
344*2d1272b8SAndroid Build Coastguard Worker 			     hb_destroy_func_t   destroy,
345*2d1272b8SAndroid Build Coastguard Worker 			     hb_bool_t           replace)
346*2d1272b8SAndroid Build Coastguard Worker {
347*2d1272b8SAndroid Build Coastguard Worker   return hb_object_set_user_data (shape_plan, key, data, destroy, replace);
348*2d1272b8SAndroid Build Coastguard Worker }
349*2d1272b8SAndroid Build Coastguard Worker 
350*2d1272b8SAndroid Build Coastguard Worker /**
351*2d1272b8SAndroid Build Coastguard Worker  * hb_shape_plan_get_user_data: (skip)
352*2d1272b8SAndroid Build Coastguard Worker  * @shape_plan: A shaping plan
353*2d1272b8SAndroid Build Coastguard Worker  * @key: The user-data key to query
354*2d1272b8SAndroid Build Coastguard Worker  *
355*2d1272b8SAndroid Build Coastguard Worker  * Fetches the user data associated with the specified key,
356*2d1272b8SAndroid Build Coastguard Worker  * attached to the specified shaping plan.
357*2d1272b8SAndroid Build Coastguard Worker  *
358*2d1272b8SAndroid Build Coastguard Worker  * Return value: (transfer none): A pointer to the user data
359*2d1272b8SAndroid Build Coastguard Worker  *
360*2d1272b8SAndroid Build Coastguard Worker  * Since: 0.9.7
361*2d1272b8SAndroid Build Coastguard Worker  **/
362*2d1272b8SAndroid Build Coastguard Worker void *
hb_shape_plan_get_user_data(const hb_shape_plan_t * shape_plan,hb_user_data_key_t * key)363*2d1272b8SAndroid Build Coastguard Worker hb_shape_plan_get_user_data (const hb_shape_plan_t *shape_plan,
364*2d1272b8SAndroid Build Coastguard Worker 			     hb_user_data_key_t    *key)
365*2d1272b8SAndroid Build Coastguard Worker {
366*2d1272b8SAndroid Build Coastguard Worker   return hb_object_get_user_data (shape_plan, key);
367*2d1272b8SAndroid Build Coastguard Worker }
368*2d1272b8SAndroid Build Coastguard Worker 
369*2d1272b8SAndroid Build Coastguard Worker /**
370*2d1272b8SAndroid Build Coastguard Worker  * hb_shape_plan_get_shaper:
371*2d1272b8SAndroid Build Coastguard Worker  * @shape_plan: A shaping plan
372*2d1272b8SAndroid Build Coastguard Worker  *
373*2d1272b8SAndroid Build Coastguard Worker  * Fetches the shaper from a given shaping plan.
374*2d1272b8SAndroid Build Coastguard Worker  *
375*2d1272b8SAndroid Build Coastguard Worker  * Return value: (transfer none): The shaper
376*2d1272b8SAndroid Build Coastguard Worker  *
377*2d1272b8SAndroid Build Coastguard Worker  * Since: 0.9.7
378*2d1272b8SAndroid Build Coastguard Worker  **/
379*2d1272b8SAndroid Build Coastguard Worker const char *
hb_shape_plan_get_shaper(hb_shape_plan_t * shape_plan)380*2d1272b8SAndroid Build Coastguard Worker hb_shape_plan_get_shaper (hb_shape_plan_t *shape_plan)
381*2d1272b8SAndroid Build Coastguard Worker {
382*2d1272b8SAndroid Build Coastguard Worker   return shape_plan->key.shaper_name;
383*2d1272b8SAndroid Build Coastguard Worker }
384*2d1272b8SAndroid Build Coastguard Worker 
385*2d1272b8SAndroid Build Coastguard Worker 
386*2d1272b8SAndroid Build Coastguard Worker static bool
_hb_shape_plan_execute_internal(hb_shape_plan_t * shape_plan,hb_font_t * font,hb_buffer_t * buffer,const hb_feature_t * features,unsigned int num_features)387*2d1272b8SAndroid Build Coastguard Worker _hb_shape_plan_execute_internal (hb_shape_plan_t    *shape_plan,
388*2d1272b8SAndroid Build Coastguard Worker 				 hb_font_t          *font,
389*2d1272b8SAndroid Build Coastguard Worker 				 hb_buffer_t        *buffer,
390*2d1272b8SAndroid Build Coastguard Worker 				 const hb_feature_t *features,
391*2d1272b8SAndroid Build Coastguard Worker 				 unsigned int        num_features)
392*2d1272b8SAndroid Build Coastguard Worker {
393*2d1272b8SAndroid Build Coastguard Worker   DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan,
394*2d1272b8SAndroid Build Coastguard Worker 		  "num_features=%u shaper_func=%p, shaper_name=%s",
395*2d1272b8SAndroid Build Coastguard Worker 		  num_features,
396*2d1272b8SAndroid Build Coastguard Worker 		  shape_plan->key.shaper_func,
397*2d1272b8SAndroid Build Coastguard Worker 		  shape_plan->key.shaper_name);
398*2d1272b8SAndroid Build Coastguard Worker 
399*2d1272b8SAndroid Build Coastguard Worker   if (unlikely (!buffer->len))
400*2d1272b8SAndroid Build Coastguard Worker     return true;
401*2d1272b8SAndroid Build Coastguard Worker 
402*2d1272b8SAndroid Build Coastguard Worker   assert (!hb_object_is_immutable (buffer));
403*2d1272b8SAndroid Build Coastguard Worker 
404*2d1272b8SAndroid Build Coastguard Worker   buffer->assert_unicode ();
405*2d1272b8SAndroid Build Coastguard Worker 
406*2d1272b8SAndroid Build Coastguard Worker   if (unlikely (!hb_object_is_valid (shape_plan)))
407*2d1272b8SAndroid Build Coastguard Worker     return false;
408*2d1272b8SAndroid Build Coastguard Worker 
409*2d1272b8SAndroid Build Coastguard Worker   assert (shape_plan->face_unsafe == font->face);
410*2d1272b8SAndroid Build Coastguard Worker   assert (hb_segment_properties_equal (&shape_plan->key.props, &buffer->props));
411*2d1272b8SAndroid Build Coastguard Worker 
412*2d1272b8SAndroid Build Coastguard Worker #define HB_SHAPER_EXECUTE(shaper) \
413*2d1272b8SAndroid Build Coastguard Worker 	HB_STMT_START { \
414*2d1272b8SAndroid Build Coastguard Worker 	  return font->data.shaper && \
415*2d1272b8SAndroid Build Coastguard Worker 		 _hb_##shaper##_shape (shape_plan, font, buffer, features, num_features); \
416*2d1272b8SAndroid Build Coastguard Worker 	} HB_STMT_END
417*2d1272b8SAndroid Build Coastguard Worker 
418*2d1272b8SAndroid Build Coastguard Worker   if (false)
419*2d1272b8SAndroid Build Coastguard Worker     ;
420*2d1272b8SAndroid Build Coastguard Worker #define HB_SHAPER_IMPLEMENT(shaper) \
421*2d1272b8SAndroid Build Coastguard Worker   else if (shape_plan->key.shaper_func == _hb_##shaper##_shape) \
422*2d1272b8SAndroid Build Coastguard Worker     HB_SHAPER_EXECUTE (shaper);
423*2d1272b8SAndroid Build Coastguard Worker #include "hb-shaper-list.hh"
424*2d1272b8SAndroid Build Coastguard Worker #undef HB_SHAPER_IMPLEMENT
425*2d1272b8SAndroid Build Coastguard Worker 
426*2d1272b8SAndroid Build Coastguard Worker #undef HB_SHAPER_EXECUTE
427*2d1272b8SAndroid Build Coastguard Worker 
428*2d1272b8SAndroid Build Coastguard Worker   return false;
429*2d1272b8SAndroid Build Coastguard Worker }
430*2d1272b8SAndroid Build Coastguard Worker /**
431*2d1272b8SAndroid Build Coastguard Worker  * hb_shape_plan_execute:
432*2d1272b8SAndroid Build Coastguard Worker  * @shape_plan: A shaping plan
433*2d1272b8SAndroid Build Coastguard Worker  * @font: The #hb_font_t to use
434*2d1272b8SAndroid Build Coastguard Worker  * @buffer: The #hb_buffer_t to work upon
435*2d1272b8SAndroid Build Coastguard Worker  * @features: (array length=num_features): Features to enable
436*2d1272b8SAndroid Build Coastguard Worker  * @num_features: The number of features to enable
437*2d1272b8SAndroid Build Coastguard Worker  *
438*2d1272b8SAndroid Build Coastguard Worker  * Executes the given shaping plan on the specified buffer, using
439*2d1272b8SAndroid Build Coastguard Worker  * the given @font and @features.
440*2d1272b8SAndroid Build Coastguard Worker  *
441*2d1272b8SAndroid Build Coastguard Worker  * Return value: `true` if success, `false` otherwise.
442*2d1272b8SAndroid Build Coastguard Worker  *
443*2d1272b8SAndroid Build Coastguard Worker  * Since: 0.9.7
444*2d1272b8SAndroid Build Coastguard Worker  **/
445*2d1272b8SAndroid Build Coastguard Worker hb_bool_t
hb_shape_plan_execute(hb_shape_plan_t * shape_plan,hb_font_t * font,hb_buffer_t * buffer,const hb_feature_t * features,unsigned int num_features)446*2d1272b8SAndroid Build Coastguard Worker hb_shape_plan_execute (hb_shape_plan_t    *shape_plan,
447*2d1272b8SAndroid Build Coastguard Worker 		       hb_font_t          *font,
448*2d1272b8SAndroid Build Coastguard Worker 		       hb_buffer_t        *buffer,
449*2d1272b8SAndroid Build Coastguard Worker 		       const hb_feature_t *features,
450*2d1272b8SAndroid Build Coastguard Worker 		       unsigned int        num_features)
451*2d1272b8SAndroid Build Coastguard Worker {
452*2d1272b8SAndroid Build Coastguard Worker   bool ret = _hb_shape_plan_execute_internal (shape_plan, font, buffer,
453*2d1272b8SAndroid Build Coastguard Worker 					      features, num_features);
454*2d1272b8SAndroid Build Coastguard Worker 
455*2d1272b8SAndroid Build Coastguard Worker   if (ret && buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE)
456*2d1272b8SAndroid Build Coastguard Worker     buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS;
457*2d1272b8SAndroid Build Coastguard Worker 
458*2d1272b8SAndroid Build Coastguard Worker   return ret;
459*2d1272b8SAndroid Build Coastguard Worker }
460*2d1272b8SAndroid Build Coastguard Worker 
461*2d1272b8SAndroid Build Coastguard Worker 
462*2d1272b8SAndroid Build Coastguard Worker /*
463*2d1272b8SAndroid Build Coastguard Worker  * Caching
464*2d1272b8SAndroid Build Coastguard Worker  */
465*2d1272b8SAndroid Build Coastguard Worker 
466*2d1272b8SAndroid Build Coastguard Worker /**
467*2d1272b8SAndroid Build Coastguard Worker  * hb_shape_plan_create_cached:
468*2d1272b8SAndroid Build Coastguard Worker  * @face: #hb_face_t to use
469*2d1272b8SAndroid Build Coastguard Worker  * @props: The #hb_segment_properties_t of the segment
470*2d1272b8SAndroid Build Coastguard Worker  * @user_features: (array length=num_user_features): The list of user-selected features
471*2d1272b8SAndroid Build Coastguard Worker  * @num_user_features: The number of user-selected features
472*2d1272b8SAndroid Build Coastguard Worker  * @shaper_list: (array zero-terminated=1): List of shapers to try
473*2d1272b8SAndroid Build Coastguard Worker  *
474*2d1272b8SAndroid Build Coastguard Worker  * Creates a cached shaping plan suitable for reuse, for a combination
475*2d1272b8SAndroid Build Coastguard Worker  * of @face, @user_features, @props, and @shaper_list.
476*2d1272b8SAndroid Build Coastguard Worker  *
477*2d1272b8SAndroid Build Coastguard Worker  * Return value: (transfer full): The shaping plan
478*2d1272b8SAndroid Build Coastguard Worker  *
479*2d1272b8SAndroid Build Coastguard Worker  * Since: 0.9.7
480*2d1272b8SAndroid Build Coastguard Worker  **/
481*2d1272b8SAndroid Build Coastguard Worker hb_shape_plan_t *
hb_shape_plan_create_cached(hb_face_t * face,const hb_segment_properties_t * props,const hb_feature_t * user_features,unsigned int num_user_features,const char * const * shaper_list)482*2d1272b8SAndroid Build Coastguard Worker hb_shape_plan_create_cached (hb_face_t                     *face,
483*2d1272b8SAndroid Build Coastguard Worker 			     const hb_segment_properties_t *props,
484*2d1272b8SAndroid Build Coastguard Worker 			     const hb_feature_t            *user_features,
485*2d1272b8SAndroid Build Coastguard Worker 			     unsigned int                   num_user_features,
486*2d1272b8SAndroid Build Coastguard Worker 			     const char * const            *shaper_list)
487*2d1272b8SAndroid Build Coastguard Worker {
488*2d1272b8SAndroid Build Coastguard Worker   return hb_shape_plan_create_cached2 (face, props,
489*2d1272b8SAndroid Build Coastguard Worker 				       user_features, num_user_features,
490*2d1272b8SAndroid Build Coastguard Worker 				       nullptr, 0,
491*2d1272b8SAndroid Build Coastguard Worker 				       shaper_list);
492*2d1272b8SAndroid Build Coastguard Worker }
493*2d1272b8SAndroid Build Coastguard Worker 
494*2d1272b8SAndroid Build Coastguard Worker /**
495*2d1272b8SAndroid Build Coastguard Worker  * hb_shape_plan_create_cached2:
496*2d1272b8SAndroid Build Coastguard Worker  * @face: #hb_face_t to use
497*2d1272b8SAndroid Build Coastguard Worker  * @props: The #hb_segment_properties_t of the segment
498*2d1272b8SAndroid Build Coastguard Worker  * @user_features: (array length=num_user_features): The list of user-selected features
499*2d1272b8SAndroid Build Coastguard Worker  * @num_user_features: The number of user-selected features
500*2d1272b8SAndroid Build Coastguard Worker  * @coords: (array length=num_coords): The list of variation-space coordinates
501*2d1272b8SAndroid Build Coastguard Worker  * @num_coords: The number of variation-space coordinates
502*2d1272b8SAndroid Build Coastguard Worker  * @shaper_list: (array zero-terminated=1): List of shapers to try
503*2d1272b8SAndroid Build Coastguard Worker  *
504*2d1272b8SAndroid Build Coastguard Worker  * The variable-font version of #hb_shape_plan_create_cached.
505*2d1272b8SAndroid Build Coastguard Worker  * Creates a cached shaping plan suitable for reuse, for a combination
506*2d1272b8SAndroid Build Coastguard Worker  * of @face, @user_features, @props, and @shaper_list, plus the
507*2d1272b8SAndroid Build Coastguard Worker  * variation-space coordinates @coords.
508*2d1272b8SAndroid Build Coastguard Worker  *
509*2d1272b8SAndroid Build Coastguard Worker  * Return value: (transfer full): The shaping plan
510*2d1272b8SAndroid Build Coastguard Worker  *
511*2d1272b8SAndroid Build Coastguard Worker  * Since: 1.4.0
512*2d1272b8SAndroid Build Coastguard Worker  **/
513*2d1272b8SAndroid Build Coastguard Worker hb_shape_plan_t *
hb_shape_plan_create_cached2(hb_face_t * face,const hb_segment_properties_t * props,const hb_feature_t * user_features,unsigned int num_user_features,const int * coords,unsigned int num_coords,const char * const * shaper_list)514*2d1272b8SAndroid Build Coastguard Worker hb_shape_plan_create_cached2 (hb_face_t                     *face,
515*2d1272b8SAndroid Build Coastguard Worker 			      const hb_segment_properties_t *props,
516*2d1272b8SAndroid Build Coastguard Worker 			      const hb_feature_t            *user_features,
517*2d1272b8SAndroid Build Coastguard Worker 			      unsigned int                   num_user_features,
518*2d1272b8SAndroid Build Coastguard Worker 			      const int                     *coords,
519*2d1272b8SAndroid Build Coastguard Worker 			      unsigned int                   num_coords,
520*2d1272b8SAndroid Build Coastguard Worker 			      const char * const            *shaper_list)
521*2d1272b8SAndroid Build Coastguard Worker {
522*2d1272b8SAndroid Build Coastguard Worker   DEBUG_MSG_FUNC (SHAPE_PLAN, nullptr,
523*2d1272b8SAndroid Build Coastguard Worker 		  "face=%p num_features=%u shaper_list=%p",
524*2d1272b8SAndroid Build Coastguard Worker 		  face,
525*2d1272b8SAndroid Build Coastguard Worker 		  num_user_features,
526*2d1272b8SAndroid Build Coastguard Worker 		  shaper_list);
527*2d1272b8SAndroid Build Coastguard Worker 
528*2d1272b8SAndroid Build Coastguard Worker retry:
529*2d1272b8SAndroid Build Coastguard Worker   hb_face_t::plan_node_t *cached_plan_nodes = face->shape_plans;
530*2d1272b8SAndroid Build Coastguard Worker 
531*2d1272b8SAndroid Build Coastguard Worker   bool dont_cache = !hb_object_is_valid (face);
532*2d1272b8SAndroid Build Coastguard Worker 
533*2d1272b8SAndroid Build Coastguard Worker   if (likely (!dont_cache))
534*2d1272b8SAndroid Build Coastguard Worker   {
535*2d1272b8SAndroid Build Coastguard Worker     hb_shape_plan_key_t key;
536*2d1272b8SAndroid Build Coastguard Worker     if (!key.init (false,
537*2d1272b8SAndroid Build Coastguard Worker 		   face,
538*2d1272b8SAndroid Build Coastguard Worker 		   props,
539*2d1272b8SAndroid Build Coastguard Worker 		   user_features,
540*2d1272b8SAndroid Build Coastguard Worker 		   num_user_features,
541*2d1272b8SAndroid Build Coastguard Worker 		   coords,
542*2d1272b8SAndroid Build Coastguard Worker 		   num_coords,
543*2d1272b8SAndroid Build Coastguard Worker 		   shaper_list))
544*2d1272b8SAndroid Build Coastguard Worker       return hb_shape_plan_get_empty ();
545*2d1272b8SAndroid Build Coastguard Worker 
546*2d1272b8SAndroid Build Coastguard Worker     for (hb_face_t::plan_node_t *node = cached_plan_nodes; node; node = node->next)
547*2d1272b8SAndroid Build Coastguard Worker       if (node->shape_plan->key.equal (&key))
548*2d1272b8SAndroid Build Coastguard Worker       {
549*2d1272b8SAndroid Build Coastguard Worker 	DEBUG_MSG_FUNC (SHAPE_PLAN, node->shape_plan, "fulfilled from cache");
550*2d1272b8SAndroid Build Coastguard Worker 	return hb_shape_plan_reference (node->shape_plan);
551*2d1272b8SAndroid Build Coastguard Worker       }
552*2d1272b8SAndroid Build Coastguard Worker   }
553*2d1272b8SAndroid Build Coastguard Worker 
554*2d1272b8SAndroid Build Coastguard Worker   hb_shape_plan_t *shape_plan = hb_shape_plan_create2 (face, props,
555*2d1272b8SAndroid Build Coastguard Worker 						       user_features, num_user_features,
556*2d1272b8SAndroid Build Coastguard Worker 						       coords, num_coords,
557*2d1272b8SAndroid Build Coastguard Worker 						       shaper_list);
558*2d1272b8SAndroid Build Coastguard Worker 
559*2d1272b8SAndroid Build Coastguard Worker   if (unlikely (dont_cache))
560*2d1272b8SAndroid Build Coastguard Worker     return shape_plan;
561*2d1272b8SAndroid Build Coastguard Worker 
562*2d1272b8SAndroid Build Coastguard Worker   hb_face_t::plan_node_t *node = (hb_face_t::plan_node_t *) hb_calloc (1, sizeof (hb_face_t::plan_node_t));
563*2d1272b8SAndroid Build Coastguard Worker   if (unlikely (!node))
564*2d1272b8SAndroid Build Coastguard Worker     return shape_plan;
565*2d1272b8SAndroid Build Coastguard Worker 
566*2d1272b8SAndroid Build Coastguard Worker   node->shape_plan = shape_plan;
567*2d1272b8SAndroid Build Coastguard Worker   node->next = cached_plan_nodes;
568*2d1272b8SAndroid Build Coastguard Worker 
569*2d1272b8SAndroid Build Coastguard Worker   if (unlikely (!face->shape_plans.cmpexch (cached_plan_nodes, node)))
570*2d1272b8SAndroid Build Coastguard Worker   {
571*2d1272b8SAndroid Build Coastguard Worker     hb_shape_plan_destroy (shape_plan);
572*2d1272b8SAndroid Build Coastguard Worker     hb_free (node);
573*2d1272b8SAndroid Build Coastguard Worker     goto retry;
574*2d1272b8SAndroid Build Coastguard Worker   }
575*2d1272b8SAndroid Build Coastguard Worker   DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan, "inserted into cache");
576*2d1272b8SAndroid Build Coastguard Worker 
577*2d1272b8SAndroid Build Coastguard Worker   return hb_shape_plan_reference (shape_plan);
578*2d1272b8SAndroid Build Coastguard Worker }
579*2d1272b8SAndroid Build Coastguard Worker 
580*2d1272b8SAndroid Build Coastguard Worker 
581*2d1272b8SAndroid Build Coastguard Worker #endif
582