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-shape-plan-private.hh" 28 #include "hb-shaper-private.hh" 29 #include "hb-font-private.hh" 30 #include "hb-buffer-private.hh" 31 32 #define HB_SHAPER_IMPLEMENT(shaper) \ 33 HB_SHAPER_DATA_ENSURE_DECLARE(shaper, face) \ 34 HB_SHAPER_DATA_ENSURE_DECLARE(shaper, font) 35 #include "hb-shaper-list.hh" 36 #undef HB_SHAPER_IMPLEMENT 37 38 39 static void 40 hb_shape_plan_plan (hb_shape_plan_t *shape_plan, 41 const hb_feature_t *user_features, 42 unsigned int num_user_features, 43 const char * const *shaper_list) 44 { 45 const hb_shaper_pair_t *shapers = _hb_shapers_get (); 46 47 #define HB_SHAPER_PLAN(shaper) \ 48 HB_STMT_START { \ 49 if (hb_##shaper##_shaper_face_data_ensure (shape_plan->face)) { \ 50 HB_SHAPER_DATA (shaper, shape_plan) = \ 51 HB_SHAPER_DATA_CREATE_FUNC (shaper, shape_plan) (shape_plan, user_features, num_user_features); \ 52 shape_plan->shaper_func = _hb_##shaper##_shape; \ 53 shape_plan->shaper_name = #shaper; \ 54 return; \ 55 } \ 56 } HB_STMT_END 57 58 if (likely (!shaper_list)) { 59 for (unsigned int i = 0; i < HB_SHAPERS_COUNT; i++) 60 if (0) 61 ; 62 #define HB_SHAPER_IMPLEMENT(shaper) \ 63 else if (shapers[i].func == _hb_##shaper##_shape) \ 64 HB_SHAPER_PLAN (shaper); 65 #include "hb-shaper-list.hh" 66 #undef HB_SHAPER_IMPLEMENT 67 } else { 68 for (; *shaper_list; shaper_list++) 69 if (0) 70 ; 71 #define HB_SHAPER_IMPLEMENT(shaper) \ 72 else if (0 == strcmp (*shaper_list, #shaper)) \ 73 HB_SHAPER_PLAN (shaper); 74 #include "hb-shaper-list.hh" 75 #undef HB_SHAPER_IMPLEMENT 76 } 77 78 #undef HB_SHAPER_PLAN 79 } 80 81 82 /* 83 * hb_shape_plan_t 84 */ 85 86 hb_shape_plan_t * 87 hb_shape_plan_create (hb_face_t *face, 88 const hb_segment_properties_t *props, 89 const hb_feature_t *user_features, 90 unsigned int num_user_features, 91 const char * const *shaper_list) 92 { 93 assert (props->direction != HB_DIRECTION_INVALID); 94 95 hb_shape_plan_t *shape_plan; 96 97 if (unlikely (!face)) 98 face = hb_face_get_empty (); 99 if (unlikely (!props || hb_object_is_inert (face))) 100 return hb_shape_plan_get_empty (); 101 if (!(shape_plan = hb_object_create<hb_shape_plan_t> ())) 102 return hb_shape_plan_get_empty (); 103 104 hb_face_make_immutable (face); 105 shape_plan->default_shaper_list = shaper_list == NULL; 106 shape_plan->face = hb_face_reference (face); 107 shape_plan->props = *props; 108 109 hb_shape_plan_plan (shape_plan, user_features, num_user_features, shaper_list); 110 111 return shape_plan; 112 } 113 114 hb_shape_plan_t * 115 hb_shape_plan_get_empty (void) 116 { 117 static const hb_shape_plan_t _hb_shape_plan_nil = { 118 HB_OBJECT_HEADER_STATIC, 119 120 true, /* default_shaper_list */ 121 NULL, /* face */ 122 HB_SEGMENT_PROPERTIES_DEFAULT, /* props */ 123 124 NULL, /* shaper_func */ 125 NULL, /* shaper_name */ 126 127 { 128 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID, 129 #include "hb-shaper-list.hh" 130 #undef HB_SHAPER_IMPLEMENT 131 } 132 }; 133 134 return const_cast<hb_shape_plan_t *> (&_hb_shape_plan_nil); 135 } 136 137 hb_shape_plan_t * 138 hb_shape_plan_reference (hb_shape_plan_t *shape_plan) 139 { 140 return hb_object_reference (shape_plan); 141 } 142 143 void 144 hb_shape_plan_destroy (hb_shape_plan_t *shape_plan) 145 { 146 if (!hb_object_destroy (shape_plan)) return; 147 148 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, shape_plan); 149 #include "hb-shaper-list.hh" 150 #undef HB_SHAPER_IMPLEMENT 151 152 hb_face_destroy (shape_plan->face); 153 154 free (shape_plan); 155 } 156 157 hb_bool_t 158 hb_shape_plan_set_user_data (hb_shape_plan_t *shape_plan, 159 hb_user_data_key_t *key, 160 void * data, 161 hb_destroy_func_t destroy, 162 hb_bool_t replace) 163 { 164 return hb_object_set_user_data (shape_plan, key, data, destroy, replace); 165 } 166 167 void * 168 hb_shape_plan_get_user_data (hb_shape_plan_t *shape_plan, 169 hb_user_data_key_t *key) 170 { 171 return hb_object_get_user_data (shape_plan, key); 172 } 173 174 175 hb_bool_t 176 hb_shape_plan_execute (hb_shape_plan_t *shape_plan, 177 hb_font_t *font, 178 hb_buffer_t *buffer, 179 const hb_feature_t *features, 180 unsigned int num_features) 181 { 182 if (unlikely (hb_object_is_inert (shape_plan) || 183 hb_object_is_inert (font) || 184 hb_object_is_inert (buffer))) 185 return false; 186 187 assert (shape_plan->face == font->face); 188 assert (hb_segment_properties_equal (&shape_plan->props, &buffer->props)); 189 190 #define HB_SHAPER_EXECUTE(shaper) \ 191 HB_STMT_START { \ 192 return HB_SHAPER_DATA (shaper, shape_plan) && \ 193 hb_##shaper##_shaper_font_data_ensure (font) && \ 194 _hb_##shaper##_shape (shape_plan, font, buffer, features, num_features); \ 195 } HB_STMT_END 196 197 if (0) 198 ; 199 #define HB_SHAPER_IMPLEMENT(shaper) \ 200 else if (shape_plan->shaper_func == _hb_##shaper##_shape) \ 201 HB_SHAPER_EXECUTE (shaper); 202 #include "hb-shaper-list.hh" 203 #undef HB_SHAPER_IMPLEMENT 204 205 #undef HB_SHAPER_EXECUTE 206 207 return false; 208 } 209 210 211 /* 212 * caching 213 */ 214 215 #if 0 216 static unsigned int 217 hb_shape_plan_hash (const hb_shape_plan_t *shape_plan) 218 { 219 return hb_segment_properties_hash (&shape_plan->props) + 220 shape_plan->default_shaper_list ? 0 : (intptr_t) shape_plan->shaper_func; 221 } 222 #endif 223 224 /* TODO no user-feature caching for now. */ 225 struct hb_shape_plan_proposal_t 226 { 227 const hb_segment_properties_t props; 228 const char * const *shaper_list; 229 hb_shape_func_t *shaper_func; 230 }; 231 232 static hb_bool_t 233 hb_shape_plan_matches (const hb_shape_plan_t *shape_plan, 234 const hb_shape_plan_proposal_t *proposal) 235 { 236 return hb_segment_properties_equal (&shape_plan->props, &proposal->props) && 237 ((shape_plan->default_shaper_list && proposal->shaper_list == NULL) || 238 (shape_plan->shaper_func == proposal->shaper_func)); 239 } 240 241 hb_shape_plan_t * 242 hb_shape_plan_create_cached (hb_face_t *face, 243 const hb_segment_properties_t *props, 244 const hb_feature_t *user_features, 245 unsigned int num_user_features, 246 const char * const *shaper_list) 247 { 248 if (num_user_features) 249 return hb_shape_plan_create (face, props, user_features, num_user_features, shaper_list); 250 251 hb_shape_plan_proposal_t proposal = { 252 *props, 253 shaper_list, 254 NULL 255 }; 256 257 if (shaper_list) { 258 /* Choose shaper. Adapted from hb_shape_plan_plan(). */ 259 #define HB_SHAPER_PLAN(shaper) \ 260 HB_STMT_START { \ 261 if (hb_##shaper##_shaper_face_data_ensure (face)) \ 262 proposal.shaper_func = _hb_##shaper##_shape; \ 263 } HB_STMT_END 264 265 for (const char * const *shaper_item = shaper_list; *shaper_item; shaper_item++) 266 if (0) 267 ; 268 #define HB_SHAPER_IMPLEMENT(shaper) \ 269 else if (0 == strcmp (*shaper_item, #shaper)) \ 270 HB_SHAPER_PLAN (shaper); 271 #include "hb-shaper-list.hh" 272 #undef HB_SHAPER_IMPLEMENT 273 274 #undef HB_SHAPER_PLAN 275 276 if (unlikely (!proposal.shaper_list)) 277 return hb_shape_plan_get_empty (); 278 } 279 280 281 retry: 282 hb_face_t::plan_node_t *cached_plan_nodes = (hb_face_t::plan_node_t *) hb_atomic_ptr_get (&face->shape_plans); 283 for (hb_face_t::plan_node_t *node = cached_plan_nodes; node; node = node->next) 284 if (hb_shape_plan_matches (node->shape_plan, &proposal)) 285 return hb_shape_plan_reference (node->shape_plan); 286 287 /* Not found. */ 288 289 hb_shape_plan_t *shape_plan = hb_shape_plan_create (face, props, user_features, num_user_features, shaper_list); 290 291 hb_face_t::plan_node_t *node = (hb_face_t::plan_node_t *) calloc (1, sizeof (hb_face_t::plan_node_t)); 292 if (unlikely (!node)) 293 return shape_plan; 294 295 node->shape_plan = shape_plan; 296 node->next = cached_plan_nodes; 297 298 if (!hb_atomic_ptr_cmpexch (&face->shape_plans, cached_plan_nodes, node)) { 299 hb_shape_plan_destroy (shape_plan); 300 free (node); 301 goto retry; 302 } 303 304 /* Release our reference on face. */ 305 hb_face_destroy (face); 306 307 return hb_shape_plan_reference (shape_plan); 308 } 309 310 const char * 311 hb_shape_plan_get_shaper (hb_shape_plan_t *shape_plan) 312 { 313 return shape_plan->shaper_name; 314 } 315