diff --git a/src/hb-ft.cc b/src/hb-ft.cc index ce68ca751..20fb32e66 100644 --- a/src/hb-ft.cc +++ b/src/hb-ft.cc @@ -398,6 +398,8 @@ hb_ft_font_create (FT_Face ft_face, } +/* Thread-safe, lock-free, FT_Library */ + static FT_Library ft_library; static diff --git a/src/hb-shape.cc b/src/hb-shape.cc index d97028e71..a8d6d0118 100644 --- a/src/hb-shape.cc +++ b/src/hb-shape.cc @@ -47,10 +47,10 @@ typedef hb_bool_t (*hb_shape_func_t) (hb_font_t *font, unsigned int num_features); #define HB_SHAPER_IMPLEMENT(name) {#name, _hb_##name##_shape} -static struct hb_shaper_pair_t { +static const struct hb_shaper_pair_t { char name[16]; hb_shape_func_t func; -} shapers[] = { +} all_shapers[] = { /* v--- Add new shapers in the right place here */ #ifdef HAVE_GRAPHITE HB_SHAPER_IMPLEMENT (graphite2), @@ -65,55 +65,120 @@ static struct hb_shaper_pair_t { }; #undef HB_SHAPER_IMPLEMENT -static struct static_shaper_list_t + +/* Thread-safe, lock-free, shapers */ + +static hb_shaper_pair_t *static_shapers; + +static +void free_static_shapers (void) { - static_shaper_list_t (void) + if (unlikely (static_shapers != all_shapers)) + free (static_shapers); +} + +static const hb_shaper_pair_t * +get_shapers (void) +{ +retry: + hb_shaper_pair_t *shapers = (hb_shaper_pair_t *) hb_atomic_ptr_get (&static_shapers); + + if (unlikely (!shapers)) { char *env = getenv ("HB_SHAPER_LIST"); - if (env && *env) - { - /* Reorder shaper list to prefer requested shaper list. */ - 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 (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; - } + if (!env || !*env) { + hb_atomic_ptr_cmpexch (&static_shapers, NULL, (const hb_shaper_pair_t *) all_shapers); + return (const hb_shaper_pair_t *) all_shapers; } - ASSERT_STATIC ((ARRAY_LENGTH (shapers) + 1) * sizeof (*shaper_list) <= sizeof (shaper_list)); - unsigned int i; - for (i = 0; i < ARRAY_LENGTH (shapers); i++) - shaper_list[i] = shapers[i].name; - shaper_list[i] = NULL; + /* 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; + } + + if (!hb_atomic_ptr_cmpexch (&static_shapers, NULL, shapers)) { + free (shapers); + goto retry; + } + +#ifdef HAVE_ATEXIT + atexit (free_static_shapers); /* First person registers atexit() callback. */ +#endif } - const char *shaper_list[ARRAY_LENGTH (shapers) + 1]; -} static_shaper_list; + return shapers; +} + + +static const char **static_shaper_list; + +static +void free_static_shaper_list (void) +{ + free (static_shaper_list); +} const char ** hb_shape_list_shapers (void) { - return static_shaper_list.shaper_list; +retry: + const char **shaper_list = (const char **) hb_atomic_ptr_get (&static_shaper_list); + + if (unlikely (!shaper_list)) + { + /* Not found; allocate one. */ + shaper_list = (const char **) calloc (1 + ARRAY_LENGTH (all_shapers), 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 (); + unsigned int i; + for (i = 0; i < ARRAY_LENGTH (all_shapers); i++) + shaper_list[i] = shapers[i].name; + shaper_list[i] = NULL; + + if (!hb_atomic_ptr_cmpexch (&static_shaper_list, NULL, shaper_list)) { + free (shaper_list); + goto retry; + } + +#ifdef HAVE_ATEXIT + atexit (free_static_shaper_list); /* First person registers atexit() callback. */ +#endif + } + + return shaper_list; } + hb_bool_t hb_shape_full (hb_font_t *font, hb_buffer_t *buffer, @@ -124,14 +189,15 @@ hb_shape_full (hb_font_t *font, hb_font_make_immutable (font); /* So we can safely cache stuff on it */ if (likely (!shaper_list)) { - for (unsigned int i = 0; i < ARRAY_LENGTH (shapers); i++) + 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 (shapers); i++) - if (0 == strcmp (*shaper_list, shapers[i].name)) { - if (likely (shapers[i].func (font, buffer, features, num_features))) + 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; }