gfx/harfbuzz/src/hb-shape-plan.cc

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

michael@0 1 /*
michael@0 2 * Copyright © 2012 Google, Inc.
michael@0 3 *
michael@0 4 * This is part of HarfBuzz, a text shaping library.
michael@0 5 *
michael@0 6 * Permission is hereby granted, without written agreement and without
michael@0 7 * license or royalty fees, to use, copy, modify, and distribute this
michael@0 8 * software and its documentation for any purpose, provided that the
michael@0 9 * above copyright notice and the following two paragraphs appear in
michael@0 10 * all copies of this software.
michael@0 11 *
michael@0 12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
michael@0 13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
michael@0 14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
michael@0 15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
michael@0 16 * DAMAGE.
michael@0 17 *
michael@0 18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
michael@0 19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
michael@0 20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
michael@0 21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
michael@0 22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
michael@0 23 *
michael@0 24 * Google Author(s): Behdad Esfahbod
michael@0 25 */
michael@0 26
michael@0 27 #include "hb-shape-plan-private.hh"
michael@0 28 #include "hb-shaper-private.hh"
michael@0 29 #include "hb-font-private.hh"
michael@0 30 #include "hb-buffer-private.hh"
michael@0 31
michael@0 32 #define HB_SHAPER_IMPLEMENT(shaper) \
michael@0 33 HB_SHAPER_DATA_ENSURE_DECLARE(shaper, face) \
michael@0 34 HB_SHAPER_DATA_ENSURE_DECLARE(shaper, font)
michael@0 35 #include "hb-shaper-list.hh"
michael@0 36 #undef HB_SHAPER_IMPLEMENT
michael@0 37
michael@0 38
michael@0 39 static void
michael@0 40 hb_shape_plan_plan (hb_shape_plan_t *shape_plan,
michael@0 41 const hb_feature_t *user_features,
michael@0 42 unsigned int num_user_features,
michael@0 43 const char * const *shaper_list)
michael@0 44 {
michael@0 45 const hb_shaper_pair_t *shapers = _hb_shapers_get ();
michael@0 46
michael@0 47 #define HB_SHAPER_PLAN(shaper) \
michael@0 48 HB_STMT_START { \
michael@0 49 if (hb_##shaper##_shaper_face_data_ensure (shape_plan->face_unsafe)) { \
michael@0 50 HB_SHAPER_DATA (shaper, shape_plan) = \
michael@0 51 HB_SHAPER_DATA_CREATE_FUNC (shaper, shape_plan) (shape_plan, user_features, num_user_features); \
michael@0 52 shape_plan->shaper_func = _hb_##shaper##_shape; \
michael@0 53 shape_plan->shaper_name = #shaper; \
michael@0 54 return; \
michael@0 55 } \
michael@0 56 } HB_STMT_END
michael@0 57
michael@0 58 if (likely (!shaper_list)) {
michael@0 59 for (unsigned int i = 0; i < HB_SHAPERS_COUNT; i++)
michael@0 60 if (0)
michael@0 61 ;
michael@0 62 #define HB_SHAPER_IMPLEMENT(shaper) \
michael@0 63 else if (shapers[i].func == _hb_##shaper##_shape) \
michael@0 64 HB_SHAPER_PLAN (shaper);
michael@0 65 #include "hb-shaper-list.hh"
michael@0 66 #undef HB_SHAPER_IMPLEMENT
michael@0 67 } else {
michael@0 68 for (; *shaper_list; shaper_list++)
michael@0 69 if (0)
michael@0 70 ;
michael@0 71 #define HB_SHAPER_IMPLEMENT(shaper) \
michael@0 72 else if (0 == strcmp (*shaper_list, #shaper)) \
michael@0 73 HB_SHAPER_PLAN (shaper);
michael@0 74 #include "hb-shaper-list.hh"
michael@0 75 #undef HB_SHAPER_IMPLEMENT
michael@0 76 }
michael@0 77
michael@0 78 #undef HB_SHAPER_PLAN
michael@0 79 }
michael@0 80
michael@0 81
michael@0 82 /*
michael@0 83 * hb_shape_plan_t
michael@0 84 */
michael@0 85
michael@0 86 /**
michael@0 87 * hb_shape_plan_create: (Xconstructor)
michael@0 88 * @face:
michael@0 89 * @props:
michael@0 90 * @user_features: (array length=num_user_features):
michael@0 91 * @num_user_features:
michael@0 92 * @shaper_list: (array zero-terminated=1):
michael@0 93 *
michael@0 94 *
michael@0 95 *
michael@0 96 * Return value: (transfer full):
michael@0 97 *
michael@0 98 * Since: 1.0
michael@0 99 **/
michael@0 100 hb_shape_plan_t *
michael@0 101 hb_shape_plan_create (hb_face_t *face,
michael@0 102 const hb_segment_properties_t *props,
michael@0 103 const hb_feature_t *user_features,
michael@0 104 unsigned int num_user_features,
michael@0 105 const char * const *shaper_list)
michael@0 106 {
michael@0 107 assert (props->direction != HB_DIRECTION_INVALID);
michael@0 108
michael@0 109 hb_shape_plan_t *shape_plan;
michael@0 110 hb_feature_t *features = NULL;
michael@0 111
michael@0 112 if (unlikely (!face))
michael@0 113 face = hb_face_get_empty ();
michael@0 114 if (unlikely (!props || hb_object_is_inert (face)))
michael@0 115 return hb_shape_plan_get_empty ();
michael@0 116 if (num_user_features && !(features = (hb_feature_t *) malloc (num_user_features * sizeof (hb_feature_t))))
michael@0 117 return hb_shape_plan_get_empty ();
michael@0 118 if (!(shape_plan = hb_object_create<hb_shape_plan_t> ())) {
michael@0 119 free (features);
michael@0 120 return hb_shape_plan_get_empty ();
michael@0 121 }
michael@0 122
michael@0 123 hb_face_make_immutable (face);
michael@0 124 shape_plan->default_shaper_list = shaper_list == NULL;
michael@0 125 shape_plan->face_unsafe = face;
michael@0 126 shape_plan->props = *props;
michael@0 127 shape_plan->num_user_features = num_user_features;
michael@0 128 shape_plan->user_features = features;
michael@0 129 if (num_user_features)
michael@0 130 memcpy (features, user_features, num_user_features * sizeof (hb_feature_t));
michael@0 131
michael@0 132 hb_shape_plan_plan (shape_plan, user_features, num_user_features, shaper_list);
michael@0 133
michael@0 134 return shape_plan;
michael@0 135 }
michael@0 136
michael@0 137 /**
michael@0 138 * hb_shape_plan_get_empty:
michael@0 139 *
michael@0 140 *
michael@0 141 *
michael@0 142 * Return value: (transfer full):
michael@0 143 *
michael@0 144 * Since: 1.0
michael@0 145 **/
michael@0 146 hb_shape_plan_t *
michael@0 147 hb_shape_plan_get_empty (void)
michael@0 148 {
michael@0 149 static const hb_shape_plan_t _hb_shape_plan_nil = {
michael@0 150 HB_OBJECT_HEADER_STATIC,
michael@0 151
michael@0 152 true, /* default_shaper_list */
michael@0 153 NULL, /* face */
michael@0 154 HB_SEGMENT_PROPERTIES_DEFAULT, /* props */
michael@0 155
michael@0 156 NULL, /* shaper_func */
michael@0 157 NULL, /* shaper_name */
michael@0 158
michael@0 159 NULL, /* user_features */
michael@0 160 0, /* num_user_featurs */
michael@0 161
michael@0 162 {
michael@0 163 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
michael@0 164 #include "hb-shaper-list.hh"
michael@0 165 #undef HB_SHAPER_IMPLEMENT
michael@0 166 }
michael@0 167 };
michael@0 168
michael@0 169 return const_cast<hb_shape_plan_t *> (&_hb_shape_plan_nil);
michael@0 170 }
michael@0 171
michael@0 172 /**
michael@0 173 * hb_shape_plan_reference: (skip)
michael@0 174 * @shape_plan: a shape plan.
michael@0 175 *
michael@0 176 *
michael@0 177 *
michael@0 178 * Return value: (transfer full):
michael@0 179 *
michael@0 180 * Since: 1.0
michael@0 181 **/
michael@0 182 hb_shape_plan_t *
michael@0 183 hb_shape_plan_reference (hb_shape_plan_t *shape_plan)
michael@0 184 {
michael@0 185 return hb_object_reference (shape_plan);
michael@0 186 }
michael@0 187
michael@0 188 /**
michael@0 189 * hb_shape_plan_destroy: (skip)
michael@0 190 * @shape_plan: a shape plan.
michael@0 191 *
michael@0 192 *
michael@0 193 *
michael@0 194 * Since: 1.0
michael@0 195 **/
michael@0 196 void
michael@0 197 hb_shape_plan_destroy (hb_shape_plan_t *shape_plan)
michael@0 198 {
michael@0 199 if (!hb_object_destroy (shape_plan)) return;
michael@0 200
michael@0 201 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, shape_plan);
michael@0 202 #include "hb-shaper-list.hh"
michael@0 203 #undef HB_SHAPER_IMPLEMENT
michael@0 204
michael@0 205 free (shape_plan->user_features);
michael@0 206
michael@0 207 free (shape_plan);
michael@0 208 }
michael@0 209
michael@0 210 /**
michael@0 211 * hb_shape_plan_set_user_data: (skip)
michael@0 212 * @shape_plan: a shape plan.
michael@0 213 * @key:
michael@0 214 * @data:
michael@0 215 * @destroy:
michael@0 216 * @replace:
michael@0 217 *
michael@0 218 *
michael@0 219 *
michael@0 220 * Return value:
michael@0 221 *
michael@0 222 * Since: 1.0
michael@0 223 **/
michael@0 224 hb_bool_t
michael@0 225 hb_shape_plan_set_user_data (hb_shape_plan_t *shape_plan,
michael@0 226 hb_user_data_key_t *key,
michael@0 227 void * data,
michael@0 228 hb_destroy_func_t destroy,
michael@0 229 hb_bool_t replace)
michael@0 230 {
michael@0 231 return hb_object_set_user_data (shape_plan, key, data, destroy, replace);
michael@0 232 }
michael@0 233
michael@0 234 /**
michael@0 235 * hb_shape_plan_get_user_data: (skip)
michael@0 236 * @shape_plan: a shape plan.
michael@0 237 * @key:
michael@0 238 *
michael@0 239 *
michael@0 240 *
michael@0 241 * Return value: (transfer none):
michael@0 242 *
michael@0 243 * Since: 1.0
michael@0 244 **/
michael@0 245 void *
michael@0 246 hb_shape_plan_get_user_data (hb_shape_plan_t *shape_plan,
michael@0 247 hb_user_data_key_t *key)
michael@0 248 {
michael@0 249 return hb_object_get_user_data (shape_plan, key);
michael@0 250 }
michael@0 251
michael@0 252
michael@0 253 /**
michael@0 254 * hb_shape_plan_execute:
michael@0 255 * @shape_plan: a shape plan.
michael@0 256 * @font: a font.
michael@0 257 * @buffer: a buffer.
michael@0 258 * @features: (array length=num_features):
michael@0 259 * @num_features:
michael@0 260 *
michael@0 261 *
michael@0 262 *
michael@0 263 * Return value:
michael@0 264 *
michael@0 265 * Since: 1.0
michael@0 266 **/
michael@0 267 hb_bool_t
michael@0 268 hb_shape_plan_execute (hb_shape_plan_t *shape_plan,
michael@0 269 hb_font_t *font,
michael@0 270 hb_buffer_t *buffer,
michael@0 271 const hb_feature_t *features,
michael@0 272 unsigned int num_features)
michael@0 273 {
michael@0 274 if (unlikely (hb_object_is_inert (shape_plan) ||
michael@0 275 hb_object_is_inert (font) ||
michael@0 276 hb_object_is_inert (buffer)))
michael@0 277 return false;
michael@0 278
michael@0 279 assert (shape_plan->face_unsafe == font->face);
michael@0 280 assert (hb_segment_properties_equal (&shape_plan->props, &buffer->props));
michael@0 281
michael@0 282 #define HB_SHAPER_EXECUTE(shaper) \
michael@0 283 HB_STMT_START { \
michael@0 284 return HB_SHAPER_DATA (shaper, shape_plan) && \
michael@0 285 hb_##shaper##_shaper_font_data_ensure (font) && \
michael@0 286 _hb_##shaper##_shape (shape_plan, font, buffer, features, num_features); \
michael@0 287 } HB_STMT_END
michael@0 288
michael@0 289 if (0)
michael@0 290 ;
michael@0 291 #define HB_SHAPER_IMPLEMENT(shaper) \
michael@0 292 else if (shape_plan->shaper_func == _hb_##shaper##_shape) \
michael@0 293 HB_SHAPER_EXECUTE (shaper);
michael@0 294 #include "hb-shaper-list.hh"
michael@0 295 #undef HB_SHAPER_IMPLEMENT
michael@0 296
michael@0 297 #undef HB_SHAPER_EXECUTE
michael@0 298
michael@0 299 return false;
michael@0 300 }
michael@0 301
michael@0 302
michael@0 303 /*
michael@0 304 * caching
michael@0 305 */
michael@0 306
michael@0 307 #if 0
michael@0 308 static unsigned int
michael@0 309 hb_shape_plan_hash (const hb_shape_plan_t *shape_plan)
michael@0 310 {
michael@0 311 return hb_segment_properties_hash (&shape_plan->props) +
michael@0 312 shape_plan->default_shaper_list ? 0 : (intptr_t) shape_plan->shaper_func;
michael@0 313 }
michael@0 314 #endif
michael@0 315
michael@0 316 /* User-feature caching is currently somewhat dumb:
michael@0 317 * it only finds matches where the feature array is identical,
michael@0 318 * not cases where the feature lists would be compatible for plan purposes
michael@0 319 * but have different ranges, for example.
michael@0 320 */
michael@0 321 struct hb_shape_plan_proposal_t
michael@0 322 {
michael@0 323 const hb_segment_properties_t props;
michael@0 324 const char * const *shaper_list;
michael@0 325 const hb_feature_t *user_features;
michael@0 326 unsigned int num_user_features;
michael@0 327 hb_shape_func_t *shaper_func;
michael@0 328 };
michael@0 329
michael@0 330 static inline hb_bool_t
michael@0 331 hb_shape_plan_user_features_match (const hb_shape_plan_t *shape_plan,
michael@0 332 const hb_shape_plan_proposal_t *proposal)
michael@0 333 {
michael@0 334 if (proposal->num_user_features != shape_plan->num_user_features) return false;
michael@0 335 for (unsigned int i = 0, n = proposal->num_user_features; i < n; i++)
michael@0 336 if (proposal->user_features[i].tag != shape_plan->user_features[i].tag ||
michael@0 337 proposal->user_features[i].value != shape_plan->user_features[i].value ||
michael@0 338 proposal->user_features[i].start != shape_plan->user_features[i].start ||
michael@0 339 proposal->user_features[i].end != shape_plan->user_features[i].end) return false;
michael@0 340 return true;
michael@0 341 }
michael@0 342
michael@0 343 static hb_bool_t
michael@0 344 hb_shape_plan_matches (const hb_shape_plan_t *shape_plan,
michael@0 345 const hb_shape_plan_proposal_t *proposal)
michael@0 346 {
michael@0 347 return hb_segment_properties_equal (&shape_plan->props, &proposal->props) &&
michael@0 348 hb_shape_plan_user_features_match (shape_plan, proposal) &&
michael@0 349 ((shape_plan->default_shaper_list && proposal->shaper_list == NULL) ||
michael@0 350 (shape_plan->shaper_func == proposal->shaper_func));
michael@0 351 }
michael@0 352
michael@0 353 static inline hb_bool_t
michael@0 354 hb_non_global_user_features_present (const hb_feature_t *user_features,
michael@0 355 unsigned int num_user_features)
michael@0 356 {
michael@0 357 while (num_user_features)
michael@0 358 if (user_features->start != 0 || user_features->end != (unsigned int) -1)
michael@0 359 return true;
michael@0 360 else
michael@0 361 num_user_features--, user_features++;
michael@0 362 return false;
michael@0 363 }
michael@0 364
michael@0 365 /**
michael@0 366 * hb_shape_plan_create_cached:
michael@0 367 * @face:
michael@0 368 * @props:
michael@0 369 * @user_features: (array length=num_user_features):
michael@0 370 * @num_user_features:
michael@0 371 * @shaper_list: (array zero-terminated=1):
michael@0 372 *
michael@0 373 *
michael@0 374 *
michael@0 375 * Return value: (transfer full):
michael@0 376 *
michael@0 377 * Since: 1.0
michael@0 378 **/
michael@0 379 hb_shape_plan_t *
michael@0 380 hb_shape_plan_create_cached (hb_face_t *face,
michael@0 381 const hb_segment_properties_t *props,
michael@0 382 const hb_feature_t *user_features,
michael@0 383 unsigned int num_user_features,
michael@0 384 const char * const *shaper_list)
michael@0 385 {
michael@0 386 hb_shape_plan_proposal_t proposal = {
michael@0 387 *props,
michael@0 388 shaper_list,
michael@0 389 user_features,
michael@0 390 num_user_features,
michael@0 391 NULL
michael@0 392 };
michael@0 393
michael@0 394 if (shaper_list) {
michael@0 395 /* Choose shaper. Adapted from hb_shape_plan_plan(). */
michael@0 396 #define HB_SHAPER_PLAN(shaper) \
michael@0 397 HB_STMT_START { \
michael@0 398 if (hb_##shaper##_shaper_face_data_ensure (face)) \
michael@0 399 proposal.shaper_func = _hb_##shaper##_shape; \
michael@0 400 } HB_STMT_END
michael@0 401
michael@0 402 for (const char * const *shaper_item = shaper_list; *shaper_item; shaper_item++)
michael@0 403 if (0)
michael@0 404 ;
michael@0 405 #define HB_SHAPER_IMPLEMENT(shaper) \
michael@0 406 else if (0 == strcmp (*shaper_item, #shaper)) \
michael@0 407 HB_SHAPER_PLAN (shaper);
michael@0 408 #include "hb-shaper-list.hh"
michael@0 409 #undef HB_SHAPER_IMPLEMENT
michael@0 410
michael@0 411 #undef HB_SHAPER_PLAN
michael@0 412
michael@0 413 if (unlikely (!proposal.shaper_list))
michael@0 414 return hb_shape_plan_get_empty ();
michael@0 415 }
michael@0 416
michael@0 417
michael@0 418 retry:
michael@0 419 hb_face_t::plan_node_t *cached_plan_nodes = (hb_face_t::plan_node_t *) hb_atomic_ptr_get (&face->shape_plans);
michael@0 420 for (hb_face_t::plan_node_t *node = cached_plan_nodes; node; node = node->next)
michael@0 421 if (hb_shape_plan_matches (node->shape_plan, &proposal))
michael@0 422 return hb_shape_plan_reference (node->shape_plan);
michael@0 423
michael@0 424 /* Not found. */
michael@0 425
michael@0 426 hb_shape_plan_t *shape_plan = hb_shape_plan_create (face, props, user_features, num_user_features, shaper_list);
michael@0 427
michael@0 428 /* Don't add the plan to the cache if there were user features with non-global ranges */
michael@0 429
michael@0 430 if (hb_non_global_user_features_present (user_features, num_user_features))
michael@0 431 return shape_plan;
michael@0 432
michael@0 433 hb_face_t::plan_node_t *node = (hb_face_t::plan_node_t *) calloc (1, sizeof (hb_face_t::plan_node_t));
michael@0 434 if (unlikely (!node))
michael@0 435 return shape_plan;
michael@0 436
michael@0 437 node->shape_plan = shape_plan;
michael@0 438 node->next = cached_plan_nodes;
michael@0 439
michael@0 440 if (!hb_atomic_ptr_cmpexch (&face->shape_plans, cached_plan_nodes, node)) {
michael@0 441 hb_shape_plan_destroy (shape_plan);
michael@0 442 free (node);
michael@0 443 goto retry;
michael@0 444 }
michael@0 445
michael@0 446 return hb_shape_plan_reference (shape_plan);
michael@0 447 }
michael@0 448
michael@0 449 /**
michael@0 450 * hb_shape_plan_get_shaper:
michael@0 451 * @shape_plan: a shape plan.
michael@0 452 *
michael@0 453 *
michael@0 454 *
michael@0 455 * Return value: (transfer none):
michael@0 456 *
michael@0 457 * Since: 1.0
michael@0 458 **/
michael@0 459 const char *
michael@0 460 hb_shape_plan_get_shaper (hb_shape_plan_t *shape_plan)
michael@0 461 {
michael@0 462 return shape_plan->shaper_name;
michael@0 463 }

mercurial