| 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 |