| Index: third_party/harfbuzz-ng/src/hb-shape.cc
|
| diff --git a/third_party/harfbuzz-ng/src/hb-shape.cc b/third_party/harfbuzz-ng/src/hb-shape.cc
|
| index 56c9046f83443690a223b27bf30a65877e17bcb5..4d6482362e2ebfa2233d99b876a60516424f95b0 100644
|
| --- a/third_party/harfbuzz-ng/src/hb-shape.cc
|
| +++ b/third_party/harfbuzz-ng/src/hb-shape.cc
|
| @@ -1,5 +1,6 @@
|
| /*
|
| * Copyright © 2009 Red Hat, Inc.
|
| + * Copyright © 2012 Google, Inc.
|
| *
|
| * This is part of HarfBuzz, a text shaping library.
|
| *
|
| @@ -22,117 +23,180 @@
|
| * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
| *
|
| * Red Hat Author(s): Behdad Esfahbod
|
| + * Google Author(s): Behdad Esfahbod
|
| */
|
|
|
| #include "hb-private.hh"
|
|
|
| -#include "hb-shape.h"
|
| -
|
| +#include "hb-shaper-private.hh"
|
| +#include "hb-shape-plan-private.hh"
|
| #include "hb-buffer-private.hh"
|
| +#include "hb-font-private.hh"
|
|
|
| -#ifdef HAVE_GRAPHITE
|
| -#include "hb-graphite2-private.hh"
|
| -#endif
|
| -#ifdef HAVE_UNISCRIBE
|
| -# include "hb-uniscribe-private.hh"
|
| -#endif
|
| -#ifdef HAVE_OT
|
| -# include "hb-ot-shape-private.hh"
|
| -#endif
|
| -#include "hb-fallback-shape-private.hh"
|
| -
|
| -typedef hb_bool_t (*hb_shape_func_t) (hb_font_t *font,
|
| - hb_buffer_t *buffer,
|
| - const hb_feature_t *features,
|
| - unsigned int num_features);
|
| -
|
| -#define HB_SHAPER_IMPLEMENT(name) {#name, _hb_##name##_shape}
|
| -static const struct hb_shaper_pair_t {
|
| - char name[16];
|
| - hb_shape_func_t func;
|
| -} all_shapers[] = {
|
| - /* v--- Add new shapers in the right place here */
|
| -#ifdef HAVE_GRAPHITE
|
| - HB_SHAPER_IMPLEMENT (graphite2),
|
| -#endif
|
| -#ifdef HAVE_UNISCRIBE
|
| - HB_SHAPER_IMPLEMENT (uniscribe),
|
| -#endif
|
| -#ifdef HAVE_OT
|
| - HB_SHAPER_IMPLEMENT (ot),
|
| -#endif
|
| - HB_SHAPER_IMPLEMENT (fallback) /* should be last */
|
| -};
|
| -#undef HB_SHAPER_IMPLEMENT
|
|
|
| +static void
|
| +parse_space (const char **pp, const char *end)
|
| +{
|
| + char c;
|
| +#define ISSPACE(c) ((c)==' '||(c)=='\f'||(c)=='\n'||(c)=='\r'||(c)=='\t'||(c)=='\v')
|
| + while (*pp < end && (c = **pp, ISSPACE (c)))
|
| + (*pp)++;
|
| +#undef ISSPACE
|
| +}
|
|
|
| -/* Thread-safe, lock-free, shapers */
|
| +static hb_bool_t
|
| +parse_char (const char **pp, const char *end, char c)
|
| +{
|
| + parse_space (pp, end);
|
|
|
| -static hb_shaper_pair_t *static_shapers;
|
| + if (*pp == end || **pp != c)
|
| + return false;
|
|
|
| -static
|
| -void free_static_shapers (void)
|
| + (*pp)++;
|
| + return true;
|
| +}
|
| +
|
| +static hb_bool_t
|
| +parse_uint (const char **pp, const char *end, unsigned int *pv)
|
| +{
|
| + char buf[32];
|
| + strncpy (buf, *pp, end - *pp);
|
| + buf[ARRAY_LENGTH (buf) - 1] = '\0';
|
| +
|
| + char *p = buf;
|
| + char *pend = p;
|
| + unsigned int v;
|
| +
|
| + v = strtol (p, &pend, 0);
|
| +
|
| + if (p == pend)
|
| + return false;
|
| +
|
| + *pv = v;
|
| + *pp += pend - p;
|
| + return true;
|
| +}
|
| +
|
| +static hb_bool_t
|
| +parse_feature_value_prefix (const char **pp, const char *end, hb_feature_t *feature)
|
| {
|
| - if (unlikely (static_shapers != all_shapers))
|
| - free (static_shapers);
|
| + if (parse_char (pp, end, '-'))
|
| + feature->value = 0;
|
| + else {
|
| + parse_char (pp, end, '+');
|
| + feature->value = 1;
|
| + }
|
| +
|
| + return true;
|
| }
|
|
|
| -static const hb_shaper_pair_t *
|
| -get_shapers (void)
|
| +static hb_bool_t
|
| +parse_feature_tag (const char **pp, const char *end, hb_feature_t *feature)
|
| {
|
| -retry:
|
| - hb_shaper_pair_t *shapers = (hb_shaper_pair_t *) hb_atomic_ptr_get (&static_shapers);
|
| + const char *p = *pp;
|
| + char c;
|
|
|
| - if (unlikely (!shapers))
|
| - {
|
| - char *env = getenv ("HB_SHAPER_LIST");
|
| - if (!env || !*env) {
|
| - (void) hb_atomic_ptr_cmpexch (&static_shapers, NULL, (const hb_shaper_pair_t *) all_shapers);
|
| - return (const hb_shaper_pair_t *) all_shapers;
|
| - }
|
| + parse_space (pp, end);
|
|
|
| - /* Not found; allocate one. */
|
| - shapers = (hb_shaper_pair_t *) malloc (sizeof (all_shapers));
|
| - if (unlikely (!shapers))
|
| - return (const hb_shaper_pair_t *) all_shapers;
|
| - memcpy (shapers, all_shapers, sizeof (all_shapers));
|
| -
|
| - /* Reorder shaper list to prefer requested shapers. */
|
| - unsigned int i = 0;
|
| - char *end, *p = env;
|
| - for (;;) {
|
| - end = strchr (p, ',');
|
| - if (!end)
|
| - end = p + strlen (p);
|
| -
|
| - for (unsigned int j = i; j < ARRAY_LENGTH (all_shapers); j++)
|
| - if (end - p == (int) strlen (shapers[j].name) &&
|
| - 0 == strncmp (shapers[j].name, p, end - p))
|
| - {
|
| - /* Reorder this shaper to position i */
|
| - struct hb_shaper_pair_t t = shapers[j];
|
| - memmove (&shapers[i + 1], &shapers[i], sizeof (shapers[i]) * (j - i));
|
| - shapers[i] = t;
|
| - i++;
|
| - }
|
| -
|
| - if (!*end)
|
| - break;
|
| - else
|
| - p = end + 1;
|
| - }
|
| +#define ISALNUM(c) (('a' <= (c) && (c) <= 'z') || ('A' <= (c) && (c) <= 'Z') || ('0' <= (c) && (c) <= '9'))
|
| + while (*pp < end && (c = **pp, ISALNUM(c)))
|
| + (*pp)++;
|
| +#undef ISALNUM
|
|
|
| - if (!hb_atomic_ptr_cmpexch (&static_shapers, NULL, shapers)) {
|
| - free (shapers);
|
| - goto retry;
|
| - }
|
| + if (p == *pp)
|
| + return false;
|
|
|
| -#ifdef HAVE_ATEXIT
|
| - atexit (free_static_shapers); /* First person registers atexit() callback. */
|
| -#endif
|
| + feature->tag = hb_tag_from_string (p, *pp - p);
|
| + return true;
|
| +}
|
| +
|
| +static hb_bool_t
|
| +parse_feature_indices (const char **pp, const char *end, hb_feature_t *feature)
|
| +{
|
| + parse_space (pp, end);
|
| +
|
| + hb_bool_t has_start;
|
| +
|
| + feature->start = 0;
|
| + feature->end = (unsigned int) -1;
|
| +
|
| + if (!parse_char (pp, end, '['))
|
| + return true;
|
| +
|
| + has_start = parse_uint (pp, end, &feature->start);
|
| +
|
| + if (parse_char (pp, end, ':')) {
|
| + parse_uint (pp, end, &feature->end);
|
| + } else {
|
| + if (has_start)
|
| + feature->end = feature->start + 1;
|
| }
|
|
|
| - return shapers;
|
| + return parse_char (pp, end, ']');
|
| +}
|
| +
|
| +static hb_bool_t
|
| +parse_feature_value_postfix (const char **pp, const char *end, hb_feature_t *feature)
|
| +{
|
| + return !parse_char (pp, end, '=') || parse_uint (pp, end, &feature->value);
|
| +}
|
| +
|
| +
|
| +static hb_bool_t
|
| +parse_one_feature (const char **pp, const char *end, hb_feature_t *feature)
|
| +{
|
| + return parse_feature_value_prefix (pp, end, feature) &&
|
| + parse_feature_tag (pp, end, feature) &&
|
| + parse_feature_indices (pp, end, feature) &&
|
| + parse_feature_value_postfix (pp, end, feature) &&
|
| + *pp == end;
|
| +}
|
| +
|
| +hb_bool_t
|
| +hb_feature_from_string (const char *str, int len,
|
| + hb_feature_t *feature)
|
| +{
|
| + if (len < 0)
|
| + len = strlen (str);
|
| +
|
| + return parse_one_feature (&str, str + len, feature);
|
| +}
|
| +
|
| +void
|
| +hb_feature_to_string (hb_feature_t *feature,
|
| + char *buf, unsigned int size)
|
| +{
|
| + if (unlikely (!size)) return;
|
| +
|
| + char s[128];
|
| + unsigned int len = 0;
|
| + if (feature->value == 0)
|
| + s[len++] = '-';
|
| + hb_tag_to_string (feature->tag, s + len);
|
| + len += 4;
|
| + while (len && s[len - 1] == ' ')
|
| + len--;
|
| + if (feature->start != 0 || feature->start != (unsigned int) -1)
|
| + {
|
| + s[len++] = '[';
|
| + if (feature->start)
|
| + len += snprintf (s + len, ARRAY_LENGTH (s) - len, "%d", feature->start);
|
| + if (feature->end != feature->start + 1) {
|
| + s[len++] = ':';
|
| + if (feature->end != (unsigned int) -1)
|
| + len += snprintf (s + len, ARRAY_LENGTH (s) - len, "%d", feature->end);
|
| + }
|
| + s[len++] = ']';
|
| + }
|
| + if (feature->value > 1)
|
| + {
|
| + s[len++] = '=';
|
| + len += snprintf (s + len, ARRAY_LENGTH (s) - len, "%d", feature->value);
|
| + }
|
| + assert (len < ARRAY_LENGTH (s));
|
| + len = MIN (len, size - 1);
|
| + memcpy (buf, s, len);
|
| + s[len] = '\0';
|
| }
|
|
|
|
|
| @@ -153,15 +217,15 @@ retry:
|
| if (unlikely (!shaper_list))
|
| {
|
| /* Not found; allocate one. */
|
| - shaper_list = (const char **) calloc (1 + ARRAY_LENGTH (all_shapers), sizeof (const char *));
|
| + shaper_list = (const char **) calloc (1 + HB_SHAPERS_COUNT, sizeof (const char *));
|
| if (unlikely (!shaper_list)) {
|
| static const char *nil_shaper_list[] = {NULL};
|
| return nil_shaper_list;
|
| }
|
|
|
| - const hb_shaper_pair_t *shapers = get_shapers ();
|
| + const hb_shaper_pair_t *shapers = _hb_shapers_get ();
|
| unsigned int i;
|
| - for (i = 0; i < ARRAY_LENGTH (all_shapers); i++)
|
| + for (i = 0; i < HB_SHAPERS_COUNT; i++)
|
| shaper_list[i] = shapers[i].name;
|
| shaper_list[i] = NULL;
|
|
|
| @@ -186,25 +250,20 @@ hb_shape_full (hb_font_t *font,
|
| unsigned int num_features,
|
| const char * const *shaper_list)
|
| {
|
| - hb_font_make_immutable (font); /* So we can safely cache stuff on it */
|
| + if (unlikely (!buffer->len))
|
| + return true;
|
|
|
| - if (likely (!shaper_list)) {
|
| - const hb_shaper_pair_t *shapers = get_shapers ();
|
| - for (unsigned int i = 0; i < ARRAY_LENGTH (all_shapers); i++)
|
| - if (likely (shapers[i].func (font, buffer, features, num_features)))
|
| - return true;
|
| - } else {
|
| - while (*shaper_list) {
|
| - for (unsigned int i = 0; i < ARRAY_LENGTH (all_shapers); i++)
|
| - if (0 == strcmp (*shaper_list, all_shapers[i].name)) {
|
| - if (likely (all_shapers[i].func (font, buffer, features, num_features)))
|
| - return true;
|
| - break;
|
| - }
|
| - shaper_list++;
|
| - }
|
| - }
|
| - return false;
|
| + assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE);
|
| +
|
| + buffer->guess_properties ();
|
| +
|
| + hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props, features, num_features, shaper_list);
|
| + hb_bool_t res = hb_shape_plan_execute (shape_plan, font, buffer, features, num_features);
|
| + hb_shape_plan_destroy (shape_plan);
|
| +
|
| + if (res)
|
| + buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS;
|
| + return res;
|
| }
|
|
|
| void
|
|
|