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 |