src/java.desktop/share/native/libfontmanager/harfbuzz/hb-shape-plan.cc
changeset 54232 7c11a7cc7c1d
parent 48274 51772bf1fb0c
equal deleted inserted replaced
54231:e4813eded7cb 54232:7c11a7cc7c1d
    22  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
    22  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
    23  *
    23  *
    24  * Google Author(s): Behdad Esfahbod
    24  * Google Author(s): Behdad Esfahbod
    25  */
    25  */
    26 
    26 
    27 #include "hb-private.hh"
    27 #include "hb.hh"
    28 #include "hb-debug.hh"
    28 #include "hb-shape-plan.hh"
    29 #include "hb-shape-plan-private.hh"
    29 #include "hb-shaper.hh"
    30 #include "hb-shaper-private.hh"
    30 #include "hb-font.hh"
    31 #include "hb-font-private.hh"
    31 #include "hb-buffer.hh"
    32 #include "hb-buffer-private.hh"
    32 
    33 
    33 
    34 
    34 /**
    35 static void
    35  * SECTION:hb-shape-plan
    36 hb_shape_plan_plan (hb_shape_plan_t    *shape_plan,
    36  * @title: hb-shape-plan
    37                     const hb_feature_t *user_features,
    37  * @short_description: Object representing a shaping plan
    38                     unsigned int        num_user_features,
    38  * @include: hb.h
    39                     const int          *coords,
    39  *
    40                     unsigned int        num_coords,
    40  * Shape plans are not used for shaping directly, but can be access to query
    41                     const char * const *shaper_list)
    41  * certain information about how shaping will perform given a set of input
    42 {
    42  * parameters (script, language, direction, features, etc.)
    43   DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan,
    43  * Most client would not need to deal with shape plans directly.
    44                   "num_features=%d num_coords=%d shaper_list=%p",
    44  **/
    45                   num_user_features,
    45 
    46                   num_coords,
    46 
    47                   shaper_list);
    47 /*
    48 
    48  * hb_shape_plan_key_t
    49   const hb_shaper_pair_t *shapers = _hb_shapers_get ();
    49  */
       
    50 
       
    51 bool
       
    52 hb_shape_plan_key_t::init (bool                           copy,
       
    53                            hb_face_t                     *face,
       
    54                            const hb_segment_properties_t *props,
       
    55                            const hb_feature_t            *user_features,
       
    56                            unsigned int                   num_user_features,
       
    57                            const int                     *coords,
       
    58                            unsigned int                   num_coords,
       
    59                            const char * const            *shaper_list)
       
    60 {
       
    61   hb_feature_t *features = nullptr;
       
    62   if (copy && num_user_features && !(features = (hb_feature_t *) calloc (num_user_features, sizeof (hb_feature_t))))
       
    63     goto bail;
       
    64 
       
    65   this->props = *props;
       
    66   this->num_user_features = num_user_features;
       
    67   this->user_features = copy ? features : user_features;
       
    68   if (copy && num_user_features)
       
    69   {
       
    70     memcpy (features, user_features, num_user_features * sizeof (hb_feature_t));
       
    71     /* Make start/end uniform to easier catch bugs. */
       
    72     for (unsigned int i = 0; i < num_user_features; i++)
       
    73     {
       
    74       if (features[0].start != HB_FEATURE_GLOBAL_START)
       
    75         features[0].start = 1;
       
    76       if (features[0].end   != HB_FEATURE_GLOBAL_END)
       
    77         features[0].end   = 2;
       
    78     }
       
    79   }
       
    80   this->shaper_func = nullptr;
       
    81   this->shaper_name = nullptr;
       
    82   this->ot.init (face, coords, num_coords);
       
    83 
       
    84   /*
       
    85    * Choose shaper.
       
    86    */
    50 
    87 
    51 #define HB_SHAPER_PLAN(shaper) \
    88 #define HB_SHAPER_PLAN(shaper) \
    52         HB_STMT_START { \
    89         HB_STMT_START { \
    53           if (hb_##shaper##_shaper_face_data_ensure (shape_plan->face_unsafe)) { \
    90           if (face->data.shaper) \
    54             HB_SHAPER_DATA (shaper, shape_plan) = \
    91           { \
    55               HB_SHAPER_DATA_CREATE_FUNC (shaper, shape_plan) (shape_plan, \
    92             this->shaper_func = _hb_##shaper##_shape; \
    56                                                                user_features, num_user_features, \
    93             this->shaper_name = #shaper; \
    57                                                                coords, num_coords); \
    94             return true; \
    58             shape_plan->shaper_func = _hb_##shaper##_shape; \
       
    59             shape_plan->shaper_name = #shaper; \
       
    60             return; \
       
    61           } \
    95           } \
    62         } HB_STMT_END
    96         } HB_STMT_END
    63 
    97 
    64   if (likely (!shaper_list)) {
    98   if (unlikely (shaper_list))
    65     for (unsigned int i = 0; i < HB_SHAPERS_COUNT; i++)
    99   {
    66       if (0)
       
    67         ;
       
    68 #define HB_SHAPER_IMPLEMENT(shaper) \
       
    69       else if (shapers[i].func == _hb_##shaper##_shape) \
       
    70         HB_SHAPER_PLAN (shaper);
       
    71 #include "hb-shaper-list.hh"
       
    72 #undef HB_SHAPER_IMPLEMENT
       
    73   } else {
       
    74     for (; *shaper_list; shaper_list++)
   100     for (; *shaper_list; shaper_list++)
    75       if (0)
   101       if (false)
    76         ;
   102         ;
    77 #define HB_SHAPER_IMPLEMENT(shaper) \
   103 #define HB_SHAPER_IMPLEMENT(shaper) \
    78       else if (0 == strcmp (*shaper_list, #shaper)) \
   104       else if (0 == strcmp (*shaper_list, #shaper)) \
    79         HB_SHAPER_PLAN (shaper);
   105         HB_SHAPER_PLAN (shaper);
    80 #include "hb-shaper-list.hh"
   106 #include "hb-shaper-list.hh"
    81 #undef HB_SHAPER_IMPLEMENT
   107 #undef HB_SHAPER_IMPLEMENT
    82   }
   108   }
    83 
   109   else
       
   110   {
       
   111     const hb_shaper_entry_t *shapers = _hb_shapers_get ();
       
   112     for (unsigned int i = 0; i < HB_SHAPERS_COUNT; i++)
       
   113       if (false)
       
   114         ;
       
   115 #define HB_SHAPER_IMPLEMENT(shaper) \
       
   116       else if (shapers[i].func == _hb_##shaper##_shape) \
       
   117         HB_SHAPER_PLAN (shaper);
       
   118 #include "hb-shaper-list.hh"
       
   119 #undef HB_SHAPER_IMPLEMENT
       
   120   }
    84 #undef HB_SHAPER_PLAN
   121 #undef HB_SHAPER_PLAN
       
   122 
       
   123 bail:
       
   124   ::free (features);
       
   125   return false;
       
   126 }
       
   127 
       
   128 bool
       
   129 hb_shape_plan_key_t::user_features_match (const hb_shape_plan_key_t *other)
       
   130 {
       
   131   if (this->num_user_features != other->num_user_features)
       
   132     return false;
       
   133   for (unsigned int i = 0; i < num_user_features; i++)
       
   134   {
       
   135     if (this->user_features[i].tag   != other->user_features[i].tag   ||
       
   136         this->user_features[i].value != other->user_features[i].value ||
       
   137         (this->user_features[i].start == HB_FEATURE_GLOBAL_START &&
       
   138          this->user_features[i].end   == HB_FEATURE_GLOBAL_END) !=
       
   139         (other->user_features[i].start == HB_FEATURE_GLOBAL_START &&
       
   140          other->user_features[i].end   == HB_FEATURE_GLOBAL_END))
       
   141       return false;
       
   142   }
       
   143   return true;
       
   144 }
       
   145 
       
   146 bool
       
   147 hb_shape_plan_key_t::equal (const hb_shape_plan_key_t *other)
       
   148 {
       
   149   return hb_segment_properties_equal (&this->props, &other->props) &&
       
   150          this->user_features_match (other) &&
       
   151          this->ot.equal (&other->ot) &&
       
   152          this->shaper_func == other->shaper_func;
    85 }
   153 }
    86 
   154 
    87 
   155 
    88 /*
   156 /*
    89  * hb_shape_plan_t
   157  * hb_shape_plan_t
    90  */
   158  */
       
   159 
    91 
   160 
    92 /**
   161 /**
    93  * hb_shape_plan_create: (Xconstructor)
   162  * hb_shape_plan_create: (Xconstructor)
    94  * @face:
   163  * @face:
    95  * @props:
   164  * @props:
   119 hb_shape_plan_t *
   188 hb_shape_plan_t *
   120 hb_shape_plan_create2 (hb_face_t                     *face,
   189 hb_shape_plan_create2 (hb_face_t                     *face,
   121                        const hb_segment_properties_t *props,
   190                        const hb_segment_properties_t *props,
   122                        const hb_feature_t            *user_features,
   191                        const hb_feature_t            *user_features,
   123                        unsigned int                   num_user_features,
   192                        unsigned int                   num_user_features,
   124                        const int                     *orig_coords,
   193                        const int                     *coords,
   125                        unsigned int                   num_coords,
   194                        unsigned int                   num_coords,
   126                        const char * const            *shaper_list)
   195                        const char * const            *shaper_list)
   127 {
   196 {
   128   DEBUG_MSG_FUNC (SHAPE_PLAN, nullptr,
   197   DEBUG_MSG_FUNC (SHAPE_PLAN, nullptr,
   129                   "face=%p num_features=%d num_coords=%d shaper_list=%p",
   198                   "face=%p num_features=%d num_coords=%d shaper_list=%p",
   130                   face,
   199                   face,
   131                   num_user_features,
   200                   num_user_features,
   132                   num_coords,
   201                   num_coords,
   133                   shaper_list);
   202                   shaper_list);
   134 
   203 
       
   204   assert (props->direction != HB_DIRECTION_INVALID);
       
   205 
   135   hb_shape_plan_t *shape_plan;
   206   hb_shape_plan_t *shape_plan;
   136   hb_feature_t *features = nullptr;
   207 
   137   int *coords = nullptr;
   208   if (unlikely (!props))
       
   209     goto bail;
       
   210   if (!(shape_plan = hb_object_create<hb_shape_plan_t> ()))
       
   211     goto bail;
   138 
   212 
   139   if (unlikely (!face))
   213   if (unlikely (!face))
   140     face = hb_face_get_empty ();
   214     face = hb_face_get_empty ();
   141   if (unlikely (!props))
       
   142     return hb_shape_plan_get_empty ();
       
   143   if (num_user_features && !(features = (hb_feature_t *) calloc (num_user_features, sizeof (hb_feature_t))))
       
   144     return hb_shape_plan_get_empty ();
       
   145   if (num_coords && !(coords = (int *) calloc (num_coords, sizeof (int))))
       
   146   {
       
   147     free (features);
       
   148     return hb_shape_plan_get_empty ();
       
   149   }
       
   150   if (!(shape_plan = hb_object_create<hb_shape_plan_t> ()))
       
   151   {
       
   152     free (coords);
       
   153     free (features);
       
   154     return hb_shape_plan_get_empty ();
       
   155   }
       
   156 
       
   157   assert (props->direction != HB_DIRECTION_INVALID);
       
   158 
       
   159   hb_face_make_immutable (face);
   215   hb_face_make_immutable (face);
   160   shape_plan->default_shaper_list = !shaper_list;
       
   161   shape_plan->face_unsafe = face;
   216   shape_plan->face_unsafe = face;
   162   shape_plan->props = *props;
   217 
   163   shape_plan->num_user_features = num_user_features;
   218   if (unlikely (!shape_plan->key.init (true,
   164   shape_plan->user_features = features;
   219                                        face,
   165   if (num_user_features)
   220                                        props,
   166     memcpy (features, user_features, num_user_features * sizeof (hb_feature_t));
   221                                        user_features,
   167   shape_plan->num_coords = num_coords;
   222                                        num_user_features,
   168   shape_plan->coords = coords;
   223                                        coords,
   169   if (num_coords)
   224                                        num_coords,
   170     memcpy (coords, orig_coords, num_coords * sizeof (int));
   225                                        shaper_list)))
   171 
   226     goto bail2;
   172   hb_shape_plan_plan (shape_plan,
   227   if (unlikely (!shape_plan->ot.init0 (face, &shape_plan->key)))
   173                       user_features, num_user_features,
   228     goto bail3;
   174                       coords, num_coords,
       
   175                       shaper_list);
       
   176 
   229 
   177   return shape_plan;
   230   return shape_plan;
       
   231 
       
   232 bail3:
       
   233   shape_plan->key.free ();
       
   234 bail2:
       
   235   free (shape_plan);
       
   236 bail:
       
   237   return hb_shape_plan_get_empty ();
   178 }
   238 }
   179 
   239 
   180 /**
   240 /**
   181  * hb_shape_plan_get_empty:
   241  * hb_shape_plan_get_empty:
   182  *
   242  *
   185  * Return value: (transfer full):
   245  * Return value: (transfer full):
   186  *
   246  *
   187  * Since: 0.9.7
   247  * Since: 0.9.7
   188  **/
   248  **/
   189 hb_shape_plan_t *
   249 hb_shape_plan_t *
   190 hb_shape_plan_get_empty (void)
   250 hb_shape_plan_get_empty ()
   191 {
   251 {
   192   static const hb_shape_plan_t _hb_shape_plan_nil = {
   252   return const_cast<hb_shape_plan_t *> (&Null(hb_shape_plan_t));
   193     HB_OBJECT_HEADER_STATIC,
       
   194 
       
   195     true, /* default_shaper_list */
       
   196     nullptr, /* face */
       
   197     HB_SEGMENT_PROPERTIES_DEFAULT, /* props */
       
   198 
       
   199     nullptr, /* shaper_func */
       
   200     nullptr, /* shaper_name */
       
   201 
       
   202     nullptr, /* user_features */
       
   203     0,    /* num_user_featurs */
       
   204 
       
   205     nullptr, /* coords */
       
   206     0,    /* num_coords */
       
   207 
       
   208     {
       
   209 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
       
   210 #include "hb-shaper-list.hh"
       
   211 #undef HB_SHAPER_IMPLEMENT
       
   212     }
       
   213   };
       
   214 
       
   215   return const_cast<hb_shape_plan_t *> (&_hb_shape_plan_nil);
       
   216 }
   253 }
   217 
   254 
   218 /**
   255 /**
   219  * hb_shape_plan_reference: (skip)
   256  * hb_shape_plan_reference: (skip)
   220  * @shape_plan: a shape plan.
   257  * @shape_plan: a shape plan.
   242 void
   279 void
   243 hb_shape_plan_destroy (hb_shape_plan_t *shape_plan)
   280 hb_shape_plan_destroy (hb_shape_plan_t *shape_plan)
   244 {
   281 {
   245   if (!hb_object_destroy (shape_plan)) return;
   282   if (!hb_object_destroy (shape_plan)) return;
   246 
   283 
   247 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, shape_plan);
   284   shape_plan->ot.fini ();
   248 #include "hb-shaper-list.hh"
   285   shape_plan->key.free ();
   249 #undef HB_SHAPER_IMPLEMENT
       
   250 
       
   251   free (shape_plan->user_features);
       
   252   free (shape_plan->coords);
       
   253 
       
   254   free (shape_plan);
   286   free (shape_plan);
   255 }
   287 }
   256 
   288 
   257 /**
   289 /**
   258  * hb_shape_plan_set_user_data: (skip)
   290  * hb_shape_plan_set_user_data: (skip)
   294                              hb_user_data_key_t *key)
   326                              hb_user_data_key_t *key)
   295 {
   327 {
   296   return hb_object_get_user_data (shape_plan, key);
   328   return hb_object_get_user_data (shape_plan, key);
   297 }
   329 }
   298 
   330 
       
   331 /**
       
   332  * hb_shape_plan_get_shaper:
       
   333  * @shape_plan: a shape plan.
       
   334  *
       
   335  *
       
   336  *
       
   337  * Return value: (transfer none):
       
   338  *
       
   339  * Since: 0.9.7
       
   340  **/
       
   341 const char *
       
   342 hb_shape_plan_get_shaper (hb_shape_plan_t *shape_plan)
       
   343 {
       
   344   return shape_plan->key.shaper_name;
       
   345 }
       
   346 
   299 
   347 
   300 /**
   348 /**
   301  * hb_shape_plan_execute:
   349  * hb_shape_plan_execute:
   302  * @shape_plan: a shape plan.
   350  * @shape_plan: a shape plan.
   303  * @font: a font.
   351  * @font: a font.
   319                        unsigned int        num_features)
   367                        unsigned int        num_features)
   320 {
   368 {
   321   DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan,
   369   DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan,
   322                   "num_features=%d shaper_func=%p, shaper_name=%s",
   370                   "num_features=%d shaper_func=%p, shaper_name=%s",
   323                   num_features,
   371                   num_features,
   324                   shape_plan->shaper_func,
   372                   shape_plan->key.shaper_func,
   325                   shape_plan->shaper_name);
   373                   shape_plan->key.shaper_name);
   326 
   374 
   327   if (unlikely (!buffer->len))
   375   if (unlikely (!buffer->len))
   328     return true;
   376     return true;
   329 
   377 
   330   assert (!hb_object_is_inert (buffer));
   378   assert (!hb_object_is_immutable (buffer));
   331   assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE);
   379   assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE);
   332 
   380 
   333   if (unlikely (hb_object_is_inert (shape_plan)))
   381   if (unlikely (hb_object_is_inert (shape_plan)))
   334     return false;
   382     return false;
   335 
   383 
   336   assert (shape_plan->face_unsafe == font->face);
   384   assert (shape_plan->face_unsafe == font->face);
   337   assert (hb_segment_properties_equal (&shape_plan->props, &buffer->props));
   385   assert (hb_segment_properties_equal (&shape_plan->key.props, &buffer->props));
   338 
   386 
   339 #define HB_SHAPER_EXECUTE(shaper) \
   387 #define HB_SHAPER_EXECUTE(shaper) \
   340         HB_STMT_START { \
   388         HB_STMT_START { \
   341           return HB_SHAPER_DATA (shaper, shape_plan) && \
   389           return font->data.shaper && \
   342                  hb_##shaper##_shaper_font_data_ensure (font) && \
       
   343                  _hb_##shaper##_shape (shape_plan, font, buffer, features, num_features); \
   390                  _hb_##shaper##_shape (shape_plan, font, buffer, features, num_features); \
   344         } HB_STMT_END
   391         } HB_STMT_END
   345 
   392 
   346   if (0)
   393   if (false)
   347     ;
   394     ;
   348 #define HB_SHAPER_IMPLEMENT(shaper) \
   395 #define HB_SHAPER_IMPLEMENT(shaper) \
   349   else if (shape_plan->shaper_func == _hb_##shaper##_shape) \
   396   else if (shape_plan->key.shaper_func == _hb_##shaper##_shape) \
   350     HB_SHAPER_EXECUTE (shaper);
   397     HB_SHAPER_EXECUTE (shaper);
   351 #include "hb-shaper-list.hh"
   398 #include "hb-shaper-list.hh"
   352 #undef HB_SHAPER_IMPLEMENT
   399 #undef HB_SHAPER_IMPLEMENT
   353 
   400 
   354 #undef HB_SHAPER_EXECUTE
   401 #undef HB_SHAPER_EXECUTE
   356   return false;
   403   return false;
   357 }
   404 }
   358 
   405 
   359 
   406 
   360 /*
   407 /*
   361  * caching
   408  * Caching
   362  */
   409  */
   363 
       
   364 #if 0
       
   365 static unsigned int
       
   366 hb_shape_plan_hash (const hb_shape_plan_t *shape_plan)
       
   367 {
       
   368   return hb_segment_properties_hash (&shape_plan->props) +
       
   369          shape_plan->default_shaper_list ? 0 : (intptr_t) shape_plan->shaper_func;
       
   370 }
       
   371 #endif
       
   372 
       
   373 /* User-feature caching is currently somewhat dumb:
       
   374  * it only finds matches where the feature array is identical,
       
   375  * not cases where the feature lists would be compatible for plan purposes
       
   376  * but have different ranges, for example.
       
   377  */
       
   378 struct hb_shape_plan_proposal_t
       
   379 {
       
   380   const hb_segment_properties_t  props;
       
   381   const char * const            *shaper_list;
       
   382   const hb_feature_t            *user_features;
       
   383   unsigned int                   num_user_features;
       
   384   const int                     *coords;
       
   385   unsigned int                   num_coords;
       
   386   hb_shape_func_t               *shaper_func;
       
   387 };
       
   388 
       
   389 static inline hb_bool_t
       
   390 hb_shape_plan_user_features_match (const hb_shape_plan_t          *shape_plan,
       
   391                                    const hb_shape_plan_proposal_t *proposal)
       
   392 {
       
   393   if (proposal->num_user_features != shape_plan->num_user_features)
       
   394     return false;
       
   395   for (unsigned int i = 0, n = proposal->num_user_features; i < n; i++)
       
   396     if (proposal->user_features[i].tag   != shape_plan->user_features[i].tag   ||
       
   397         proposal->user_features[i].value != shape_plan->user_features[i].value ||
       
   398         proposal->user_features[i].start != shape_plan->user_features[i].start ||
       
   399         proposal->user_features[i].end   != shape_plan->user_features[i].end)
       
   400       return false;
       
   401   return true;
       
   402 }
       
   403 
       
   404 static inline hb_bool_t
       
   405 hb_shape_plan_coords_match (const hb_shape_plan_t          *shape_plan,
       
   406                             const hb_shape_plan_proposal_t *proposal)
       
   407 {
       
   408   if (proposal->num_coords != shape_plan->num_coords)
       
   409     return false;
       
   410   for (unsigned int i = 0, n = proposal->num_coords; i < n; i++)
       
   411     if (proposal->coords[i] != shape_plan->coords[i])
       
   412       return false;
       
   413   return true;
       
   414 }
       
   415 
       
   416 static hb_bool_t
       
   417 hb_shape_plan_matches (const hb_shape_plan_t          *shape_plan,
       
   418                        const hb_shape_plan_proposal_t *proposal)
       
   419 {
       
   420   return hb_segment_properties_equal (&shape_plan->props, &proposal->props) &&
       
   421          hb_shape_plan_user_features_match (shape_plan, proposal) &&
       
   422          hb_shape_plan_coords_match (shape_plan, proposal) &&
       
   423          ((shape_plan->default_shaper_list && !proposal->shaper_list) ||
       
   424           (shape_plan->shaper_func == proposal->shaper_func));
       
   425 }
       
   426 
       
   427 static inline hb_bool_t
       
   428 hb_non_global_user_features_present (const hb_feature_t *user_features,
       
   429                                      unsigned int        num_user_features)
       
   430 {
       
   431   while (num_user_features) {
       
   432     if (user_features->start != 0 || user_features->end != (unsigned int) -1)
       
   433       return true;
       
   434     num_user_features--;
       
   435     user_features++;
       
   436   }
       
   437   return false;
       
   438 }
       
   439 
       
   440 static inline hb_bool_t
       
   441 hb_coords_present (const int *coords,
       
   442                    unsigned int num_coords)
       
   443 {
       
   444   return num_coords != 0;
       
   445 }
       
   446 
   410 
   447 /**
   411 /**
   448  * hb_shape_plan_create_cached:
   412  * hb_shape_plan_create_cached:
   449  * @face:
   413  * @face:
   450  * @props:
   414  * @props:
   484                   "face=%p num_features=%d shaper_list=%p",
   448                   "face=%p num_features=%d shaper_list=%p",
   485                   face,
   449                   face,
   486                   num_user_features,
   450                   num_user_features,
   487                   shaper_list);
   451                   shaper_list);
   488 
   452 
   489   hb_shape_plan_proposal_t proposal = {
   453 retry:
   490     *props,
   454   hb_face_t::plan_node_t *cached_plan_nodes = face->shape_plans;
   491     shaper_list,
   455 
   492     user_features,
   456   bool dont_cache = hb_object_is_inert (face);
   493     num_user_features,
   457 
   494     nullptr
   458   if (likely (!dont_cache))
   495   };
   459   {
   496 
   460     hb_shape_plan_key_t key;
   497   if (shaper_list) {
   461     if (!key.init (false,
   498     /* Choose shaper.  Adapted from hb_shape_plan_plan().
   462                    face,
   499      * Must choose shaper exactly the same way as that function. */
   463                    props,
   500     for (const char * const *shaper_item = shaper_list; *shaper_item; shaper_item++)
   464                    user_features,
   501       if (0)
   465                    num_user_features,
   502         ;
   466                    coords,
   503 #define HB_SHAPER_IMPLEMENT(shaper) \
   467                    num_coords,
   504       else if (0 == strcmp (*shaper_item, #shaper) && \
   468                    shaper_list))
   505                hb_##shaper##_shaper_face_data_ensure (face)) \
       
   506       { \
       
   507         proposal.shaper_func = _hb_##shaper##_shape; \
       
   508         break; \
       
   509       }
       
   510 #include "hb-shaper-list.hh"
       
   511 #undef HB_SHAPER_IMPLEMENT
       
   512 
       
   513     if (unlikely (!proposal.shaper_func))
       
   514       return hb_shape_plan_get_empty ();
   469       return hb_shape_plan_get_empty ();
   515   }
   470 
   516 
       
   517 
       
   518 retry:
       
   519   hb_face_t::plan_node_t *cached_plan_nodes = (hb_face_t::plan_node_t *) hb_atomic_ptr_get (&face->shape_plans);
       
   520 
       
   521   /* Don't look for plan in the cache if there were variation coordinates XXX Fix me. */
       
   522   if (!hb_coords_present (coords, num_coords))
       
   523     for (hb_face_t::plan_node_t *node = cached_plan_nodes; node; node = node->next)
   471     for (hb_face_t::plan_node_t *node = cached_plan_nodes; node; node = node->next)
   524       if (hb_shape_plan_matches (node->shape_plan, &proposal))
   472       if (node->shape_plan->key.equal (&key))
   525       {
   473       {
   526         DEBUG_MSG_FUNC (SHAPE_PLAN, node->shape_plan, "fulfilled from cache");
   474         DEBUG_MSG_FUNC (SHAPE_PLAN, node->shape_plan, "fulfilled from cache");
   527         return hb_shape_plan_reference (node->shape_plan);
   475         return hb_shape_plan_reference (node->shape_plan);
   528       }
   476       }
   529 
   477   }
   530   /* Not found. */
   478 
   531   hb_shape_plan_t *shape_plan = hb_shape_plan_create2 (face, props,
   479   hb_shape_plan_t *shape_plan = hb_shape_plan_create2 (face, props,
   532                                                        user_features, num_user_features,
   480                                                        user_features, num_user_features,
   533                                                        coords, num_coords,
   481                                                        coords, num_coords,
   534                                                        shaper_list);
   482                                                        shaper_list);
   535 
   483 
   536   /* Don't add to the cache if face is inert. */
   484   if (unlikely (dont_cache))
   537   if (unlikely (hb_object_is_inert (face)))
       
   538     return shape_plan;
       
   539 
       
   540   /* Don't add the plan to the cache if there were user features with non-global ranges */
       
   541   if (hb_non_global_user_features_present (user_features, num_user_features))
       
   542     return shape_plan;
       
   543   /* Don't add the plan to the cache if there were variation coordinates XXX Fix me. */
       
   544   if (hb_coords_present (coords, num_coords))
       
   545     return shape_plan;
   485     return shape_plan;
   546 
   486 
   547   hb_face_t::plan_node_t *node = (hb_face_t::plan_node_t *) calloc (1, sizeof (hb_face_t::plan_node_t));
   487   hb_face_t::plan_node_t *node = (hb_face_t::plan_node_t *) calloc (1, sizeof (hb_face_t::plan_node_t));
   548   if (unlikely (!node))
   488   if (unlikely (!node))
   549     return shape_plan;
   489     return shape_plan;
   550 
   490 
   551   node->shape_plan = shape_plan;
   491   node->shape_plan = shape_plan;
   552   node->next = cached_plan_nodes;
   492   node->next = cached_plan_nodes;
   553 
   493 
   554   if (!hb_atomic_ptr_cmpexch (&face->shape_plans, cached_plan_nodes, node)) {
   494   if (unlikely (!face->shape_plans.cmpexch (cached_plan_nodes, node)))
       
   495   {
   555     hb_shape_plan_destroy (shape_plan);
   496     hb_shape_plan_destroy (shape_plan);
   556     free (node);
   497     free (node);
   557     goto retry;
   498     goto retry;
   558   }
   499   }
   559   DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan, "inserted into cache");
   500   DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan, "inserted into cache");
   560 
   501 
   561   return hb_shape_plan_reference (shape_plan);
   502   return hb_shape_plan_reference (shape_plan);
   562 }
   503 }
   563 
       
   564 /**
       
   565  * hb_shape_plan_get_shaper:
       
   566  * @shape_plan: a shape plan.
       
   567  *
       
   568  *
       
   569  *
       
   570  * Return value: (transfer none):
       
   571  *
       
   572  * Since: 0.9.7
       
   573  **/
       
   574 const char *
       
   575 hb_shape_plan_get_shaper (hb_shape_plan_t *shape_plan)
       
   576 {
       
   577   return shape_plan->shaper_name;
       
   578 }