summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/harfbuzz-ng/src/hb-shape-plan.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/harfbuzz-ng/src/hb-shape-plan.cc')
-rw-r--r--chromium/third_party/harfbuzz-ng/src/hb-shape-plan.cc60
1 files changed, 55 insertions, 5 deletions
diff --git a/chromium/third_party/harfbuzz-ng/src/hb-shape-plan.cc b/chromium/third_party/harfbuzz-ng/src/hb-shape-plan.cc
index 13544056d72..e354f291763 100644
--- a/chromium/third_party/harfbuzz-ng/src/hb-shape-plan.cc
+++ b/chromium/third_party/harfbuzz-ng/src/hb-shape-plan.cc
@@ -107,18 +107,27 @@ hb_shape_plan_create (hb_face_t *face,
assert (props->direction != HB_DIRECTION_INVALID);
hb_shape_plan_t *shape_plan;
+ hb_feature_t *features = NULL;
if (unlikely (!face))
face = hb_face_get_empty ();
if (unlikely (!props || hb_object_is_inert (face)))
return hb_shape_plan_get_empty ();
- if (!(shape_plan = hb_object_create<hb_shape_plan_t> ()))
+ if (num_user_features && !(features = (hb_feature_t *) malloc (num_user_features * sizeof (hb_feature_t))))
return hb_shape_plan_get_empty ();
+ if (!(shape_plan = hb_object_create<hb_shape_plan_t> ())) {
+ free (features);
+ return hb_shape_plan_get_empty ();
+ }
hb_face_make_immutable (face);
shape_plan->default_shaper_list = shaper_list == NULL;
shape_plan->face_unsafe = face;
shape_plan->props = *props;
+ shape_plan->num_user_features = num_user_features;
+ shape_plan->user_features = features;
+ if (num_user_features)
+ memcpy (features, user_features, num_user_features * sizeof (hb_feature_t));
hb_shape_plan_plan (shape_plan, user_features, num_user_features, shaper_list);
@@ -147,6 +156,9 @@ hb_shape_plan_get_empty (void)
NULL, /* shaper_func */
NULL, /* shaper_name */
+ NULL, /* user_features */
+ 0, /* num_user_featurs */
+
{
#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
#include "hb-shaper-list.hh"
@@ -190,6 +202,8 @@ hb_shape_plan_destroy (hb_shape_plan_t *shape_plan)
#include "hb-shaper-list.hh"
#undef HB_SHAPER_IMPLEMENT
+ free (shape_plan->user_features);
+
free (shape_plan);
}
@@ -299,23 +313,55 @@ hb_shape_plan_hash (const hb_shape_plan_t *shape_plan)
}
#endif
-/* TODO no user-feature caching for now. */
+/* User-feature caching is currently somewhat dumb:
+ * it only finds matches where the feature array is identical,
+ * not cases where the feature lists would be compatible for plan purposes
+ * but have different ranges, for example.
+ */
struct hb_shape_plan_proposal_t
{
const hb_segment_properties_t props;
const char * const *shaper_list;
+ const hb_feature_t *user_features;
+ unsigned int num_user_features;
hb_shape_func_t *shaper_func;
};
+static inline hb_bool_t
+hb_shape_plan_user_features_match (const hb_shape_plan_t *shape_plan,
+ const hb_shape_plan_proposal_t *proposal)
+{
+ if (proposal->num_user_features != shape_plan->num_user_features) return false;
+ for (unsigned int i = 0, n = proposal->num_user_features; i < n; i++)
+ if (proposal->user_features[i].tag != shape_plan->user_features[i].tag ||
+ proposal->user_features[i].value != shape_plan->user_features[i].value ||
+ proposal->user_features[i].start != shape_plan->user_features[i].start ||
+ proposal->user_features[i].end != shape_plan->user_features[i].end) return false;
+ return true;
+}
+
static hb_bool_t
hb_shape_plan_matches (const hb_shape_plan_t *shape_plan,
const hb_shape_plan_proposal_t *proposal)
{
return hb_segment_properties_equal (&shape_plan->props, &proposal->props) &&
+ hb_shape_plan_user_features_match (shape_plan, proposal) &&
((shape_plan->default_shaper_list && proposal->shaper_list == NULL) ||
(shape_plan->shaper_func == proposal->shaper_func));
}
+static inline hb_bool_t
+hb_non_global_user_features_present (const hb_feature_t *user_features,
+ unsigned int num_user_features)
+{
+ while (num_user_features)
+ if (user_features->start != 0 || user_features->end != (unsigned int) -1)
+ return true;
+ else
+ num_user_features--, user_features++;
+ return false;
+}
+
/**
* hb_shape_plan_create_cached:
* @face:
@@ -337,12 +383,11 @@ hb_shape_plan_create_cached (hb_face_t *face,
unsigned int num_user_features,
const char * const *shaper_list)
{
- if (num_user_features)
- return hb_shape_plan_create (face, props, user_features, num_user_features, shaper_list);
-
hb_shape_plan_proposal_t proposal = {
*props,
shaper_list,
+ user_features,
+ num_user_features,
NULL
};
@@ -380,6 +425,11 @@ retry:
hb_shape_plan_t *shape_plan = hb_shape_plan_create (face, props, user_features, num_user_features, shaper_list);
+ /* Don't add the plan to the cache if there were user features with non-global ranges */
+
+ if (hb_non_global_user_features_present (user_features, num_user_features))
+ return shape_plan;
+
hb_face_t::plan_node_t *node = (hb_face_t::plan_node_t *) calloc (1, sizeof (hb_face_t::plan_node_t));
if (unlikely (!node))
return shape_plan;