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