cache shape plans even if (global) user features are set
This commit is contained in:
parent
8ffa528f28
commit
ca8d96c8ba
|
@ -45,6 +45,9 @@ struct hb_shape_plan_t
|
||||||
hb_shape_func_t *shaper_func;
|
hb_shape_func_t *shaper_func;
|
||||||
const char *shaper_name;
|
const char *shaper_name;
|
||||||
|
|
||||||
|
hb_feature_t *user_features;
|
||||||
|
unsigned int num_user_features;
|
||||||
|
|
||||||
struct hb_shaper_data_t shaper_data;
|
struct hb_shaper_data_t shaper_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -107,18 +107,27 @@ hb_shape_plan_create (hb_face_t *face,
|
||||||
assert (props->direction != HB_DIRECTION_INVALID);
|
assert (props->direction != HB_DIRECTION_INVALID);
|
||||||
|
|
||||||
hb_shape_plan_t *shape_plan;
|
hb_shape_plan_t *shape_plan;
|
||||||
|
hb_feature_t *features = NULL;
|
||||||
|
|
||||||
if (unlikely (!face))
|
if (unlikely (!face))
|
||||||
face = hb_face_get_empty ();
|
face = hb_face_get_empty ();
|
||||||
if (unlikely (!props || hb_object_is_inert (face)))
|
if (unlikely (!props || hb_object_is_inert (face)))
|
||||||
return hb_shape_plan_get_empty ();
|
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 ();
|
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);
|
hb_face_make_immutable (face);
|
||||||
shape_plan->default_shaper_list = shaper_list == NULL;
|
shape_plan->default_shaper_list = shaper_list == NULL;
|
||||||
shape_plan->face = hb_face_reference (face);
|
shape_plan->face = hb_face_reference (face);
|
||||||
shape_plan->props = *props;
|
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);
|
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_func */
|
||||||
NULL, /* shaper_name */
|
NULL, /* shaper_name */
|
||||||
|
|
||||||
|
NULL, /* user_features */
|
||||||
|
0, /* num_user_featurs */
|
||||||
|
|
||||||
{
|
{
|
||||||
#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
|
#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
|
||||||
#include "hb-shaper-list.hh"
|
#include "hb-shaper-list.hh"
|
||||||
|
@ -191,6 +203,7 @@ hb_shape_plan_destroy (hb_shape_plan_t *shape_plan)
|
||||||
#undef HB_SHAPER_IMPLEMENT
|
#undef HB_SHAPER_IMPLEMENT
|
||||||
|
|
||||||
hb_face_destroy (shape_plan->face);
|
hb_face_destroy (shape_plan->face);
|
||||||
|
free (shape_plan->user_features);
|
||||||
|
|
||||||
free (shape_plan);
|
free (shape_plan);
|
||||||
}
|
}
|
||||||
|
@ -301,23 +314,55 @@ hb_shape_plan_hash (const hb_shape_plan_t *shape_plan)
|
||||||
}
|
}
|
||||||
#endif
|
#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
|
struct hb_shape_plan_proposal_t
|
||||||
{
|
{
|
||||||
const hb_segment_properties_t props;
|
const hb_segment_properties_t props;
|
||||||
const char * const *shaper_list;
|
const char * const *shaper_list;
|
||||||
|
const hb_feature_t *user_features;
|
||||||
|
unsigned int num_user_features;
|
||||||
hb_shape_func_t *shaper_func;
|
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
|
static hb_bool_t
|
||||||
hb_shape_plan_matches (const hb_shape_plan_t *shape_plan,
|
hb_shape_plan_matches (const hb_shape_plan_t *shape_plan,
|
||||||
const hb_shape_plan_proposal_t *proposal)
|
const hb_shape_plan_proposal_t *proposal)
|
||||||
{
|
{
|
||||||
return hb_segment_properties_equal (&shape_plan->props, &proposal->props) &&
|
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->default_shaper_list && proposal->shaper_list == NULL) ||
|
||||||
(shape_plan->shaper_func == proposal->shaper_func));
|
(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:
|
* hb_shape_plan_create_cached:
|
||||||
* @face:
|
* @face:
|
||||||
|
@ -339,12 +384,11 @@ hb_shape_plan_create_cached (hb_face_t *face,
|
||||||
unsigned int num_user_features,
|
unsigned int num_user_features,
|
||||||
const char * const *shaper_list)
|
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 = {
|
hb_shape_plan_proposal_t proposal = {
|
||||||
*props,
|
*props,
|
||||||
shaper_list,
|
shaper_list,
|
||||||
|
user_features,
|
||||||
|
num_user_features,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -382,6 +426,11 @@ retry:
|
||||||
|
|
||||||
hb_shape_plan_t *shape_plan = hb_shape_plan_create (face, props, user_features, num_user_features, shaper_list);
|
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));
|
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))
|
if (unlikely (!node))
|
||||||
return shape_plan;
|
return shape_plan;
|
||||||
|
|
Loading…
Reference in New Issue