2 Port from c++ is protected by a GNU Lesser GPLv3
3 Copyright © 2013 Sylvain BERTRAND <sylvain.bertrand@gmail.com>
10 #include FT_FREETYPE_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
= {
24 TRUE
, /*default_shaper_list */
26 HB_SEGMENT_PROPERTIES_DEFAULT
, /*props */
27 NULL
, /*shaper_func */
28 NULL
, /*shaper_name */
31 HB_SHAPER_DATA_INVALID
,
34 HB_SHAPER_DATA_INVALID
,
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
;
53 static INLINE hb_bool_t
hb_graphite2_shaper_face_data_ensure(hb_face_t
* face
)
56 struct hb_graphite2_shaper_face_data_t
*data
;
59 data
= hb_atomic_ptr_get(&face
->shaper_data
.graphite2
);
61 return !HB_SHAPER_DATA_IS_INVALID(data
);
64 data
= hb_graphite2_shaper_face_data_create(face
);
67 data
= HB_SHAPER_DATA_INVALID
;
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
)
83 struct hb_graphite2_shaper_font_data_t
*data
;
86 data
= hb_atomic_ptr_get(&font
->shaper_data
.graphite2
);
88 return !HB_SHAPER_DATA_IS_INVALID(data
);
91 data
= hb_graphite2_shaper_font_data_create(font
);
94 data
= HB_SHAPER_DATA_INVALID
;
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
);
109 static INLINE hb_bool_t
hb_ot_shaper_face_data_ensure(hb_face_t
* face
)
112 struct hb_ot_shaper_face_data_t
*data
;
115 data
= hb_atomic_ptr_get(&face
->shaper_data
.ot
);
117 return !HB_SHAPER_DATA_IS_INVALID(data
);
120 data
= hb_ot_shaper_face_data_create(face
);
123 data
= HB_SHAPER_DATA_INVALID
;
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
)
139 struct hb_ot_shaper_font_data_t
*data
;
142 data
= hb_atomic_ptr_get(&font
->shaper_data
.ot
);
144 return !HB_SHAPER_DATA_IS_INVALID(data
);
147 data
= hb_ot_shaper_font_data_create(font
);
150 data
= HB_SHAPER_DATA_INVALID
;
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
);
164 static INLINE hb_bool_t
hb_fallback_shaper_face_data_ensure(hb_face_t
* face
)
167 struct hb_fallback_shaper_face_data_t
*data
;
170 data
= hb_atomic_ptr_get(&face
->shaper_data
.fallback
);
172 return !HB_SHAPER_DATA_IS_INVALID(data
);
175 data
= hb_fallback_shaper_face_data_create(face
);
178 data
= HB_SHAPER_DATA_INVALID
;
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
)
194 struct hb_fallback_shaper_font_data_t
*data
;
197 data
= hb_atomic_ptr_get(&font
->shaper_data
.fallback
);
199 return !HB_SHAPER_DATA_IS_INVALID(data
);
202 data
= hb_fallback_shaper_font_data_create(font
);
205 data
= HB_SHAPER_DATA_INVALID
;
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
;
226 shapers
= hb_shapers_get();
228 for (i
= 0; i
< HB_SHAPERS_COUNT
; ++i
)
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
,
238 shape_plan
->shaper_func
=
240 shape_plan
->shaper_name
= "graphite2";
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
,
253 shape_plan
->shaper_func
= hb_ot_shape
;
254 shape_plan
->shaper_name
= "ot";
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
,
266 shape_plan
->shaper_func
=
268 shape_plan
->shaper_name
= "fallback";
273 for (; *shaper_list
; ++shaper_list
)
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
,
283 shape_plan
->shaper_func
=
285 shape_plan
->shaper_name
= "graphite2";
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
,
298 shape_plan
->shaper_func
= hb_ot_shape
;
299 shape_plan
->shaper_name
= "ot";
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
,
311 shape_plan
->shaper_func
=
313 shape_plan
->shaper_name
= "fallback";
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
);
331 face
= hb_face_get_empty();
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
));
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
,
352 static hb_bool_t
hb_shape_plan_matches(hb_shape_plan_t
* shape_plan
,
353 struct hb_shape_plan_proposal_t
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);
369 void hb_shape_plan_destroy(hb_shape_plan_t
* shape_plan
)
373 if (hb_atomic_int32_get(&shape_plan
->ref_cnt
) == REF_CNT_INVALID_VAL
)
375 hb_atomic_int32_add(&shape_plan
->ref_cnt
, -1);
376 if (hb_atomic_int32_get(&shape_plan
->ref_cnt
) > 0)
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
);
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
.
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
);
404 hb_shape_plan_t
*hb_shape_plan_create_cached(hb_face_t
* face
,
405 const hb_segment_properties_t
*
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
;
426 /*Choose shaper. Adapted from hb_shape_plan_plan(). */
427 for (shaper_item
= shaper_list
; *shaper_item
; shaper_item
++)
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
=
437 else if (0 == strcmp(*shaper_item
, "ot")) {
438 if (hb_ot_shaper_face_data_ensure(face
))
439 proposal
.shaper_func
= hb_ot_shape
;
442 else if (0 == strcmp(*shaper_item
, "fallback")) {
443 if (hb_fallback_shaper_face_data_ensure(face
))
444 proposal
.shaper_func
=
448 if (!proposal
.shaper_list
)
449 return hb_shape_plan_get_empty();
452 cached_plan_nodes
= hb_atomic_ptr_get(&face
->shape_plans
);
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
))
459 hb_shape_plan_reference(node
->shape_plan
);
464 hb_shape_plan_create(face
, props
, user_features
,
465 num_user_features
, shaper_list
);
466 node
= calloc(1, sizeof(*node
));
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
))
477 hb_shape_plan_destroy(shape_plan
);
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
)
496 assert(shape_plan
->face
== font
->face
);
497 assert(hb_segment_properties_equal(&shape_plan
->props
, &buffer
->props
));
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
,
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
,
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
,