OLD | NEW |
1 /* | 1 /* |
2 * Copyright © 2012 Google, Inc. | 2 * Copyright © 2012 Google, Inc. |
3 * | 3 * |
4 * This is part of HarfBuzz, a text shaping library. | 4 * This is part of HarfBuzz, a text shaping library. |
5 * | 5 * |
6 * Permission is hereby granted, without written agreement and without | 6 * Permission is hereby granted, without written agreement and without |
7 * license or royalty fees, to use, copy, modify, and distribute this | 7 * license or royalty fees, to use, copy, modify, and distribute this |
8 * software and its documentation for any purpose, provided that the | 8 * software and its documentation for any purpose, provided that the |
9 * above copyright notice and the following two paragraphs appear in | 9 * above copyright notice and the following two paragraphs appear in |
10 * all copies of this software. | 10 * all copies of this software. |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
100 hb_shape_plan_t * | 100 hb_shape_plan_t * |
101 hb_shape_plan_create (hb_face_t *face, | 101 hb_shape_plan_create (hb_face_t *face, |
102 const hb_segment_properties_t *props, | 102 const hb_segment_properties_t *props, |
103 const hb_feature_t *user_features, | 103 const hb_feature_t *user_features, |
104 unsigned int num_user_features, | 104 unsigned int num_user_features, |
105 const char * const *shaper_list) | 105 const char * const *shaper_list) |
106 { | 106 { |
107 assert (props->direction != HB_DIRECTION_INVALID); | 107 assert (props->direction != HB_DIRECTION_INVALID); |
108 | 108 |
109 hb_shape_plan_t *shape_plan; | 109 hb_shape_plan_t *shape_plan; |
| 110 hb_feature_t *features = NULL; |
110 | 111 |
111 if (unlikely (!face)) | 112 if (unlikely (!face)) |
112 face = hb_face_get_empty (); | 113 face = hb_face_get_empty (); |
113 if (unlikely (!props || hb_object_is_inert (face))) | 114 if (unlikely (!props || hb_object_is_inert (face))) |
114 return hb_shape_plan_get_empty (); | 115 return hb_shape_plan_get_empty (); |
115 if (!(shape_plan = hb_object_create<hb_shape_plan_t> ())) | 116 if (num_user_features && !(features = (hb_feature_t *) malloc (num_user_featur
es * sizeof (hb_feature_t)))) |
116 return hb_shape_plan_get_empty (); | 117 return hb_shape_plan_get_empty (); |
| 118 if (!(shape_plan = hb_object_create<hb_shape_plan_t> ())) { |
| 119 free (features); |
| 120 return hb_shape_plan_get_empty (); |
| 121 } |
117 | 122 |
118 hb_face_make_immutable (face); | 123 hb_face_make_immutable (face); |
119 shape_plan->default_shaper_list = shaper_list == NULL; | 124 shape_plan->default_shaper_list = shaper_list == NULL; |
120 shape_plan->face_unsafe = face; | 125 shape_plan->face_unsafe = face; |
121 shape_plan->props = *props; | 126 shape_plan->props = *props; |
| 127 shape_plan->num_user_features = num_user_features; |
| 128 shape_plan->user_features = features; |
| 129 if (num_user_features) |
| 130 memcpy (features, user_features, num_user_features * sizeof (hb_feature_t)); |
122 | 131 |
123 hb_shape_plan_plan (shape_plan, user_features, num_user_features, shaper_list)
; | 132 hb_shape_plan_plan (shape_plan, user_features, num_user_features, shaper_list)
; |
124 | 133 |
125 return shape_plan; | 134 return shape_plan; |
126 } | 135 } |
127 | 136 |
128 /** | 137 /** |
129 * hb_shape_plan_get_empty: | 138 * hb_shape_plan_get_empty: |
130 * | 139 * |
131 * | 140 * |
132 * | 141 * |
133 * Return value: (transfer full): | 142 * Return value: (transfer full): |
134 * | 143 * |
135 * Since: 1.0 | 144 * Since: 1.0 |
136 **/ | 145 **/ |
137 hb_shape_plan_t * | 146 hb_shape_plan_t * |
138 hb_shape_plan_get_empty (void) | 147 hb_shape_plan_get_empty (void) |
139 { | 148 { |
140 static const hb_shape_plan_t _hb_shape_plan_nil = { | 149 static const hb_shape_plan_t _hb_shape_plan_nil = { |
141 HB_OBJECT_HEADER_STATIC, | 150 HB_OBJECT_HEADER_STATIC, |
142 | 151 |
143 true, /* default_shaper_list */ | 152 true, /* default_shaper_list */ |
144 NULL, /* face */ | 153 NULL, /* face */ |
145 HB_SEGMENT_PROPERTIES_DEFAULT, /* props */ | 154 HB_SEGMENT_PROPERTIES_DEFAULT, /* props */ |
146 | 155 |
147 NULL, /* shaper_func */ | 156 NULL, /* shaper_func */ |
148 NULL, /* shaper_name */ | 157 NULL, /* shaper_name */ |
149 | 158 |
| 159 NULL, /* user_features */ |
| 160 0, /* num_user_featurs */ |
| 161 |
150 { | 162 { |
151 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID, | 163 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID, |
152 #include "hb-shaper-list.hh" | 164 #include "hb-shaper-list.hh" |
153 #undef HB_SHAPER_IMPLEMENT | 165 #undef HB_SHAPER_IMPLEMENT |
154 } | 166 } |
155 }; | 167 }; |
156 | 168 |
157 return const_cast<hb_shape_plan_t *> (&_hb_shape_plan_nil); | 169 return const_cast<hb_shape_plan_t *> (&_hb_shape_plan_nil); |
158 } | 170 } |
159 | 171 |
(...skipping 23 matching lines...) Expand all Loading... |
183 **/ | 195 **/ |
184 void | 196 void |
185 hb_shape_plan_destroy (hb_shape_plan_t *shape_plan) | 197 hb_shape_plan_destroy (hb_shape_plan_t *shape_plan) |
186 { | 198 { |
187 if (!hb_object_destroy (shape_plan)) return; | 199 if (!hb_object_destroy (shape_plan)) return; |
188 | 200 |
189 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, shape_plan); | 201 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, shape_plan); |
190 #include "hb-shaper-list.hh" | 202 #include "hb-shaper-list.hh" |
191 #undef HB_SHAPER_IMPLEMENT | 203 #undef HB_SHAPER_IMPLEMENT |
192 | 204 |
| 205 free (shape_plan->user_features); |
| 206 |
193 free (shape_plan); | 207 free (shape_plan); |
194 } | 208 } |
195 | 209 |
196 /** | 210 /** |
197 * hb_shape_plan_set_user_data: (skip) | 211 * hb_shape_plan_set_user_data: (skip) |
198 * @shape_plan: a shape plan. | 212 * @shape_plan: a shape plan. |
199 * @key: | 213 * @key: |
200 * @data: | 214 * @data: |
201 * @destroy: | 215 * @destroy: |
202 * @replace: | 216 * @replace: |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
292 | 306 |
293 #if 0 | 307 #if 0 |
294 static unsigned int | 308 static unsigned int |
295 hb_shape_plan_hash (const hb_shape_plan_t *shape_plan) | 309 hb_shape_plan_hash (const hb_shape_plan_t *shape_plan) |
296 { | 310 { |
297 return hb_segment_properties_hash (&shape_plan->props) + | 311 return hb_segment_properties_hash (&shape_plan->props) + |
298 shape_plan->default_shaper_list ? 0 : (intptr_t) shape_plan->shaper_fun
c; | 312 shape_plan->default_shaper_list ? 0 : (intptr_t) shape_plan->shaper_fun
c; |
299 } | 313 } |
300 #endif | 314 #endif |
301 | 315 |
302 /* TODO no user-feature caching for now. */ | 316 /* User-feature caching is currently somewhat dumb: |
| 317 * it only finds matches where the feature array is identical, |
| 318 * not cases where the feature lists would be compatible for plan purposes |
| 319 * but have different ranges, for example. |
| 320 */ |
303 struct hb_shape_plan_proposal_t | 321 struct hb_shape_plan_proposal_t |
304 { | 322 { |
305 const hb_segment_properties_t props; | 323 const hb_segment_properties_t props; |
306 const char * const *shaper_list; | 324 const char * const *shaper_list; |
| 325 const hb_feature_t *user_features; |
| 326 unsigned int num_user_features; |
307 hb_shape_func_t *shaper_func; | 327 hb_shape_func_t *shaper_func; |
308 }; | 328 }; |
309 | 329 |
| 330 static inline hb_bool_t |
| 331 hb_shape_plan_user_features_match (const hb_shape_plan_t *shape_plan, |
| 332 const hb_shape_plan_proposal_t *proposal) |
| 333 { |
| 334 if (proposal->num_user_features != shape_plan->num_user_features) return false
; |
| 335 for (unsigned int i = 0, n = proposal->num_user_features; i < n; i++) |
| 336 if (proposal->user_features[i].tag != shape_plan->user_features[i].tag |
| |
| 337 proposal->user_features[i].value != shape_plan->user_features[i].value |
| |
| 338 proposal->user_features[i].start != shape_plan->user_features[i].start |
| |
| 339 proposal->user_features[i].end != shape_plan->user_features[i].end) re
turn false; |
| 340 return true; |
| 341 } |
| 342 |
310 static hb_bool_t | 343 static hb_bool_t |
311 hb_shape_plan_matches (const hb_shape_plan_t *shape_plan, | 344 hb_shape_plan_matches (const hb_shape_plan_t *shape_plan, |
312 const hb_shape_plan_proposal_t *proposal) | 345 const hb_shape_plan_proposal_t *proposal) |
313 { | 346 { |
314 return hb_segment_properties_equal (&shape_plan->props, &proposal->props) && | 347 return hb_segment_properties_equal (&shape_plan->props, &proposal->props) && |
| 348 hb_shape_plan_user_features_match (shape_plan, proposal) && |
315 ((shape_plan->default_shaper_list && proposal->shaper_list == NULL) || | 349 ((shape_plan->default_shaper_list && proposal->shaper_list == NULL) || |
316 (shape_plan->shaper_func == proposal->shaper_func)); | 350 (shape_plan->shaper_func == proposal->shaper_func)); |
317 } | 351 } |
318 | 352 |
| 353 static inline hb_bool_t |
| 354 hb_non_global_user_features_present (const hb_feature_t *user_features, |
| 355 unsigned int num_user_features) |
| 356 { |
| 357 while (num_user_features) |
| 358 if (user_features->start != 0 || user_features->end != (unsigned int) -1) |
| 359 return true; |
| 360 else |
| 361 num_user_features--, user_features++; |
| 362 return false; |
| 363 } |
| 364 |
319 /** | 365 /** |
320 * hb_shape_plan_create_cached: | 366 * hb_shape_plan_create_cached: |
321 * @face: | 367 * @face: |
322 * @props: | 368 * @props: |
323 * @user_features: (array length=num_user_features): | 369 * @user_features: (array length=num_user_features): |
324 * @num_user_features: | 370 * @num_user_features: |
325 * @shaper_list: (array zero-terminated=1): | 371 * @shaper_list: (array zero-terminated=1): |
326 * | 372 * |
327 * | 373 * |
328 * | 374 * |
329 * Return value: (transfer full): | 375 * Return value: (transfer full): |
330 * | 376 * |
331 * Since: 1.0 | 377 * Since: 1.0 |
332 **/ | 378 **/ |
333 hb_shape_plan_t * | 379 hb_shape_plan_t * |
334 hb_shape_plan_create_cached (hb_face_t *face, | 380 hb_shape_plan_create_cached (hb_face_t *face, |
335 const hb_segment_properties_t *props, | 381 const hb_segment_properties_t *props, |
336 const hb_feature_t *user_features, | 382 const hb_feature_t *user_features, |
337 unsigned int num_user_features, | 383 unsigned int num_user_features, |
338 const char * const *shaper_list) | 384 const char * const *shaper_list) |
339 { | 385 { |
340 if (num_user_features) | |
341 return hb_shape_plan_create (face, props, user_features, num_user_features,
shaper_list); | |
342 | |
343 hb_shape_plan_proposal_t proposal = { | 386 hb_shape_plan_proposal_t proposal = { |
344 *props, | 387 *props, |
345 shaper_list, | 388 shaper_list, |
| 389 user_features, |
| 390 num_user_features, |
346 NULL | 391 NULL |
347 }; | 392 }; |
348 | 393 |
349 if (shaper_list) { | 394 if (shaper_list) { |
350 /* Choose shaper. Adapted from hb_shape_plan_plan(). */ | 395 /* Choose shaper. Adapted from hb_shape_plan_plan(). */ |
351 #define HB_SHAPER_PLAN(shaper) \ | 396 #define HB_SHAPER_PLAN(shaper) \ |
352 HB_STMT_START { \ | 397 HB_STMT_START { \ |
353 if (hb_##shaper##_shaper_face_data_ensure (face)) \ | 398 if (hb_##shaper##_shaper_face_data_ensure (face)) \ |
354 proposal.shaper_func = _hb_##shaper##_shape; \ | 399 proposal.shaper_func = _hb_##shaper##_shape; \ |
355 } HB_STMT_END | 400 } HB_STMT_END |
(...skipping 17 matching lines...) Expand all Loading... |
373 retry: | 418 retry: |
374 hb_face_t::plan_node_t *cached_plan_nodes = (hb_face_t::plan_node_t *) hb_atom
ic_ptr_get (&face->shape_plans); | 419 hb_face_t::plan_node_t *cached_plan_nodes = (hb_face_t::plan_node_t *) hb_atom
ic_ptr_get (&face->shape_plans); |
375 for (hb_face_t::plan_node_t *node = cached_plan_nodes; node; node = node->next
) | 420 for (hb_face_t::plan_node_t *node = cached_plan_nodes; node; node = node->next
) |
376 if (hb_shape_plan_matches (node->shape_plan, &proposal)) | 421 if (hb_shape_plan_matches (node->shape_plan, &proposal)) |
377 return hb_shape_plan_reference (node->shape_plan); | 422 return hb_shape_plan_reference (node->shape_plan); |
378 | 423 |
379 /* Not found. */ | 424 /* Not found. */ |
380 | 425 |
381 hb_shape_plan_t *shape_plan = hb_shape_plan_create (face, props, user_features
, num_user_features, shaper_list); | 426 hb_shape_plan_t *shape_plan = hb_shape_plan_create (face, props, user_features
, num_user_features, shaper_list); |
382 | 427 |
| 428 /* Don't add the plan to the cache if there were user features with non-global
ranges */ |
| 429 |
| 430 if (hb_non_global_user_features_present (user_features, num_user_features)) |
| 431 return shape_plan; |
| 432 |
383 hb_face_t::plan_node_t *node = (hb_face_t::plan_node_t *) calloc (1, sizeof (h
b_face_t::plan_node_t)); | 433 hb_face_t::plan_node_t *node = (hb_face_t::plan_node_t *) calloc (1, sizeof (h
b_face_t::plan_node_t)); |
384 if (unlikely (!node)) | 434 if (unlikely (!node)) |
385 return shape_plan; | 435 return shape_plan; |
386 | 436 |
387 node->shape_plan = shape_plan; | 437 node->shape_plan = shape_plan; |
388 node->next = cached_plan_nodes; | 438 node->next = cached_plan_nodes; |
389 | 439 |
390 if (!hb_atomic_ptr_cmpexch (&face->shape_plans, cached_plan_nodes, node)) { | 440 if (!hb_atomic_ptr_cmpexch (&face->shape_plans, cached_plan_nodes, node)) { |
391 hb_shape_plan_destroy (shape_plan); | 441 hb_shape_plan_destroy (shape_plan); |
392 free (node); | 442 free (node); |
(...skipping 11 matching lines...) Expand all Loading... |
404 * | 454 * |
405 * Return value: (transfer none): | 455 * Return value: (transfer none): |
406 * | 456 * |
407 * Since: 1.0 | 457 * Since: 1.0 |
408 **/ | 458 **/ |
409 const char * | 459 const char * |
410 hb_shape_plan_get_shaper (hb_shape_plan_t *shape_plan) | 460 hb_shape_plan_get_shaper (hb_shape_plan_t *shape_plan) |
411 { | 461 { |
412 return shape_plan->shaper_name; | 462 return shape_plan->shaper_name; |
413 } | 463 } |
OLD | NEW |