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

changeset 0
6474c204b198
     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 +}

mercurial