1 | /* |
2 | * Copyright © 2012 Google, Inc. |
3 | * |
4 | * This is part of HarfBuzz, a text shaping library. |
5 | * |
6 | * Permission is hereby granted, without written agreement and without |
7 | * license or royalty fees, to use, copy, modify, and distribute this |
8 | * software and its documentation for any purpose, provided that the |
9 | * above copyright notice and the following two paragraphs appear in |
10 | * all copies of this software. |
11 | * |
12 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR |
13 | * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
14 | * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN |
15 | * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
16 | * DAMAGE. |
17 | * |
18 | * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, |
19 | * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
20 | * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS |
21 | * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO |
22 | * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
23 | * |
24 | * Google Author(s): Behdad Esfahbod |
25 | */ |
26 | |
27 | #include "hb-private.hh" |
28 | #include "hb-shaper-private.hh" |
29 | #include "hb-atomic-private.hh" |
30 | |
31 | |
32 | static const hb_shaper_pair_t all_shapers[] = { |
33 | #define HB_SHAPER_IMPLEMENT(name) {#name, _hb_##name##_shape}, |
34 | #include "hb-shaper-list.hh" |
35 | #undef HB_SHAPER_IMPLEMENT |
36 | }; |
37 | |
38 | |
39 | /* Thread-safe, lock-free, shapers */ |
40 | |
41 | static const hb_shaper_pair_t *static_shapers; |
42 | |
43 | #ifdef HB_USE_ATEXIT |
44 | static |
45 | void free_static_shapers (void) |
46 | { |
47 | if (unlikely (static_shapers != all_shapers)) |
48 | free (ptr: (void *) static_shapers); |
49 | } |
50 | #endif |
51 | |
52 | const hb_shaper_pair_t * |
53 | _hb_shapers_get (void) |
54 | { |
55 | retry: |
56 | hb_shaper_pair_t *shapers = (hb_shaper_pair_t *) hb_atomic_ptr_get (&static_shapers); |
57 | |
58 | if (unlikely (!shapers)) |
59 | { |
60 | char *env = getenv (name: "HB_SHAPER_LIST" ); |
61 | if (!env || !*env) { |
62 | (void) hb_atomic_ptr_cmpexch (&static_shapers, nullptr, &all_shapers[0]); |
63 | return (const hb_shaper_pair_t *) all_shapers; |
64 | } |
65 | |
66 | /* Not found; allocate one. */ |
67 | shapers = (hb_shaper_pair_t *) calloc (nmemb: 1, size: sizeof (all_shapers)); |
68 | if (unlikely (!shapers)) { |
69 | (void) hb_atomic_ptr_cmpexch (&static_shapers, nullptr, &all_shapers[0]); |
70 | return (const hb_shaper_pair_t *) all_shapers; |
71 | } |
72 | |
73 | memcpy (dest: shapers, src: all_shapers, n: sizeof (all_shapers)); |
74 | |
75 | /* Reorder shaper list to prefer requested shapers. */ |
76 | unsigned int i = 0; |
77 | char *end, *p = env; |
78 | for (;;) { |
79 | end = strchr (s: p, c: ','); |
80 | if (!end) |
81 | end = p + strlen (s: p); |
82 | |
83 | for (unsigned int j = i; j < ARRAY_LENGTH (all_shapers); j++) |
84 | if (end - p == (int) strlen (s: shapers[j].name) && |
85 | 0 == strncmp (s1: shapers[j].name, s2: p, n: end - p)) |
86 | { |
87 | /* Reorder this shaper to position i */ |
88 | struct hb_shaper_pair_t t = shapers[j]; |
89 | memmove (dest: &shapers[i + 1], src: &shapers[i], n: sizeof (shapers[i]) * (j - i)); |
90 | shapers[i] = t; |
91 | i++; |
92 | } |
93 | |
94 | if (!*end) |
95 | break; |
96 | else |
97 | p = end + 1; |
98 | } |
99 | |
100 | if (!hb_atomic_ptr_cmpexch (&static_shapers, nullptr, shapers)) { |
101 | free (ptr: shapers); |
102 | goto retry; |
103 | } |
104 | |
105 | #ifdef HB_USE_ATEXIT |
106 | atexit (func: free_static_shapers); /* First person registers atexit() callback. */ |
107 | #endif |
108 | } |
109 | |
110 | return shapers; |
111 | } |
112 | |