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