hb-shape.cc revision f64b2ebf82c5f355cd95806478cd30c00b1a2731
1/* 2 * Copyright © 2009 Red Hat, 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 * Red Hat Author(s): Behdad Esfahbod 25 */ 26 27#include "hb-private.hh" 28 29#include "hb-shape.h" 30 31#include "hb-buffer-private.hh" 32 33#ifdef HAVE_GRAPHITE 34#include "hb-graphite2-private.hh" 35#endif 36#ifdef HAVE_UNISCRIBE 37# include "hb-uniscribe-private.hh" 38#endif 39#ifdef HAVE_OT 40# include "hb-ot-shape-private.hh" 41#endif 42#include "hb-fallback-shape-private.hh" 43 44typedef hb_bool_t (*hb_shape_func_t) (hb_font_t *font, 45 hb_buffer_t *buffer, 46 const hb_feature_t *features, 47 unsigned int num_features); 48 49#define HB_SHAPER_IMPLEMENT(name) {#name, _hb_##name##_shape} 50static const struct hb_shaper_pair_t { 51 char name[16]; 52 hb_shape_func_t func; 53} all_shapers[] = { 54 /* v--- Add new shapers in the right place here */ 55#ifdef HAVE_GRAPHITE 56 HB_SHAPER_IMPLEMENT (graphite2), 57#endif 58#ifdef HAVE_UNISCRIBE 59 HB_SHAPER_IMPLEMENT (uniscribe), 60#endif 61#ifdef HAVE_OT 62 HB_SHAPER_IMPLEMENT (ot), 63#endif 64 HB_SHAPER_IMPLEMENT (fallback) /* should be last */ 65}; 66#undef HB_SHAPER_IMPLEMENT 67 68 69/* Thread-safe, lock-free, shapers */ 70 71static hb_shaper_pair_t *static_shapers; 72 73static 74void free_static_shapers (void) 75{ 76 if (unlikely (static_shapers != all_shapers)) 77 free (static_shapers); 78} 79 80static const hb_shaper_pair_t * 81get_shapers (void) 82{ 83retry: 84 hb_shaper_pair_t *shapers = (hb_shaper_pair_t *) hb_atomic_ptr_get (&static_shapers); 85 86 if (unlikely (!shapers)) 87 { 88 char *env = getenv ("HB_SHAPER_LIST"); 89 if (!env || !*env) { 90 hb_atomic_ptr_cmpexch (&static_shapers, NULL, (const hb_shaper_pair_t *) all_shapers); 91 return (const hb_shaper_pair_t *) all_shapers; 92 } 93 94 /* Not found; allocate one. */ 95 shapers = (hb_shaper_pair_t *) malloc (sizeof (all_shapers)); 96 if (unlikely (!shapers)) 97 return (const hb_shaper_pair_t *) all_shapers; 98 memcpy (shapers, all_shapers, sizeof (all_shapers)); 99 100 /* Reorder shaper list to prefer requested shapers. */ 101 unsigned int i = 0; 102 char *end, *p = env; 103 for (;;) { 104 end = strchr (p, ','); 105 if (!end) 106 end = p + strlen (p); 107 108 for (unsigned int j = i; j < ARRAY_LENGTH (all_shapers); j++) 109 if (end - p == (int) strlen (shapers[j].name) && 110 0 == strncmp (shapers[j].name, p, end - p)) 111 { 112 /* Reorder this shaper to position i */ 113 struct hb_shaper_pair_t t = shapers[j]; 114 memmove (&shapers[i + 1], &shapers[i], sizeof (shapers[i]) * (j - i)); 115 shapers[i] = t; 116 i++; 117 } 118 119 if (!*end) 120 break; 121 else 122 p = end + 1; 123 } 124 125 if (!hb_atomic_ptr_cmpexch (&static_shapers, NULL, shapers)) { 126 free (shapers); 127 goto retry; 128 } 129 130#ifdef HAVE_ATEXIT 131 atexit (free_static_shapers); /* First person registers atexit() callback. */ 132#endif 133 } 134 135 return shapers; 136} 137 138 139static const char **static_shaper_list; 140 141static 142void free_static_shaper_list (void) 143{ 144 free (static_shaper_list); 145} 146 147const char ** 148hb_shape_list_shapers (void) 149{ 150retry: 151 const char **shaper_list = (const char **) hb_atomic_ptr_get (&static_shaper_list); 152 153 if (unlikely (!shaper_list)) 154 { 155 /* Not found; allocate one. */ 156 shaper_list = (const char **) calloc (1 + ARRAY_LENGTH (all_shapers), sizeof (const char *)); 157 if (unlikely (!shaper_list)) { 158 static const char *nil_shaper_list[] = {NULL}; 159 return nil_shaper_list; 160 } 161 162 const hb_shaper_pair_t *shapers = get_shapers (); 163 unsigned int i; 164 for (i = 0; i < ARRAY_LENGTH (all_shapers); i++) 165 shaper_list[i] = shapers[i].name; 166 shaper_list[i] = NULL; 167 168 if (!hb_atomic_ptr_cmpexch (&static_shaper_list, NULL, shaper_list)) { 169 free (shaper_list); 170 goto retry; 171 } 172 173#ifdef HAVE_ATEXIT 174 atexit (free_static_shaper_list); /* First person registers atexit() callback. */ 175#endif 176 } 177 178 return shaper_list; 179} 180 181 182hb_bool_t 183hb_shape_full (hb_font_t *font, 184 hb_buffer_t *buffer, 185 const hb_feature_t *features, 186 unsigned int num_features, 187 const char * const *shaper_list) 188{ 189 hb_font_make_immutable (font); /* So we can safely cache stuff on it */ 190 191 if (likely (!shaper_list)) { 192 const hb_shaper_pair_t *shapers = get_shapers (); 193 for (unsigned int i = 0; i < ARRAY_LENGTH (all_shapers); i++) 194 if (likely (shapers[i].func (font, buffer, features, num_features))) 195 return TRUE; 196 } else { 197 while (*shaper_list) { 198 for (unsigned int i = 0; i < ARRAY_LENGTH (all_shapers); i++) 199 if (0 == strcmp (*shaper_list, all_shapers[i].name)) { 200 if (likely (all_shapers[i].func (font, buffer, features, num_features))) 201 return TRUE; 202 break; 203 } 204 shaper_list++; 205 } 206 } 207 return FALSE; 208} 209 210void 211hb_shape (hb_font_t *font, 212 hb_buffer_t *buffer, 213 const hb_feature_t *features, 214 unsigned int num_features) 215{ 216 hb_shape_full (font, buffer, features, num_features, NULL); 217} 218