1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/harfbuzz/src/hb-shape-plan.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,463 @@ 1.4 +/* 1.5 + * Copyright © 2012 Google, Inc. 1.6 + * 1.7 + * This is part of HarfBuzz, a text shaping library. 1.8 + * 1.9 + * Permission is hereby granted, without written agreement and without 1.10 + * license or royalty fees, to use, copy, modify, and distribute this 1.11 + * software and its documentation for any purpose, provided that the 1.12 + * above copyright notice and the following two paragraphs appear in 1.13 + * all copies of this software. 1.14 + * 1.15 + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 1.16 + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 1.17 + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 1.18 + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 1.19 + * DAMAGE. 1.20 + * 1.21 + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 1.22 + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 1.23 + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 1.24 + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 1.25 + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 1.26 + * 1.27 + * Google Author(s): Behdad Esfahbod 1.28 + */ 1.29 + 1.30 +#include "hb-shape-plan-private.hh" 1.31 +#include "hb-shaper-private.hh" 1.32 +#include "hb-font-private.hh" 1.33 +#include "hb-buffer-private.hh" 1.34 + 1.35 +#define HB_SHAPER_IMPLEMENT(shaper) \ 1.36 + HB_SHAPER_DATA_ENSURE_DECLARE(shaper, face) \ 1.37 + HB_SHAPER_DATA_ENSURE_DECLARE(shaper, font) 1.38 +#include "hb-shaper-list.hh" 1.39 +#undef HB_SHAPER_IMPLEMENT 1.40 + 1.41 + 1.42 +static void 1.43 +hb_shape_plan_plan (hb_shape_plan_t *shape_plan, 1.44 + const hb_feature_t *user_features, 1.45 + unsigned int num_user_features, 1.46 + const char * const *shaper_list) 1.47 +{ 1.48 + const hb_shaper_pair_t *shapers = _hb_shapers_get (); 1.49 + 1.50 +#define HB_SHAPER_PLAN(shaper) \ 1.51 + HB_STMT_START { \ 1.52 + if (hb_##shaper##_shaper_face_data_ensure (shape_plan->face_unsafe)) { \ 1.53 + HB_SHAPER_DATA (shaper, shape_plan) = \ 1.54 + HB_SHAPER_DATA_CREATE_FUNC (shaper, shape_plan) (shape_plan, user_features, num_user_features); \ 1.55 + shape_plan->shaper_func = _hb_##shaper##_shape; \ 1.56 + shape_plan->shaper_name = #shaper; \ 1.57 + return; \ 1.58 + } \ 1.59 + } HB_STMT_END 1.60 + 1.61 + if (likely (!shaper_list)) { 1.62 + for (unsigned int i = 0; i < HB_SHAPERS_COUNT; i++) 1.63 + if (0) 1.64 + ; 1.65 +#define HB_SHAPER_IMPLEMENT(shaper) \ 1.66 + else if (shapers[i].func == _hb_##shaper##_shape) \ 1.67 + HB_SHAPER_PLAN (shaper); 1.68 +#include "hb-shaper-list.hh" 1.69 +#undef HB_SHAPER_IMPLEMENT 1.70 + } else { 1.71 + for (; *shaper_list; shaper_list++) 1.72 + if (0) 1.73 + ; 1.74 +#define HB_SHAPER_IMPLEMENT(shaper) \ 1.75 + else if (0 == strcmp (*shaper_list, #shaper)) \ 1.76 + HB_SHAPER_PLAN (shaper); 1.77 +#include "hb-shaper-list.hh" 1.78 +#undef HB_SHAPER_IMPLEMENT 1.79 + } 1.80 + 1.81 +#undef HB_SHAPER_PLAN 1.82 +} 1.83 + 1.84 + 1.85 +/* 1.86 + * hb_shape_plan_t 1.87 + */ 1.88 + 1.89 +/** 1.90 + * hb_shape_plan_create: (Xconstructor) 1.91 + * @face: 1.92 + * @props: 1.93 + * @user_features: (array length=num_user_features): 1.94 + * @num_user_features: 1.95 + * @shaper_list: (array zero-terminated=1): 1.96 + * 1.97 + * 1.98 + * 1.99 + * Return value: (transfer full): 1.100 + * 1.101 + * Since: 1.0 1.102 + **/ 1.103 +hb_shape_plan_t * 1.104 +hb_shape_plan_create (hb_face_t *face, 1.105 + const hb_segment_properties_t *props, 1.106 + const hb_feature_t *user_features, 1.107 + unsigned int num_user_features, 1.108 + const char * const *shaper_list) 1.109 +{ 1.110 + assert (props->direction != HB_DIRECTION_INVALID); 1.111 + 1.112 + hb_shape_plan_t *shape_plan; 1.113 + hb_feature_t *features = NULL; 1.114 + 1.115 + if (unlikely (!face)) 1.116 + face = hb_face_get_empty (); 1.117 + if (unlikely (!props || hb_object_is_inert (face))) 1.118 + return hb_shape_plan_get_empty (); 1.119 + if (num_user_features && !(features = (hb_feature_t *) malloc (num_user_features * sizeof (hb_feature_t)))) 1.120 + return hb_shape_plan_get_empty (); 1.121 + if (!(shape_plan = hb_object_create<hb_shape_plan_t> ())) { 1.122 + free (features); 1.123 + return hb_shape_plan_get_empty (); 1.124 + } 1.125 + 1.126 + hb_face_make_immutable (face); 1.127 + shape_plan->default_shaper_list = shaper_list == NULL; 1.128 + shape_plan->face_unsafe = face; 1.129 + shape_plan->props = *props; 1.130 + shape_plan->num_user_features = num_user_features; 1.131 + shape_plan->user_features = features; 1.132 + if (num_user_features) 1.133 + memcpy (features, user_features, num_user_features * sizeof (hb_feature_t)); 1.134 + 1.135 + hb_shape_plan_plan (shape_plan, user_features, num_user_features, shaper_list); 1.136 + 1.137 + return shape_plan; 1.138 +} 1.139 + 1.140 +/** 1.141 + * hb_shape_plan_get_empty: 1.142 + * 1.143 + * 1.144 + * 1.145 + * Return value: (transfer full): 1.146 + * 1.147 + * Since: 1.0 1.148 + **/ 1.149 +hb_shape_plan_t * 1.150 +hb_shape_plan_get_empty (void) 1.151 +{ 1.152 + static const hb_shape_plan_t _hb_shape_plan_nil = { 1.153 + HB_OBJECT_HEADER_STATIC, 1.154 + 1.155 + true, /* default_shaper_list */ 1.156 + NULL, /* face */ 1.157 + HB_SEGMENT_PROPERTIES_DEFAULT, /* props */ 1.158 + 1.159 + NULL, /* shaper_func */ 1.160 + NULL, /* shaper_name */ 1.161 + 1.162 + NULL, /* user_features */ 1.163 + 0, /* num_user_featurs */ 1.164 + 1.165 + { 1.166 +#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID, 1.167 +#include "hb-shaper-list.hh" 1.168 +#undef HB_SHAPER_IMPLEMENT 1.169 + } 1.170 + }; 1.171 + 1.172 + return const_cast<hb_shape_plan_t *> (&_hb_shape_plan_nil); 1.173 +} 1.174 + 1.175 +/** 1.176 + * hb_shape_plan_reference: (skip) 1.177 + * @shape_plan: a shape plan. 1.178 + * 1.179 + * 1.180 + * 1.181 + * Return value: (transfer full): 1.182 + * 1.183 + * Since: 1.0 1.184 + **/ 1.185 +hb_shape_plan_t * 1.186 +hb_shape_plan_reference (hb_shape_plan_t *shape_plan) 1.187 +{ 1.188 + return hb_object_reference (shape_plan); 1.189 +} 1.190 + 1.191 +/** 1.192 + * hb_shape_plan_destroy: (skip) 1.193 + * @shape_plan: a shape plan. 1.194 + * 1.195 + * 1.196 + * 1.197 + * Since: 1.0 1.198 + **/ 1.199 +void 1.200 +hb_shape_plan_destroy (hb_shape_plan_t *shape_plan) 1.201 +{ 1.202 + if (!hb_object_destroy (shape_plan)) return; 1.203 + 1.204 +#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, shape_plan); 1.205 +#include "hb-shaper-list.hh" 1.206 +#undef HB_SHAPER_IMPLEMENT 1.207 + 1.208 + free (shape_plan->user_features); 1.209 + 1.210 + free (shape_plan); 1.211 +} 1.212 + 1.213 +/** 1.214 + * hb_shape_plan_set_user_data: (skip) 1.215 + * @shape_plan: a shape plan. 1.216 + * @key: 1.217 + * @data: 1.218 + * @destroy: 1.219 + * @replace: 1.220 + * 1.221 + * 1.222 + * 1.223 + * Return value: 1.224 + * 1.225 + * Since: 1.0 1.226 + **/ 1.227 +hb_bool_t 1.228 +hb_shape_plan_set_user_data (hb_shape_plan_t *shape_plan, 1.229 + hb_user_data_key_t *key, 1.230 + void * data, 1.231 + hb_destroy_func_t destroy, 1.232 + hb_bool_t replace) 1.233 +{ 1.234 + return hb_object_set_user_data (shape_plan, key, data, destroy, replace); 1.235 +} 1.236 + 1.237 +/** 1.238 + * hb_shape_plan_get_user_data: (skip) 1.239 + * @shape_plan: a shape plan. 1.240 + * @key: 1.241 + * 1.242 + * 1.243 + * 1.244 + * Return value: (transfer none): 1.245 + * 1.246 + * Since: 1.0 1.247 + **/ 1.248 +void * 1.249 +hb_shape_plan_get_user_data (hb_shape_plan_t *shape_plan, 1.250 + hb_user_data_key_t *key) 1.251 +{ 1.252 + return hb_object_get_user_data (shape_plan, key); 1.253 +} 1.254 + 1.255 + 1.256 +/** 1.257 + * hb_shape_plan_execute: 1.258 + * @shape_plan: a shape plan. 1.259 + * @font: a font. 1.260 + * @buffer: a buffer. 1.261 + * @features: (array length=num_features): 1.262 + * @num_features: 1.263 + * 1.264 + * 1.265 + * 1.266 + * Return value: 1.267 + * 1.268 + * Since: 1.0 1.269 + **/ 1.270 +hb_bool_t 1.271 +hb_shape_plan_execute (hb_shape_plan_t *shape_plan, 1.272 + hb_font_t *font, 1.273 + hb_buffer_t *buffer, 1.274 + const hb_feature_t *features, 1.275 + unsigned int num_features) 1.276 +{ 1.277 + if (unlikely (hb_object_is_inert (shape_plan) || 1.278 + hb_object_is_inert (font) || 1.279 + hb_object_is_inert (buffer))) 1.280 + return false; 1.281 + 1.282 + assert (shape_plan->face_unsafe == font->face); 1.283 + assert (hb_segment_properties_equal (&shape_plan->props, &buffer->props)); 1.284 + 1.285 +#define HB_SHAPER_EXECUTE(shaper) \ 1.286 + HB_STMT_START { \ 1.287 + return HB_SHAPER_DATA (shaper, shape_plan) && \ 1.288 + hb_##shaper##_shaper_font_data_ensure (font) && \ 1.289 + _hb_##shaper##_shape (shape_plan, font, buffer, features, num_features); \ 1.290 + } HB_STMT_END 1.291 + 1.292 + if (0) 1.293 + ; 1.294 +#define HB_SHAPER_IMPLEMENT(shaper) \ 1.295 + else if (shape_plan->shaper_func == _hb_##shaper##_shape) \ 1.296 + HB_SHAPER_EXECUTE (shaper); 1.297 +#include "hb-shaper-list.hh" 1.298 +#undef HB_SHAPER_IMPLEMENT 1.299 + 1.300 +#undef HB_SHAPER_EXECUTE 1.301 + 1.302 + return false; 1.303 +} 1.304 + 1.305 + 1.306 +/* 1.307 + * caching 1.308 + */ 1.309 + 1.310 +#if 0 1.311 +static unsigned int 1.312 +hb_shape_plan_hash (const hb_shape_plan_t *shape_plan) 1.313 +{ 1.314 + return hb_segment_properties_hash (&shape_plan->props) + 1.315 + shape_plan->default_shaper_list ? 0 : (intptr_t) shape_plan->shaper_func; 1.316 +} 1.317 +#endif 1.318 + 1.319 +/* User-feature caching is currently somewhat dumb: 1.320 + * it only finds matches where the feature array is identical, 1.321 + * not cases where the feature lists would be compatible for plan purposes 1.322 + * but have different ranges, for example. 1.323 + */ 1.324 +struct hb_shape_plan_proposal_t 1.325 +{ 1.326 + const hb_segment_properties_t props; 1.327 + const char * const *shaper_list; 1.328 + const hb_feature_t *user_features; 1.329 + unsigned int num_user_features; 1.330 + hb_shape_func_t *shaper_func; 1.331 +}; 1.332 + 1.333 +static inline hb_bool_t 1.334 +hb_shape_plan_user_features_match (const hb_shape_plan_t *shape_plan, 1.335 + const hb_shape_plan_proposal_t *proposal) 1.336 +{ 1.337 + if (proposal->num_user_features != shape_plan->num_user_features) return false; 1.338 + for (unsigned int i = 0, n = proposal->num_user_features; i < n; i++) 1.339 + if (proposal->user_features[i].tag != shape_plan->user_features[i].tag || 1.340 + proposal->user_features[i].value != shape_plan->user_features[i].value || 1.341 + proposal->user_features[i].start != shape_plan->user_features[i].start || 1.342 + proposal->user_features[i].end != shape_plan->user_features[i].end) return false; 1.343 + return true; 1.344 +} 1.345 + 1.346 +static hb_bool_t 1.347 +hb_shape_plan_matches (const hb_shape_plan_t *shape_plan, 1.348 + const hb_shape_plan_proposal_t *proposal) 1.349 +{ 1.350 + return hb_segment_properties_equal (&shape_plan->props, &proposal->props) && 1.351 + hb_shape_plan_user_features_match (shape_plan, proposal) && 1.352 + ((shape_plan->default_shaper_list && proposal->shaper_list == NULL) || 1.353 + (shape_plan->shaper_func == proposal->shaper_func)); 1.354 +} 1.355 + 1.356 +static inline hb_bool_t 1.357 +hb_non_global_user_features_present (const hb_feature_t *user_features, 1.358 + unsigned int num_user_features) 1.359 +{ 1.360 + while (num_user_features) 1.361 + if (user_features->start != 0 || user_features->end != (unsigned int) -1) 1.362 + return true; 1.363 + else 1.364 + num_user_features--, user_features++; 1.365 + return false; 1.366 +} 1.367 + 1.368 +/** 1.369 + * hb_shape_plan_create_cached: 1.370 + * @face: 1.371 + * @props: 1.372 + * @user_features: (array length=num_user_features): 1.373 + * @num_user_features: 1.374 + * @shaper_list: (array zero-terminated=1): 1.375 + * 1.376 + * 1.377 + * 1.378 + * Return value: (transfer full): 1.379 + * 1.380 + * Since: 1.0 1.381 + **/ 1.382 +hb_shape_plan_t * 1.383 +hb_shape_plan_create_cached (hb_face_t *face, 1.384 + const hb_segment_properties_t *props, 1.385 + const hb_feature_t *user_features, 1.386 + unsigned int num_user_features, 1.387 + const char * const *shaper_list) 1.388 +{ 1.389 + hb_shape_plan_proposal_t proposal = { 1.390 + *props, 1.391 + shaper_list, 1.392 + user_features, 1.393 + num_user_features, 1.394 + NULL 1.395 + }; 1.396 + 1.397 + if (shaper_list) { 1.398 + /* Choose shaper. Adapted from hb_shape_plan_plan(). */ 1.399 +#define HB_SHAPER_PLAN(shaper) \ 1.400 + HB_STMT_START { \ 1.401 + if (hb_##shaper##_shaper_face_data_ensure (face)) \ 1.402 + proposal.shaper_func = _hb_##shaper##_shape; \ 1.403 + } HB_STMT_END 1.404 + 1.405 + for (const char * const *shaper_item = shaper_list; *shaper_item; shaper_item++) 1.406 + if (0) 1.407 + ; 1.408 +#define HB_SHAPER_IMPLEMENT(shaper) \ 1.409 + else if (0 == strcmp (*shaper_item, #shaper)) \ 1.410 + HB_SHAPER_PLAN (shaper); 1.411 +#include "hb-shaper-list.hh" 1.412 +#undef HB_SHAPER_IMPLEMENT 1.413 + 1.414 +#undef HB_SHAPER_PLAN 1.415 + 1.416 + if (unlikely (!proposal.shaper_list)) 1.417 + return hb_shape_plan_get_empty (); 1.418 + } 1.419 + 1.420 + 1.421 +retry: 1.422 + hb_face_t::plan_node_t *cached_plan_nodes = (hb_face_t::plan_node_t *) hb_atomic_ptr_get (&face->shape_plans); 1.423 + for (hb_face_t::plan_node_t *node = cached_plan_nodes; node; node = node->next) 1.424 + if (hb_shape_plan_matches (node->shape_plan, &proposal)) 1.425 + return hb_shape_plan_reference (node->shape_plan); 1.426 + 1.427 + /* Not found. */ 1.428 + 1.429 + hb_shape_plan_t *shape_plan = hb_shape_plan_create (face, props, user_features, num_user_features, shaper_list); 1.430 + 1.431 + /* Don't add the plan to the cache if there were user features with non-global ranges */ 1.432 + 1.433 + if (hb_non_global_user_features_present (user_features, num_user_features)) 1.434 + return shape_plan; 1.435 + 1.436 + hb_face_t::plan_node_t *node = (hb_face_t::plan_node_t *) calloc (1, sizeof (hb_face_t::plan_node_t)); 1.437 + if (unlikely (!node)) 1.438 + return shape_plan; 1.439 + 1.440 + node->shape_plan = shape_plan; 1.441 + node->next = cached_plan_nodes; 1.442 + 1.443 + if (!hb_atomic_ptr_cmpexch (&face->shape_plans, cached_plan_nodes, node)) { 1.444 + hb_shape_plan_destroy (shape_plan); 1.445 + free (node); 1.446 + goto retry; 1.447 + } 1.448 + 1.449 + return hb_shape_plan_reference (shape_plan); 1.450 +} 1.451 + 1.452 +/** 1.453 + * hb_shape_plan_get_shaper: 1.454 + * @shape_plan: a shape plan. 1.455 + * 1.456 + * 1.457 + * 1.458 + * Return value: (transfer none): 1.459 + * 1.460 + * Since: 1.0 1.461 + **/ 1.462 +const char * 1.463 +hb_shape_plan_get_shaper (hb_shape_plan_t *shape_plan) 1.464 +{ 1.465 + return shape_plan->shaper_name; 1.466 +}