add explicit freetype2 linking
[charfbuzz.git] / hb-shape-plan.c
blob11f405cdb548fd9ac6aaebda60059202512d5831
1 /*
2 Port from c++ is protected by a GNU Lesser GPLv3
3 Copyright © 2013 Sylvain BERTRAND <sylvain.bertrand@gmail.com>
4 <sylware@legeek.net>
5 */
6 #include <stddef.h>
7 #include <assert.h>
9 #include <ft2build.h>
10 #include FT_FREETYPE_H
12 #include "hb.h"
13 #include "hb-private.h"
14 #include "hb-atomic-private.h"
15 #include "hb-buffer-private.h"
16 #include "hb-shaper-private.h"
17 #include "hb-face-private.h"
18 #include "hb-font-private.h"
19 #include "hb-shape-plan-private.h"
21 /*XXX:should go in lib "global init"*/
22 static hb_shape_plan_t hb_shape_plan_nil = {
23 REF_CNT_INVALID_VAL,
24 TRUE, /*default_shaper_list */
25 NULL, /*face */
26 HB_SEGMENT_PROPERTIES_DEFAULT, /*props */
27 NULL, /*shaper_func */
28 NULL, /*shaper_name */
30 #ifdef HAVE_GRAPHITE2
31 HB_SHAPER_DATA_INVALID,
32 #endif
33 #ifdef HAVE_OT
34 HB_SHAPER_DATA_INVALID,
35 #endif
36 HB_SHAPER_DATA_INVALID /*fallback */
40 /*TODO no user-feature caching for now.*/
41 struct hb_shape_plan_proposal_t {
42 const hb_segment_properties_t props;
43 const char *const *shaper_list;
44 hb_shape_func_t *shaper_func;
47 hb_shape_plan_t *hb_shape_plan_get_empty(void)
49 return &hb_shape_plan_nil;
52 #ifdef HAVE_GRAPHITE2
53 static INLINE hb_bool_t hb_graphite2_shaper_face_data_ensure(hb_face_t * face)
55 while (1) {
56 struct hb_graphite2_shaper_face_data_t *data;
57 void *expected;
59 data = hb_atomic_ptr_get(&face->shaper_data.graphite2);
60 if (data)
61 return !HB_SHAPER_DATA_IS_INVALID(data);
63 if (!data)
64 data = hb_graphite2_shaper_face_data_create(face);
66 if (!data)
67 data = HB_SHAPER_DATA_INVALID;
69 expected = NULL;
70 if (hb_atomic_ptr_cmpexch
71 (&face->shaper_data.graphite2, &expected, &data))
72 return !HB_SHAPER_DATA_IS_INVALID(data);
74 if (data != HB_SHAPER_DATA_INVALID
75 && data != HB_SHAPER_DATA_SUCCEEDED)
76 hb_graphite2_shaper_face_data_destroy(data);
80 static INLINE hb_bool_t hb_graphite2_shaper_font_data_ensure(hb_font_t * font)
82 while (1) {
83 struct hb_graphite2_shaper_font_data_t *data;
84 void *expected;
86 data = hb_atomic_ptr_get(&font->shaper_data.graphite2);
87 if (data)
88 return !HB_SHAPER_DATA_IS_INVALID(data);
90 if (!data)
91 data = hb_graphite2_shaper_font_data_create(font);
93 if (!data)
94 data = HB_SHAPER_DATA_INVALID;
96 expected = NULL;
97 if (hb_atomic_ptr_cmpexch
98 (&font->shaper_data.graphite2, &expected, &data))
99 return !HB_SHAPER_DATA_IS_INVALID(data);
101 if (data != HB_SHAPER_DATA_INVALID
102 && data != HB_SHAPER_DATA_SUCCEEDED)
103 hb_graphite2_shaper_font_data_destroy(data);
106 #endif
108 #ifdef HAVE_OT
109 static INLINE hb_bool_t hb_ot_shaper_face_data_ensure(hb_face_t * face)
111 while (1) {
112 struct hb_ot_shaper_face_data_t *data;
113 void *expected;
115 data = hb_atomic_ptr_get(&face->shaper_data.ot);
116 if (data)
117 return !HB_SHAPER_DATA_IS_INVALID(data);
119 if (!data)
120 data = hb_ot_shaper_face_data_create(face);
122 if (!data)
123 data = HB_SHAPER_DATA_INVALID;
125 expected = NULL;
126 if (hb_atomic_ptr_cmpexch
127 (&face->shaper_data.ot, &expected, &data))
128 return !HB_SHAPER_DATA_IS_INVALID(data);
130 if (data != HB_SHAPER_DATA_INVALID
131 && data != HB_SHAPER_DATA_SUCCEEDED)
132 hb_ot_shaper_face_data_destroy(data);
136 static INLINE hb_bool_t hb_ot_shaper_font_data_ensure(hb_font_t * font)
138 while (1) {
139 struct hb_ot_shaper_font_data_t *data;
140 void *expected;
142 data = hb_atomic_ptr_get(&font->shaper_data.ot);
143 if (data)
144 return !HB_SHAPER_DATA_IS_INVALID(data);
146 if (!data)
147 data = hb_ot_shaper_font_data_create(font);
149 if (!data)
150 data = HB_SHAPER_DATA_INVALID;
152 expected = NULL;
153 if (hb_atomic_ptr_cmpexch
154 (&font->shaper_data.ot, &expected, &data))
155 return !HB_SHAPER_DATA_IS_INVALID(data);
157 if (data != HB_SHAPER_DATA_INVALID
158 && data != HB_SHAPER_DATA_SUCCEEDED)
159 hb_ot_shaper_font_data_destroy(data);
162 #endif
164 static INLINE hb_bool_t hb_fallback_shaper_face_data_ensure(hb_face_t * face)
166 while (1) {
167 struct hb_fallback_shaper_face_data_t *data;
168 void *expected;
170 data = hb_atomic_ptr_get(&face->shaper_data.fallback);
171 if (data)
172 return !HB_SHAPER_DATA_IS_INVALID(data);
174 if (!data)
175 data = hb_fallback_shaper_face_data_create(face);
177 if (!data)
178 data = HB_SHAPER_DATA_INVALID;
180 expected = NULL;
181 if (hb_atomic_ptr_cmpexch
182 (&face->shaper_data.fallback, &expected, &data))
183 return !HB_SHAPER_DATA_IS_INVALID(data);
185 if (data != HB_SHAPER_DATA_INVALID
186 && data != HB_SHAPER_DATA_SUCCEEDED)
187 hb_fallback_shaper_face_data_destroy(data);
191 static INLINE hb_bool_t hb_fallback_shaper_font_data_ensure(hb_font_t * font)
193 while (1) {
194 struct hb_fallback_shaper_font_data_t *data;
195 void *expected;
197 data = hb_atomic_ptr_get(&font->shaper_data.fallback);
198 if (data)
199 return !HB_SHAPER_DATA_IS_INVALID(data);
201 if (!data)
202 data = hb_fallback_shaper_font_data_create(font);
204 if (!data)
205 data = HB_SHAPER_DATA_INVALID;
207 expected = NULL;
208 if (hb_atomic_ptr_cmpexch
209 (&font->shaper_data.fallback, &expected, &data))
210 return !HB_SHAPER_DATA_IS_INVALID(data);
212 if (data != HB_SHAPER_DATA_INVALID
213 && data != HB_SHAPER_DATA_SUCCEEDED)
214 hb_fallback_shaper_font_data_destroy(data);
218 static void hb_shape_plan_plan(hb_shape_plan_t * shape_plan,
219 const hb_feature_t * user_features,
220 unsigned num_user_features,
221 const char *const *shaper_list)
223 struct hb_shaper_pair_t *shapers;
224 unsigned i;
226 shapers = hb_shapers_get();
227 if (!shaper_list) {
228 for (i = 0; i < HB_SHAPERS_COUNT; ++i)
229 if (0) ;
230 #ifdef HAVE_GRAPHITE2
231 else if (shapers[i].func == hb_graphite2_shape) {
232 if (hb_graphite2_shaper_face_data_ensure
233 (shape_plan->face)) {
234 shape_plan->shaper_data.graphite2 =
235 hb_graphite2_shaper_shape_plan_data_create
236 (shape_plan, user_features,
237 num_user_features);
238 shape_plan->shaper_func =
239 hb_graphite2_shape;
240 shape_plan->shaper_name = "graphite2";
241 return;
244 #endif
245 #ifdef HAVE_OT
246 else if (shapers[i].func == hb_ot_shape) {
247 if (hb_ot_shaper_face_data_ensure
248 (shape_plan->face)) {
249 shape_plan->shaper_data.ot =
250 hb_ot_shaper_shape_plan_data_create
251 (shape_plan, user_features,
252 num_user_features);
253 shape_plan->shaper_func = hb_ot_shape;
254 shape_plan->shaper_name = "ot";
255 return;
258 #endif
259 else if (shapers[i].func == hb_fallback_shape) {
260 if (hb_fallback_shaper_face_data_ensure
261 (shape_plan->face)) {
262 shape_plan->shaper_data.fallback =
263 hb_fallback_shaper_shape_plan_data_create
264 (shape_plan, user_features,
265 num_user_features);
266 shape_plan->shaper_func =
267 hb_fallback_shape;
268 shape_plan->shaper_name = "fallback";
269 return;
272 } else {
273 for (; *shaper_list; ++shaper_list)
274 if (0) ;
275 #ifdef HAVE_GRAPHITE2
276 else if (0 == strcmp(*shaper_list, "graphite2")) {
277 if (hb_graphite2_shaper_face_data_ensure
278 (shape_plan->face)) {
279 shape_plan->shaper_data.graphite2 =
280 hb_graphite2_shaper_shape_plan_data_create
281 (shape_plan, user_features,
282 num_user_features);
283 shape_plan->shaper_func =
284 hb_graphite2_shape;
285 shape_plan->shaper_name = "graphite2";
286 return;
289 #endif
290 #ifdef HAVE_OT
291 else if (0 == strcmp(*shaper_list, "ot")) {
292 if (hb_ot_shaper_face_data_ensure
293 (shape_plan->face)) {
294 shape_plan->shaper_data.ot =
295 hb_ot_shaper_shape_plan_data_create
296 (shape_plan, user_features,
297 num_user_features);
298 shape_plan->shaper_func = hb_ot_shape;
299 shape_plan->shaper_name = "ot";
300 return;
303 #endif
304 else if (0 == strcmp(*shaper_list, "fallback")) {
305 if (hb_fallback_shaper_face_data_ensure
306 (shape_plan->face)) {
307 shape_plan->shaper_data.fallback =
308 hb_fallback_shaper_shape_plan_data_create
309 (shape_plan, user_features,
310 num_user_features);
311 shape_plan->shaper_func =
312 hb_fallback_shape;
313 shape_plan->shaper_name = "fallback";
314 return;
320 hb_shape_plan_t *hb_shape_plan_create(hb_face_t * face,
321 const hb_segment_properties_t * props,
322 const hb_feature_t * user_features,
323 unsigned int num_user_features,
324 const char *const *shaper_list)
326 hb_shape_plan_t *shape_plan;
328 assert(props->direction != HB_DIRECTION_INVALID);
330 if (!face)
331 face = hb_face_get_empty();
333 if (!props
334 || hb_atomic_int32_get(&face->ref_cnt) == REF_CNT_INVALID_VAL)
335 return hb_shape_plan_get_empty();
337 shape_plan = calloc(1, sizeof(*shape_plan));
338 if (!shape_plan)
339 return hb_shape_plan_get_empty();
340 hb_atomic_int32_set(&shape_plan->ref_cnt, 1);
342 shape_plan->default_shaper_list = shaper_list == NULL;
343 hb_face_make_immutable(face);
344 shape_plan->face = hb_face_reference(face);
345 shape_plan->props = *props;
347 hb_shape_plan_plan(shape_plan, user_features, num_user_features,
348 shaper_list);
349 return shape_plan;
352 static hb_bool_t hb_shape_plan_matches(hb_shape_plan_t * shape_plan,
353 struct hb_shape_plan_proposal_t
354 *proposal)
356 return hb_segment_properties_equal(&shape_plan->props, &proposal->props)
358 ((shape_plan->default_shaper_list && proposal->shaper_list == NULL)
359 || (shape_plan->shaper_func == proposal->shaper_func));
362 hb_shape_plan_t *hb_shape_plan_reference(hb_shape_plan_t * shape_plan)
364 if (hb_atomic_int32_get(&shape_plan->ref_cnt) != REF_CNT_INVALID_VAL)
365 hb_atomic_int32_add(&shape_plan->ref_cnt, 1);
366 return shape_plan;
369 void hb_shape_plan_destroy(hb_shape_plan_t * shape_plan)
371 if (!shape_plan)
372 return;
373 if (hb_atomic_int32_get(&shape_plan->ref_cnt) == REF_CNT_INVALID_VAL)
374 return;
375 hb_atomic_int32_add(&shape_plan->ref_cnt, -1);
376 if (hb_atomic_int32_get(&shape_plan->ref_cnt) > 0)
377 return;
378 hb_atomic_int32_set(&shape_plan->ref_cnt, REF_CNT_INVALID_VAL);
380 #ifdef HAVE_GRAPHITE2
381 if (shape_plan->shaper_data.graphite2
382 && shape_plan->shaper_data.graphite2 != HB_SHAPER_DATA_INVALID
383 && shape_plan->shaper_data.graphite2 != HB_SHAPER_DATA_SUCCEEDED)
384 hb_graphite2_shaper_shape_plan_data_destroy
385 (shape_plan->shaper_data.graphite2);
386 #endif
387 #ifdef HAVE_OT
388 if (shape_plan->shaper_data.ot
389 && shape_plan->shaper_data.ot != HB_SHAPER_DATA_INVALID
390 && shape_plan->shaper_data.ot != HB_SHAPER_DATA_SUCCEEDED)
391 hb_ot_shaper_shape_plan_data_destroy(shape_plan->shaper_data.
392 ot);
393 #endif
394 if (shape_plan->shaper_data.fallback
395 && shape_plan->shaper_data.fallback != HB_SHAPER_DATA_INVALID
396 && shape_plan->shaper_data.fallback != HB_SHAPER_DATA_SUCCEEDED)
397 hb_fallback_shaper_shape_plan_data_destroy
398 (shape_plan->shaper_data.fallback);
400 hb_face_destroy(shape_plan->face);
401 free(shape_plan);
404 hb_shape_plan_t *hb_shape_plan_create_cached(hb_face_t * face,
405 const hb_segment_properties_t *
406 props,
407 const hb_feature_t * user_features,
408 unsigned int num_user_features,
409 const char *const *shaper_list)
411 struct hb_shape_plan_proposal_t proposal;
412 const char *const *shaper_item;
413 struct plan_node_t *cached_plan_nodes;
414 hb_shape_plan_t *shape_plan;
416 if (num_user_features)
417 return hb_shape_plan_create(face, props, user_features,
418 num_user_features, shaper_list);
420 /*XXX:proposal.props = *props;*/
421 memcpy((void*)&proposal.props,(void*)props,sizeof(proposal.props));
422 proposal.shaper_list = shaper_list;
423 proposal.shaper_func = NULL;
425 if (shaper_list) {
426 /*Choose shaper. Adapted from hb_shape_plan_plan(). */
427 for (shaper_item = shaper_list; *shaper_item; shaper_item++)
428 if (0) ;
429 #ifdef HAVE_GRAPHITE2
430 else if (0 == strcmp(*shaper_item, "graphite2")) {
431 if (hb_graphite2_shaper_face_data_ensure(face))
432 proposal.shaper_func =
433 hb_graphite2_shape;
435 #endif
436 #ifdef HAVE_OT
437 else if (0 == strcmp(*shaper_item, "ot")) {
438 if (hb_ot_shaper_face_data_ensure(face))
439 proposal.shaper_func = hb_ot_shape;
441 #endif
442 else if (0 == strcmp(*shaper_item, "fallback")) {
443 if (hb_fallback_shaper_face_data_ensure(face))
444 proposal.shaper_func =
445 hb_fallback_shape;
448 if (!proposal.shaper_list)
449 return hb_shape_plan_get_empty();
452 cached_plan_nodes = hb_atomic_ptr_get(&face->shape_plans);
453 while (1) {
454 struct plan_node_t *node;
456 for (node = cached_plan_nodes; node; node = node->next)
457 if (hb_shape_plan_matches(node->shape_plan, &proposal))
458 return
459 hb_shape_plan_reference(node->shape_plan);
461 /*Not found. */
463 shape_plan =
464 hb_shape_plan_create(face, props, user_features,
465 num_user_features, shaper_list);
466 node = calloc(1, sizeof(*node));
467 if (!node)
468 return shape_plan;
470 node->shape_plan = shape_plan;
471 node->next = cached_plan_nodes;
473 if (hb_atomic_ptr_cmpexch
474 (&face->shape_plans, &cached_plan_nodes, &node))
475 break;
477 hb_shape_plan_destroy(shape_plan);
478 free(node);
481 /*Release our reference on face. */
482 hb_face_destroy(face);
483 return hb_shape_plan_reference(shape_plan);
486 hb_bool_t hb_shape_plan_execute(hb_shape_plan_t * shape_plan, hb_font_t * font,
487 hb_buffer_t * buffer,
488 const hb_feature_t * features,
489 unsigned num_features)
491 if (hb_atomic_int32_get(&shape_plan->ref_cnt) == REF_CNT_INVALID_VAL
492 || hb_atomic_int32_get(&font->ref_cnt) == REF_CNT_INVALID_VAL
493 || hb_atomic_int32_get(&buffer->ref_cnt) == REF_CNT_INVALID_VAL)
494 return FALSE;
496 assert(shape_plan->face == font->face);
497 assert(hb_segment_properties_equal(&shape_plan->props, &buffer->props));
499 if (0) ;
500 #ifdef HAVE_GRAPHITE2
501 else if (shape_plan->shaper_func == hb_graphite2_shape)
502 return shape_plan->shaper_data.graphite2
503 && hb_graphite2_shaper_font_data_ensure(font)
504 && hb_graphite2_shape(shape_plan, font, buffer, features,
505 num_features);
506 #endif
507 #ifdef HAVE_OT
508 else if (shape_plan->shaper_func == hb_ot_shape)
509 return shape_plan->shaper_data.ot
510 && hb_ot_shaper_font_data_ensure(font)
511 && hb_ot_shape(shape_plan, font, buffer, features,
512 num_features);
513 #endif
514 else if (shape_plan->shaper_func == hb_fallback_shape)
515 return shape_plan->shaper_data.fallback
516 && hb_fallback_shaper_font_data_ensure(font)
517 && hb_fallback_shape(shape_plan, font, buffer, features,
518 num_features);
519 return FALSE;