< prev index next >

src/java.desktop/share/native/libfontmanager/harfbuzz/hb-shape-plan.cc

Print this page




  29 #include "hb-font-private.hh"
  30 #include "hb-buffer-private.hh"
  31 
  32 
  33 #ifndef HB_DEBUG_SHAPE_PLAN
  34 #define HB_DEBUG_SHAPE_PLAN (HB_DEBUG+0)
  35 #endif
  36 
  37 
  38 #define HB_SHAPER_IMPLEMENT(shaper) \
  39         HB_SHAPER_DATA_ENSURE_DECLARE(shaper, face) \
  40         HB_SHAPER_DATA_ENSURE_DECLARE(shaper, font)
  41 #include "hb-shaper-list.hh"
  42 #undef HB_SHAPER_IMPLEMENT
  43 
  44 
  45 static void
  46 hb_shape_plan_plan (hb_shape_plan_t    *shape_plan,
  47                     const hb_feature_t *user_features,
  48                     unsigned int        num_user_features,


  49                     const char * const *shaper_list)
  50 {
  51   DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan,
  52                   "num_features=%d shaper_list=%p",
  53                   num_user_features,

  54                   shaper_list);
  55 
  56   const hb_shaper_pair_t *shapers = _hb_shapers_get ();
  57 
  58 #define HB_SHAPER_PLAN(shaper) \
  59         HB_STMT_START { \
  60           if (hb_##shaper##_shaper_face_data_ensure (shape_plan->face_unsafe)) { \
  61             HB_SHAPER_DATA (shaper, shape_plan) = \
  62               HB_SHAPER_DATA_CREATE_FUNC (shaper, shape_plan) (shape_plan, user_features, num_user_features); \


  63             shape_plan->shaper_func = _hb_##shaper##_shape; \
  64             shape_plan->shaper_name = #shaper; \
  65             return; \
  66           } \
  67         } HB_STMT_END
  68 
  69   if (likely (!shaper_list)) {
  70     for (unsigned int i = 0; i < HB_SHAPERS_COUNT; i++)
  71       if (0)
  72         ;
  73 #define HB_SHAPER_IMPLEMENT(shaper) \
  74       else if (shapers[i].func == _hb_##shaper##_shape) \
  75         HB_SHAPER_PLAN (shaper);
  76 #include "hb-shaper-list.hh"
  77 #undef HB_SHAPER_IMPLEMENT
  78   } else {
  79     for (; *shaper_list; shaper_list++)
  80       if (0)
  81         ;
  82 #define HB_SHAPER_IMPLEMENT(shaper) \


  98  * hb_shape_plan_create: (Xconstructor)
  99  * @face:
 100  * @props:
 101  * @user_features: (array length=num_user_features):
 102  * @num_user_features:
 103  * @shaper_list: (array zero-terminated=1):
 104  *
 105  *
 106  *
 107  * Return value: (transfer full):
 108  *
 109  * Since: 0.9.7
 110  **/
 111 hb_shape_plan_t *
 112 hb_shape_plan_create (hb_face_t                     *face,
 113                       const hb_segment_properties_t *props,
 114                       const hb_feature_t            *user_features,
 115                       unsigned int                   num_user_features,
 116                       const char * const            *shaper_list)
 117 {















 118   DEBUG_MSG_FUNC (SHAPE_PLAN, NULL,
 119                   "face=%p num_features=%d shaper_list=%p",
 120                   face,
 121                   num_user_features,

 122                   shaper_list);
 123 
 124   hb_shape_plan_t *shape_plan;
 125   hb_feature_t *features = NULL;

 126 
 127   if (unlikely (!face))
 128     face = hb_face_get_empty ();
 129   if (unlikely (!props))
 130     return hb_shape_plan_get_empty ();
 131   if (num_user_features && !(features = (hb_feature_t *) calloc (num_user_features, sizeof (hb_feature_t))))
 132     return hb_shape_plan_get_empty ();
 133   if (!(shape_plan = hb_object_create<hb_shape_plan_t> ())) {







 134     free (features);
 135     return hb_shape_plan_get_empty ();
 136   }
 137 
 138   assert (props->direction != HB_DIRECTION_INVALID);
 139 
 140   hb_face_make_immutable (face);
 141   shape_plan->default_shaper_list = shaper_list == NULL;
 142   shape_plan->face_unsafe = face;
 143   shape_plan->props = *props;
 144   shape_plan->num_user_features = num_user_features;
 145   shape_plan->user_features = features;
 146   if (num_user_features)
 147     memcpy (features, user_features, num_user_features * sizeof (hb_feature_t));
 148 
 149   hb_shape_plan_plan (shape_plan, user_features, num_user_features, shaper_list);







 150 
 151   return shape_plan;
 152 }
 153 
 154 /**
 155  * hb_shape_plan_get_empty:
 156  *
 157  *
 158  *
 159  * Return value: (transfer full):
 160  *
 161  * Since: 0.9.7
 162  **/
 163 hb_shape_plan_t *
 164 hb_shape_plan_get_empty (void)
 165 {
 166   static const hb_shape_plan_t _hb_shape_plan_nil = {
 167     HB_OBJECT_HEADER_STATIC,
 168 
 169     true, /* default_shaper_list */
 170     NULL, /* face */
 171     HB_SEGMENT_PROPERTIES_DEFAULT, /* props */
 172 
 173     NULL, /* shaper_func */
 174     NULL, /* shaper_name */
 175 
 176     NULL, /* user_features */
 177     0,    /* num_user_featurs */
 178 



 179     {
 180 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
 181 #include "hb-shaper-list.hh"
 182 #undef HB_SHAPER_IMPLEMENT
 183     }
 184   };
 185 
 186   return const_cast<hb_shape_plan_t *> (&_hb_shape_plan_nil);
 187 }
 188 
 189 /**
 190  * hb_shape_plan_reference: (skip)
 191  * @shape_plan: a shape plan.
 192  *
 193  *
 194  *
 195  * Return value: (transfer full):
 196  *
 197  * Since: 0.9.7
 198  **/


 203 }
 204 
 205 /**
 206  * hb_shape_plan_destroy: (skip)
 207  * @shape_plan: a shape plan.
 208  *
 209  *
 210  *
 211  * Since: 0.9.7
 212  **/
 213 void
 214 hb_shape_plan_destroy (hb_shape_plan_t *shape_plan)
 215 {
 216   if (!hb_object_destroy (shape_plan)) return;
 217 
 218 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, shape_plan);
 219 #include "hb-shaper-list.hh"
 220 #undef HB_SHAPER_IMPLEMENT
 221 
 222   free (shape_plan->user_features);

 223 
 224   free (shape_plan);
 225 }
 226 
 227 /**
 228  * hb_shape_plan_set_user_data: (skip)
 229  * @shape_plan: a shape plan.
 230  * @key:
 231  * @data:
 232  * @destroy:
 233  * @replace:
 234  *
 235  *
 236  *
 237  * Return value:
 238  *
 239  * Since: 0.9.7
 240  **/
 241 hb_bool_t
 242 hb_shape_plan_set_user_data (hb_shape_plan_t    *shape_plan,


 272  * @shape_plan: a shape plan.
 273  * @font: a font.
 274  * @buffer: a buffer.
 275  * @features: (array length=num_features):
 276  * @num_features:
 277  *
 278  *
 279  *
 280  * Return value:
 281  *
 282  * Since: 0.9.7
 283  **/
 284 hb_bool_t
 285 hb_shape_plan_execute (hb_shape_plan_t    *shape_plan,
 286                        hb_font_t          *font,
 287                        hb_buffer_t        *buffer,
 288                        const hb_feature_t *features,
 289                        unsigned int        num_features)
 290 {
 291   DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan,
 292                   "num_features=%d shaper_func=%p",
 293                   num_features,
 294                   shape_plan->shaper_func);

 295 
 296   if (unlikely (!buffer->len))
 297     return true;
 298 
 299   assert (!hb_object_is_inert (buffer));
 300   assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE);
 301 
 302   if (unlikely (hb_object_is_inert (shape_plan)))
 303     return false;
 304 
 305   assert (shape_plan->face_unsafe == font->face);
 306   assert (hb_segment_properties_equal (&shape_plan->props, &buffer->props));
 307 
 308 #define HB_SHAPER_EXECUTE(shaper) \
 309         HB_STMT_START { \
 310           return HB_SHAPER_DATA (shaper, shape_plan) && \
 311                  hb_##shaper##_shaper_font_data_ensure (font) && \
 312                  _hb_##shaper##_shape (shape_plan, font, buffer, features, num_features); \
 313         } HB_STMT_END
 314 


 333 #if 0
 334 static unsigned int
 335 hb_shape_plan_hash (const hb_shape_plan_t *shape_plan)
 336 {
 337   return hb_segment_properties_hash (&shape_plan->props) +
 338          shape_plan->default_shaper_list ? 0 : (intptr_t) shape_plan->shaper_func;
 339 }
 340 #endif
 341 
 342 /* User-feature caching is currently somewhat dumb:
 343  * it only finds matches where the feature array is identical,
 344  * not cases where the feature lists would be compatible for plan purposes
 345  * but have different ranges, for example.
 346  */
 347 struct hb_shape_plan_proposal_t
 348 {
 349   const hb_segment_properties_t  props;
 350   const char * const            *shaper_list;
 351   const hb_feature_t            *user_features;
 352   unsigned int                   num_user_features;


 353   hb_shape_func_t               *shaper_func;
 354 };
 355 
 356 static inline hb_bool_t
 357 hb_shape_plan_user_features_match (const hb_shape_plan_t          *shape_plan,
 358                                    const hb_shape_plan_proposal_t *proposal)
 359 {
 360   if (proposal->num_user_features != shape_plan->num_user_features) return false;

 361   for (unsigned int i = 0, n = proposal->num_user_features; i < n; i++)
 362     if (proposal->user_features[i].tag   != shape_plan->user_features[i].tag   ||
 363         proposal->user_features[i].value != shape_plan->user_features[i].value ||
 364         proposal->user_features[i].start != shape_plan->user_features[i].start ||
 365         proposal->user_features[i].end   != shape_plan->user_features[i].end) return false;













 366   return true;
 367 }
 368 
 369 static hb_bool_t
 370 hb_shape_plan_matches (const hb_shape_plan_t          *shape_plan,
 371                        const hb_shape_plan_proposal_t *proposal)
 372 {
 373   return hb_segment_properties_equal (&shape_plan->props, &proposal->props) &&
 374          hb_shape_plan_user_features_match (shape_plan, proposal) &&

 375          ((shape_plan->default_shaper_list && proposal->shaper_list == NULL) ||
 376           (shape_plan->shaper_func == proposal->shaper_func));
 377 }
 378 
 379 static inline hb_bool_t
 380 hb_non_global_user_features_present (const hb_feature_t *user_features,
 381                                      unsigned int        num_user_features)
 382 {
 383   while (num_user_features)
 384     if (user_features->start != 0 || user_features->end != (unsigned int) -1)
 385       return true;
 386     else
 387       num_user_features--, user_features++;
 388   return false;
 389 }
 390 







 391 /**
 392  * hb_shape_plan_create_cached:
 393  * @face:
 394  * @props:
 395  * @user_features: (array length=num_user_features):
 396  * @num_user_features:
 397  * @shaper_list: (array zero-terminated=1):
 398  *
 399  *
 400  *
 401  * Return value: (transfer full):
 402  *
 403  * Since: 0.9.7
 404  **/
 405 hb_shape_plan_t *
 406 hb_shape_plan_create_cached (hb_face_t                     *face,
 407                              const hb_segment_properties_t *props,
 408                              const hb_feature_t            *user_features,
 409                              unsigned int                   num_user_features,
 410                              const char * const            *shaper_list)
 411 {















 412   DEBUG_MSG_FUNC (SHAPE_PLAN, NULL,
 413                   "face=%p num_features=%d shaper_list=%p",
 414                   face,
 415                   num_user_features,
 416                   shaper_list);
 417 
 418   hb_shape_plan_proposal_t proposal = {
 419     *props,
 420     shaper_list,
 421     user_features,
 422     num_user_features,
 423     NULL
 424   };
 425 
 426   if (shaper_list) {
 427     /* Choose shaper.  Adapted from hb_shape_plan_plan().
 428      * Must choose shaper exactly the same way as that function. */
 429     for (const char * const *shaper_item = shaper_list; *shaper_item; shaper_item++)
 430       if (0)
 431         ;


 438       }
 439 #include "hb-shaper-list.hh"
 440 #undef HB_SHAPER_IMPLEMENT
 441 
 442     if (unlikely (!proposal.shaper_func))
 443       return hb_shape_plan_get_empty ();
 444   }
 445 
 446 
 447 retry:
 448   hb_face_t::plan_node_t *cached_plan_nodes = (hb_face_t::plan_node_t *) hb_atomic_ptr_get (&face->shape_plans);
 449   for (hb_face_t::plan_node_t *node = cached_plan_nodes; node; node = node->next)
 450     if (hb_shape_plan_matches (node->shape_plan, &proposal))
 451     {
 452       DEBUG_MSG_FUNC (SHAPE_PLAN, node->shape_plan, "fulfilled from cache");
 453       return hb_shape_plan_reference (node->shape_plan);
 454     }
 455 
 456   /* Not found. */
 457 
 458   hb_shape_plan_t *shape_plan = hb_shape_plan_create (face, props, user_features, num_user_features, shaper_list);



 459 
 460   /* Don't add to the cache if face is inert. */
 461   if (unlikely (hb_object_is_inert (face)))
 462     return shape_plan;
 463 
 464   /* Don't add the plan to the cache if there were user features with non-global ranges */
 465 
 466   if (hb_non_global_user_features_present (user_features, num_user_features))
 467     return shape_plan;



 468 
 469   hb_face_t::plan_node_t *node = (hb_face_t::plan_node_t *) calloc (1, sizeof (hb_face_t::plan_node_t));
 470   if (unlikely (!node))
 471     return shape_plan;
 472 
 473   node->shape_plan = shape_plan;
 474   node->next = cached_plan_nodes;
 475 
 476   if (!hb_atomic_ptr_cmpexch (&face->shape_plans, cached_plan_nodes, node)) {
 477     hb_shape_plan_destroy (shape_plan);
 478     free (node);
 479     goto retry;
 480   }
 481   DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan, "inserted into cache");
 482 
 483   return hb_shape_plan_reference (shape_plan);
 484 }
 485 
 486 /**
 487  * hb_shape_plan_get_shaper:


  29 #include "hb-font-private.hh"
  30 #include "hb-buffer-private.hh"
  31 
  32 
  33 #ifndef HB_DEBUG_SHAPE_PLAN
  34 #define HB_DEBUG_SHAPE_PLAN (HB_DEBUG+0)
  35 #endif
  36 
  37 
  38 #define HB_SHAPER_IMPLEMENT(shaper) \
  39         HB_SHAPER_DATA_ENSURE_DECLARE(shaper, face) \
  40         HB_SHAPER_DATA_ENSURE_DECLARE(shaper, font)
  41 #include "hb-shaper-list.hh"
  42 #undef HB_SHAPER_IMPLEMENT
  43 
  44 
  45 static void
  46 hb_shape_plan_plan (hb_shape_plan_t    *shape_plan,
  47                     const hb_feature_t *user_features,
  48                     unsigned int        num_user_features,
  49                     const int          *coords,
  50                     unsigned int        num_coords,
  51                     const char * const *shaper_list)
  52 {
  53   DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan,
  54                   "num_features=%d num_coords=%d shaper_list=%p",
  55                   num_user_features,
  56                   num_coords,
  57                   shaper_list);
  58 
  59   const hb_shaper_pair_t *shapers = _hb_shapers_get ();
  60 
  61 #define HB_SHAPER_PLAN(shaper) \
  62         HB_STMT_START { \
  63           if (hb_##shaper##_shaper_face_data_ensure (shape_plan->face_unsafe)) { \
  64             HB_SHAPER_DATA (shaper, shape_plan) = \
  65               HB_SHAPER_DATA_CREATE_FUNC (shaper, shape_plan) (shape_plan, \
  66                                                                user_features, num_user_features, \
  67                                                                coords, num_coords); \
  68             shape_plan->shaper_func = _hb_##shaper##_shape; \
  69             shape_plan->shaper_name = #shaper; \
  70             return; \
  71           } \
  72         } HB_STMT_END
  73 
  74   if (likely (!shaper_list)) {
  75     for (unsigned int i = 0; i < HB_SHAPERS_COUNT; i++)
  76       if (0)
  77         ;
  78 #define HB_SHAPER_IMPLEMENT(shaper) \
  79       else if (shapers[i].func == _hb_##shaper##_shape) \
  80         HB_SHAPER_PLAN (shaper);
  81 #include "hb-shaper-list.hh"
  82 #undef HB_SHAPER_IMPLEMENT
  83   } else {
  84     for (; *shaper_list; shaper_list++)
  85       if (0)
  86         ;
  87 #define HB_SHAPER_IMPLEMENT(shaper) \


 103  * hb_shape_plan_create: (Xconstructor)
 104  * @face: 
 105  * @props: 
 106  * @user_features: (array length=num_user_features):
 107  * @num_user_features: 
 108  * @shaper_list: (array zero-terminated=1):
 109  *
 110  * 
 111  *
 112  * Return value: (transfer full):
 113  *
 114  * Since: 0.9.7
 115  **/
 116 hb_shape_plan_t *
 117 hb_shape_plan_create (hb_face_t                     *face,
 118                       const hb_segment_properties_t *props,
 119                       const hb_feature_t            *user_features,
 120                       unsigned int                   num_user_features,
 121                       const char * const            *shaper_list)
 122 {
 123   return hb_shape_plan_create2 (face, props,
 124                                 user_features, num_user_features,
 125                                 NULL, 0,
 126                                 shaper_list);
 127 }
 128 
 129 hb_shape_plan_t *
 130 hb_shape_plan_create2 (hb_face_t                     *face,
 131                        const hb_segment_properties_t *props,
 132                        const hb_feature_t            *user_features,
 133                        unsigned int                   num_user_features,
 134                        const int                     *orig_coords,
 135                        unsigned int                   num_coords,
 136                        const char * const            *shaper_list)
 137 {
 138   DEBUG_MSG_FUNC (SHAPE_PLAN, NULL,
 139                   "face=%p num_features=%d num_coords=%d shaper_list=%p",
 140                   face,
 141                   num_user_features,
 142                   num_coords,
 143                   shaper_list);
 144 
 145   hb_shape_plan_t *shape_plan;
 146   hb_feature_t *features = NULL;
 147   int *coords = NULL;
 148 
 149   if (unlikely (!face))
 150     face = hb_face_get_empty ();
 151   if (unlikely (!props))
 152     return hb_shape_plan_get_empty ();
 153   if (num_user_features && !(features = (hb_feature_t *) calloc (num_user_features, sizeof (hb_feature_t))))
 154     return hb_shape_plan_get_empty ();
 155   if (num_coords && !(coords = (int *) calloc (num_coords, sizeof (int))))
 156   {
 157     free (features);
 158     return hb_shape_plan_get_empty ();
 159   }
 160   if (!(shape_plan = hb_object_create<hb_shape_plan_t> ()))
 161   {
 162     free (coords);
 163     free (features);
 164     return hb_shape_plan_get_empty ();
 165   }
 166 
 167   assert (props->direction != HB_DIRECTION_INVALID);
 168 
 169   hb_face_make_immutable (face);
 170   shape_plan->default_shaper_list = shaper_list == NULL;
 171   shape_plan->face_unsafe = face;
 172   shape_plan->props = *props;
 173   shape_plan->num_user_features = num_user_features;
 174   shape_plan->user_features = features;
 175   if (num_user_features)
 176     memcpy (features, user_features, num_user_features * sizeof (hb_feature_t));
 177   shape_plan->num_coords = num_coords;
 178   shape_plan->coords = coords;
 179   if (num_coords)
 180     memcpy (coords, orig_coords, num_coords * sizeof (int));
 181 
 182   hb_shape_plan_plan (shape_plan,
 183                       user_features, num_user_features,
 184                       coords, num_coords,
 185                       shaper_list);
 186 
 187   return shape_plan;
 188 }
 189 
 190 /**
 191  * hb_shape_plan_get_empty:
 192  *
 193  * 
 194  *
 195  * Return value: (transfer full):
 196  *
 197  * Since: 0.9.7
 198  **/
 199 hb_shape_plan_t *
 200 hb_shape_plan_get_empty (void)
 201 {
 202   static const hb_shape_plan_t _hb_shape_plan_nil = {
 203     HB_OBJECT_HEADER_STATIC,
 204 
 205     true, /* default_shaper_list */
 206     NULL, /* face */
 207     HB_SEGMENT_PROPERTIES_DEFAULT, /* props */
 208 
 209     NULL, /* shaper_func */
 210     NULL, /* shaper_name */
 211 
 212     NULL, /* user_features */
 213     0,    /* num_user_featurs */
 214 
 215     NULL, /* coords */
 216     0,    /* num_coords */
 217 
 218     {
 219 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
 220 #include "hb-shaper-list.hh"
 221 #undef HB_SHAPER_IMPLEMENT
 222     }
 223   };
 224 
 225   return const_cast<hb_shape_plan_t *> (&_hb_shape_plan_nil);
 226 }
 227 
 228 /**
 229  * hb_shape_plan_reference: (skip)
 230  * @shape_plan: a shape plan.
 231  *
 232  * 
 233  *
 234  * Return value: (transfer full):
 235  *
 236  * Since: 0.9.7
 237  **/


 242 }
 243 
 244 /**
 245  * hb_shape_plan_destroy: (skip)
 246  * @shape_plan: a shape plan.
 247  *
 248  * 
 249  *
 250  * Since: 0.9.7
 251  **/
 252 void
 253 hb_shape_plan_destroy (hb_shape_plan_t *shape_plan)
 254 {
 255   if (!hb_object_destroy (shape_plan)) return;
 256 
 257 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, shape_plan);
 258 #include "hb-shaper-list.hh"
 259 #undef HB_SHAPER_IMPLEMENT
 260 
 261   free (shape_plan->user_features);
 262   free (shape_plan->coords);
 263 
 264   free (shape_plan);
 265 }
 266 
 267 /**
 268  * hb_shape_plan_set_user_data: (skip)
 269  * @shape_plan: a shape plan.
 270  * @key: 
 271  * @data: 
 272  * @destroy: 
 273  * @replace: 
 274  *
 275  * 
 276  *
 277  * Return value: 
 278  *
 279  * Since: 0.9.7
 280  **/
 281 hb_bool_t
 282 hb_shape_plan_set_user_data (hb_shape_plan_t    *shape_plan,


 312  * @shape_plan: a shape plan.
 313  * @font: a font.
 314  * @buffer: a buffer.
 315  * @features: (array length=num_features):
 316  * @num_features: 
 317  *
 318  * 
 319  *
 320  * Return value: 
 321  *
 322  * Since: 0.9.7
 323  **/
 324 hb_bool_t
 325 hb_shape_plan_execute (hb_shape_plan_t    *shape_plan,
 326                        hb_font_t          *font,
 327                        hb_buffer_t        *buffer,
 328                        const hb_feature_t *features,
 329                        unsigned int        num_features)
 330 {
 331   DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan,
 332                   "num_features=%d shaper_func=%p, shaper_name=%s",
 333                   num_features,
 334                   shape_plan->shaper_func,
 335                   shape_plan->shaper_name);
 336 
 337   if (unlikely (!buffer->len))
 338     return true;
 339 
 340   assert (!hb_object_is_inert (buffer));
 341   assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE);
 342 
 343   if (unlikely (hb_object_is_inert (shape_plan)))
 344     return false;
 345 
 346   assert (shape_plan->face_unsafe == font->face);
 347   assert (hb_segment_properties_equal (&shape_plan->props, &buffer->props));
 348 
 349 #define HB_SHAPER_EXECUTE(shaper) \
 350         HB_STMT_START { \
 351           return HB_SHAPER_DATA (shaper, shape_plan) && \
 352                  hb_##shaper##_shaper_font_data_ensure (font) && \
 353                  _hb_##shaper##_shape (shape_plan, font, buffer, features, num_features); \
 354         } HB_STMT_END
 355 


 374 #if 0
 375 static unsigned int
 376 hb_shape_plan_hash (const hb_shape_plan_t *shape_plan)
 377 {
 378   return hb_segment_properties_hash (&shape_plan->props) +
 379          shape_plan->default_shaper_list ? 0 : (intptr_t) shape_plan->shaper_func;
 380 }
 381 #endif
 382 
 383 /* User-feature caching is currently somewhat dumb:
 384  * it only finds matches where the feature array is identical,
 385  * not cases where the feature lists would be compatible for plan purposes
 386  * but have different ranges, for example.
 387  */
 388 struct hb_shape_plan_proposal_t
 389 {
 390   const hb_segment_properties_t  props;
 391   const char * const            *shaper_list;
 392   const hb_feature_t            *user_features;
 393   unsigned int                   num_user_features;
 394   const int                     *coords;
 395   unsigned int                   num_coords;
 396   hb_shape_func_t               *shaper_func;
 397 };
 398 
 399 static inline hb_bool_t
 400 hb_shape_plan_user_features_match (const hb_shape_plan_t          *shape_plan,
 401                                    const hb_shape_plan_proposal_t *proposal)
 402 {
 403   if (proposal->num_user_features != shape_plan->num_user_features)
 404     return false;
 405   for (unsigned int i = 0, n = proposal->num_user_features; i < n; i++)
 406     if (proposal->user_features[i].tag   != shape_plan->user_features[i].tag   ||
 407         proposal->user_features[i].value != shape_plan->user_features[i].value ||
 408         proposal->user_features[i].start != shape_plan->user_features[i].start ||
 409         proposal->user_features[i].end   != shape_plan->user_features[i].end)
 410       return false;
 411   return true;
 412 }
 413 
 414 static inline hb_bool_t
 415 hb_shape_plan_coords_match (const hb_shape_plan_t          *shape_plan,
 416                             const hb_shape_plan_proposal_t *proposal)
 417 {
 418   if (proposal->num_coords != shape_plan->num_coords)
 419     return false;
 420   for (unsigned int i = 0, n = proposal->num_coords; i < n; i++)
 421     if (proposal->coords[i] != shape_plan->coords[i])
 422       return false;
 423   return true;
 424 }
 425 
 426 static hb_bool_t
 427 hb_shape_plan_matches (const hb_shape_plan_t          *shape_plan,
 428                        const hb_shape_plan_proposal_t *proposal)
 429 {
 430   return hb_segment_properties_equal (&shape_plan->props, &proposal->props) &&
 431          hb_shape_plan_user_features_match (shape_plan, proposal) &&
 432          hb_shape_plan_coords_match (shape_plan, proposal) &&
 433          ((shape_plan->default_shaper_list && proposal->shaper_list == NULL) ||
 434           (shape_plan->shaper_func == proposal->shaper_func));
 435 }
 436 
 437 static inline hb_bool_t
 438 hb_non_global_user_features_present (const hb_feature_t *user_features,
 439                                      unsigned int        num_user_features)
 440 {
 441   while (num_user_features)
 442     if (user_features->start != 0 || user_features->end != (unsigned int) -1)
 443       return true;
 444     else
 445       num_user_features--, user_features++;
 446   return false;
 447 }
 448 
 449 static inline hb_bool_t
 450 hb_coords_present (const int *coords,
 451                    unsigned int num_coords)
 452 {
 453   return num_coords != 0;
 454 }
 455 
 456 /**
 457  * hb_shape_plan_create_cached:
 458  * @face: 
 459  * @props: 
 460  * @user_features: (array length=num_user_features):
 461  * @num_user_features: 
 462  * @shaper_list: (array zero-terminated=1):
 463  *
 464  * 
 465  *
 466  * Return value: (transfer full):
 467  *
 468  * Since: 0.9.7
 469  **/
 470 hb_shape_plan_t *
 471 hb_shape_plan_create_cached (hb_face_t                     *face,
 472                              const hb_segment_properties_t *props,
 473                              const hb_feature_t            *user_features,
 474                              unsigned int                   num_user_features,
 475                              const char * const            *shaper_list)
 476 {
 477   return hb_shape_plan_create_cached2 (face, props,
 478                                        user_features, num_user_features,
 479                                        NULL, 0,
 480                                        shaper_list);
 481 }
 482 
 483 hb_shape_plan_t *
 484 hb_shape_plan_create_cached2 (hb_face_t                     *face,
 485                               const hb_segment_properties_t *props,
 486                               const hb_feature_t            *user_features,
 487                               unsigned int                   num_user_features,
 488                               const int                     *coords,
 489                               unsigned int                   num_coords,
 490                               const char * const            *shaper_list)
 491 {
 492   DEBUG_MSG_FUNC (SHAPE_PLAN, NULL,
 493                   "face=%p num_features=%d shaper_list=%p",
 494                   face,
 495                   num_user_features,
 496                   shaper_list);
 497 
 498   hb_shape_plan_proposal_t proposal = {
 499     *props,
 500     shaper_list,
 501     user_features,
 502     num_user_features,
 503     NULL
 504   };
 505 
 506   if (shaper_list) {
 507     /* Choose shaper.  Adapted from hb_shape_plan_plan().
 508      * Must choose shaper exactly the same way as that function. */
 509     for (const char * const *shaper_item = shaper_list; *shaper_item; shaper_item++)
 510       if (0)
 511         ;


 518       }
 519 #include "hb-shaper-list.hh"
 520 #undef HB_SHAPER_IMPLEMENT
 521 
 522     if (unlikely (!proposal.shaper_func))
 523       return hb_shape_plan_get_empty ();
 524   }
 525 
 526 
 527 retry:
 528   hb_face_t::plan_node_t *cached_plan_nodes = (hb_face_t::plan_node_t *) hb_atomic_ptr_get (&face->shape_plans);
 529   for (hb_face_t::plan_node_t *node = cached_plan_nodes; node; node = node->next)
 530     if (hb_shape_plan_matches (node->shape_plan, &proposal))
 531     {
 532       DEBUG_MSG_FUNC (SHAPE_PLAN, node->shape_plan, "fulfilled from cache");
 533       return hb_shape_plan_reference (node->shape_plan);
 534     }
 535 
 536   /* Not found. */
 537 
 538   hb_shape_plan_t *shape_plan = hb_shape_plan_create2 (face, props,
 539                                                        user_features, num_user_features,
 540                                                        coords, num_coords,
 541                                                        shaper_list);
 542 
 543   /* Don't add to the cache if face is inert. */
 544   if (unlikely (hb_object_is_inert (face)))
 545     return shape_plan;
 546 
 547   /* Don't add the plan to the cache if there were user features with non-global ranges */

 548   if (hb_non_global_user_features_present (user_features, num_user_features))
 549     return shape_plan;
 550   /* Don't add the plan to the cache if there were variation coordinates XXX Fix me. */
 551   if (hb_coords_present (coords, num_coords))
 552     return shape_plan;
 553 
 554   hb_face_t::plan_node_t *node = (hb_face_t::plan_node_t *) calloc (1, sizeof (hb_face_t::plan_node_t));
 555   if (unlikely (!node))
 556     return shape_plan;
 557 
 558   node->shape_plan = shape_plan;
 559   node->next = cached_plan_nodes;
 560 
 561   if (!hb_atomic_ptr_cmpexch (&face->shape_plans, cached_plan_nodes, node)) {
 562     hb_shape_plan_destroy (shape_plan);
 563     free (node);
 564     goto retry;
 565   }
 566   DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan, "inserted into cache");
 567 
 568   return hb_shape_plan_reference (shape_plan);
 569 }
 570 
 571 /**
 572  * hb_shape_plan_get_shaper:
< prev index next >