< prev index next >

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

Print this page




   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-private.hh"
  28 #include "hb-debug.hh"
  29 #include "hb-shape-plan-private.hh"
  30 #include "hb-shaper-private.hh"
  31 #include "hb-font-private.hh"
  32 #include "hb-buffer-private.hh"
  33 
  34 
  35 static void
  36 hb_shape_plan_plan (hb_shape_plan_t    *shape_plan,



















  37                     const hb_feature_t *user_features,
  38                     unsigned int        num_user_features,
  39                     const int          *coords,
  40                     unsigned int        num_coords,
  41                     const char * const *shaper_list)
  42 {
  43   DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan,
  44                   "num_features=%d num_coords=%d shaper_list=%p",
  45                   num_user_features,
  46                   num_coords,
  47                   shaper_list);

















  48 
  49   const hb_shaper_pair_t *shapers = _hb_shapers_get ();


  50 
  51 #define HB_SHAPER_PLAN(shaper) \
  52         HB_STMT_START { \
  53           if (hb_##shaper##_shaper_face_data_ensure (shape_plan->face_unsafe)) { \
  54             HB_SHAPER_DATA (shaper, shape_plan) = \
  55               HB_SHAPER_DATA_CREATE_FUNC (shaper, shape_plan) (shape_plan, \
  56                                                                user_features, num_user_features, \
  57                                                                coords, num_coords); \
  58             shape_plan->shaper_func = _hb_##shaper##_shape; \
  59             shape_plan->shaper_name = #shaper; \
  60             return; \
  61           } \
  62         } HB_STMT_END
  63 
  64   if (likely (!shaper_list)) {
  65     for (unsigned int i = 0; i < HB_SHAPERS_COUNT; i++)
  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++)
  75       if (0)



  76         ;
  77 #define HB_SHAPER_IMPLEMENT(shaper) \
  78       else if (0 == strcmp (*shaper_list, #shaper)) \
  79         HB_SHAPER_PLAN (shaper);
  80 #include "hb-shaper-list.hh"
  81 #undef HB_SHAPER_IMPLEMENT
  82   }
  83 
  84 #undef HB_SHAPER_PLAN































  85 }
  86 
  87 
  88 /*
  89  * hb_shape_plan_t
  90  */
  91 

  92 /**
  93  * hb_shape_plan_create: (Xconstructor)
  94  * @face:
  95  * @props:
  96  * @user_features: (array length=num_user_features):
  97  * @num_user_features:
  98  * @shaper_list: (array zero-terminated=1):
  99  *
 100  *
 101  *
 102  * Return value: (transfer full):
 103  *
 104  * Since: 0.9.7
 105  **/
 106 hb_shape_plan_t *
 107 hb_shape_plan_create (hb_face_t                     *face,
 108                       const hb_segment_properties_t *props,
 109                       const hb_feature_t            *user_features,
 110                       unsigned int                   num_user_features,
 111                       const char * const            *shaper_list)
 112 {
 113   return hb_shape_plan_create2 (face, props,
 114                                 user_features, num_user_features,
 115                                 nullptr, 0,
 116                                 shaper_list);
 117 }
 118 
 119 hb_shape_plan_t *
 120 hb_shape_plan_create2 (hb_face_t                     *face,
 121                        const hb_segment_properties_t *props,
 122                        const hb_feature_t            *user_features,
 123                        unsigned int                   num_user_features,
 124                        const int                     *orig_coords,
 125                        unsigned int                   num_coords,
 126                        const char * const            *shaper_list)
 127 {
 128   DEBUG_MSG_FUNC (SHAPE_PLAN, nullptr,
 129                   "face=%p num_features=%d num_coords=%d shaper_list=%p",
 130                   face,
 131                   num_user_features,
 132                   num_coords,
 133                   shaper_list);
 134 


 135   hb_shape_plan_t *shape_plan;
 136   hb_feature_t *features = nullptr;
 137   int *coords = nullptr;
 138 
 139   if (unlikely (!face))
 140     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);
 160   shape_plan->default_shaper_list = !shaper_list;
 161   shape_plan->face_unsafe = face;
 162   shape_plan->props = *props;
 163   shape_plan->num_user_features = num_user_features;
 164   shape_plan->user_features = features;
 165   if (num_user_features)
 166     memcpy (features, user_features, num_user_features * sizeof (hb_feature_t));
 167   shape_plan->num_coords = num_coords;
 168   shape_plan->coords = coords;
 169   if (num_coords)
 170     memcpy (coords, orig_coords, num_coords * sizeof (int));
 171 
 172   hb_shape_plan_plan (shape_plan,
 173                       user_features, num_user_features,
 174                       coords, num_coords,
 175                       shaper_list);







 176 
 177   return shape_plan;







 178 }
 179 
 180 /**
 181  * hb_shape_plan_get_empty:
 182  *
 183  *
 184  *
 185  * Return value: (transfer full):
 186  *
 187  * Since: 0.9.7
 188  **/
 189 hb_shape_plan_t *
 190 hb_shape_plan_get_empty (void)
 191 {
 192   static const hb_shape_plan_t _hb_shape_plan_nil = {
 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 }
 217 
 218 /**
 219  * hb_shape_plan_reference: (skip)
 220  * @shape_plan: a shape plan.
 221  *
 222  *
 223  *
 224  * Return value: (transfer full):
 225  *
 226  * Since: 0.9.7
 227  **/
 228 hb_shape_plan_t *
 229 hb_shape_plan_reference (hb_shape_plan_t *shape_plan)
 230 {
 231   return hb_object_reference (shape_plan);
 232 }
 233 
 234 /**
 235  * hb_shape_plan_destroy: (skip)
 236  * @shape_plan: a shape plan.
 237  *
 238  *
 239  *
 240  * Since: 0.9.7
 241  **/
 242 void
 243 hb_shape_plan_destroy (hb_shape_plan_t *shape_plan)
 244 {
 245   if (!hb_object_destroy (shape_plan)) return;
 246 
 247 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, shape_plan);
 248 #include "hb-shaper-list.hh"
 249 #undef HB_SHAPER_IMPLEMENT
 250 
 251   free (shape_plan->user_features);
 252   free (shape_plan->coords);
 253 
 254   free (shape_plan);
 255 }
 256 
 257 /**
 258  * hb_shape_plan_set_user_data: (skip)
 259  * @shape_plan: a shape plan.
 260  * @key:
 261  * @data:
 262  * @destroy:
 263  * @replace:
 264  *
 265  *
 266  *
 267  * Return value:
 268  *
 269  * Since: 0.9.7
 270  **/
 271 hb_bool_t
 272 hb_shape_plan_set_user_data (hb_shape_plan_t    *shape_plan,
 273                              hb_user_data_key_t *key,


 279 }
 280 
 281 /**
 282  * hb_shape_plan_get_user_data: (skip)
 283  * @shape_plan: a shape plan.
 284  * @key:
 285  *
 286  *
 287  *
 288  * Return value: (transfer none):
 289  *
 290  * Since: 0.9.7
 291  **/
 292 void *
 293 hb_shape_plan_get_user_data (hb_shape_plan_t    *shape_plan,
 294                              hb_user_data_key_t *key)
 295 {
 296   return hb_object_get_user_data (shape_plan, key);
 297 }
 298 
















 299 
 300 /**
 301  * hb_shape_plan_execute:
 302  * @shape_plan: a shape plan.
 303  * @font: a font.
 304  * @buffer: a buffer.
 305  * @features: (array length=num_features):
 306  * @num_features:
 307  *
 308  *
 309  *
 310  * Return value:
 311  *
 312  * Since: 0.9.7
 313  **/
 314 hb_bool_t
 315 hb_shape_plan_execute (hb_shape_plan_t    *shape_plan,
 316                        hb_font_t          *font,
 317                        hb_buffer_t        *buffer,
 318                        const hb_feature_t *features,
 319                        unsigned int        num_features)
 320 {
 321   DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan,
 322                   "num_features=%d shaper_func=%p, shaper_name=%s",
 323                   num_features,
 324                   shape_plan->shaper_func,
 325                   shape_plan->shaper_name);
 326 
 327   if (unlikely (!buffer->len))
 328     return true;
 329 
 330   assert (!hb_object_is_inert (buffer));
 331   assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE);
 332 
 333   if (unlikely (hb_object_is_inert (shape_plan)))
 334     return false;
 335 
 336   assert (shape_plan->face_unsafe == font->face);
 337   assert (hb_segment_properties_equal (&shape_plan->props, &buffer->props));
 338 
 339 #define HB_SHAPER_EXECUTE(shaper) \
 340         HB_STMT_START { \
 341           return HB_SHAPER_DATA (shaper, shape_plan) && \
 342                  hb_##shaper##_shaper_font_data_ensure (font) && \
 343                  _hb_##shaper##_shape (shape_plan, font, buffer, features, num_features); \
 344         } HB_STMT_END
 345 
 346   if (0)
 347     ;
 348 #define HB_SHAPER_IMPLEMENT(shaper) \
 349   else if (shape_plan->shaper_func == _hb_##shaper##_shape) \
 350     HB_SHAPER_EXECUTE (shaper);
 351 #include "hb-shaper-list.hh"
 352 #undef HB_SHAPER_IMPLEMENT
 353 
 354 #undef HB_SHAPER_EXECUTE
 355 
 356   return false;
 357 }
 358 
 359 
 360 /*
 361  * caching
 362  */
 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 
 447 /**
 448  * hb_shape_plan_create_cached:
 449  * @face:
 450  * @props:
 451  * @user_features: (array length=num_user_features):
 452  * @num_user_features:
 453  * @shaper_list: (array zero-terminated=1):
 454  *
 455  *
 456  *
 457  * Return value: (transfer full):
 458  *
 459  * Since: 0.9.7
 460  **/
 461 hb_shape_plan_t *
 462 hb_shape_plan_create_cached (hb_face_t                     *face,
 463                              const hb_segment_properties_t *props,
 464                              const hb_feature_t            *user_features,
 465                              unsigned int                   num_user_features,


 469                                        user_features, num_user_features,
 470                                        nullptr, 0,
 471                                        shaper_list);
 472 }
 473 
 474 hb_shape_plan_t *
 475 hb_shape_plan_create_cached2 (hb_face_t                     *face,
 476                               const hb_segment_properties_t *props,
 477                               const hb_feature_t            *user_features,
 478                               unsigned int                   num_user_features,
 479                               const int                     *coords,
 480                               unsigned int                   num_coords,
 481                               const char * const            *shaper_list)
 482 {
 483   DEBUG_MSG_FUNC (SHAPE_PLAN, nullptr,
 484                   "face=%p num_features=%d shaper_list=%p",
 485                   face,
 486                   num_user_features,
 487                   shaper_list);
 488 
 489   hb_shape_plan_proposal_t proposal = {
 490     *props,
 491     shaper_list,
 492     user_features,
 493     num_user_features,
 494     nullptr
 495   };
 496 
 497   if (shaper_list) {
 498     /* Choose shaper.  Adapted from hb_shape_plan_plan().
 499      * Must choose shaper exactly the same way as that function. */
 500     for (const char * const *shaper_item = shaper_list; *shaper_item; shaper_item++)
 501       if (0)
 502         ;
 503 #define HB_SHAPER_IMPLEMENT(shaper) \
 504       else if (0 == strcmp (*shaper_item, #shaper) && \
 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 ();
 515   }
 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)
 524       if (hb_shape_plan_matches (node->shape_plan, &proposal))
 525       {
 526         DEBUG_MSG_FUNC (SHAPE_PLAN, node->shape_plan, "fulfilled from cache");
 527         return hb_shape_plan_reference (node->shape_plan);
 528       }

 529 
 530   /* Not found. */
 531   hb_shape_plan_t *shape_plan = hb_shape_plan_create2 (face, props,
 532                                                        user_features, num_user_features,
 533                                                        coords, num_coords,
 534                                                        shaper_list);
 535 
 536   /* Don't add to the cache if face is inert. */
 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;
 546 
 547   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))
 549     return shape_plan;
 550 
 551   node->shape_plan = shape_plan;
 552   node->next = cached_plan_nodes;
 553 
 554   if (!hb_atomic_ptr_cmpexch (&face->shape_plans, cached_plan_nodes, node)) {

 555     hb_shape_plan_destroy (shape_plan);
 556     free (node);
 557     goto retry;
 558   }
 559   DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan, "inserted into cache");
 560 
 561   return hb_shape_plan_reference (shape_plan);
 562 }
 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 }


   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.hh"
  28 #include "hb-shape-plan.hh"
  29 #include "hb-shaper.hh"
  30 #include "hb-font.hh"
  31 #include "hb-buffer.hh"

  32 
  33 
  34 /**
  35  * SECTION:hb-shape-plan
  36  * @title: hb-shape-plan
  37  * @short_description: Object representing a shaping plan
  38  * @include: hb.h
  39  *
  40  * Shape plans are not used for shaping directly, but can be access to query
  41  * certain information about how shaping will perform given a set of input
  42  * parameters (script, language, direction, features, etc.)
  43  * Most client would not need to deal with shape plans directly.
  44  **/
  45 
  46 
  47 /*
  48  * hb_shape_plan_key_t
  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    */
  87 
  88 #define HB_SHAPER_PLAN(shaper) \
  89         HB_STMT_START { \
  90           if (face->data.shaper) \
  91           { \
  92             this->shaper_func = _hb_##shaper##_shape; \
  93             this->shaper_name = #shaper; \
  94             return true; \



  95           } \
  96         } HB_STMT_END
  97 
  98   if (unlikely (shaper_list))
  99   {
 100     for (; *shaper_list; shaper_list++)
 101       if (false)
 102         ;
 103 #define HB_SHAPER_IMPLEMENT(shaper) \
 104       else if (0 == strcmp (*shaper_list, #shaper)) \
 105         HB_SHAPER_PLAN (shaper);
 106 #include "hb-shaper-list.hh"
 107 #undef HB_SHAPER_IMPLEMENT
 108   }
 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   }

 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;
 153 }
 154 
 155 
 156 /*
 157  * hb_shape_plan_t
 158  */
 159 
 160 
 161 /**
 162  * hb_shape_plan_create: (Xconstructor)
 163  * @face:
 164  * @props:
 165  * @user_features: (array length=num_user_features):
 166  * @num_user_features:
 167  * @shaper_list: (array zero-terminated=1):
 168  *
 169  *
 170  *
 171  * Return value: (transfer full):
 172  *
 173  * Since: 0.9.7
 174  **/
 175 hb_shape_plan_t *
 176 hb_shape_plan_create (hb_face_t                     *face,
 177                       const hb_segment_properties_t *props,
 178                       const hb_feature_t            *user_features,
 179                       unsigned int                   num_user_features,
 180                       const char * const            *shaper_list)
 181 {
 182   return hb_shape_plan_create2 (face, props,
 183                                 user_features, num_user_features,
 184                                 nullptr, 0,
 185                                 shaper_list);
 186 }
 187 
 188 hb_shape_plan_t *
 189 hb_shape_plan_create2 (hb_face_t                     *face,
 190                        const hb_segment_properties_t *props,
 191                        const hb_feature_t            *user_features,
 192                        unsigned int                   num_user_features,
 193                        const int                     *coords,
 194                        unsigned int                   num_coords,
 195                        const char * const            *shaper_list)
 196 {
 197   DEBUG_MSG_FUNC (SHAPE_PLAN, nullptr,
 198                   "face=%p num_features=%d num_coords=%d shaper_list=%p",
 199                   face,
 200                   num_user_features,
 201                   num_coords,
 202                   shaper_list);
 203 
 204   assert (props->direction != HB_DIRECTION_INVALID);
 205 
 206   hb_shape_plan_t *shape_plan;


 207 


 208   if (unlikely (!props))
 209     goto bail;







 210   if (!(shape_plan = hb_object_create<hb_shape_plan_t> ()))
 211     goto bail;






 212 
 213   if (unlikely (!face))
 214     face = hb_face_get_empty ();
 215   hb_face_make_immutable (face);

 216   shape_plan->face_unsafe = face;









 217 
 218   if (unlikely (!shape_plan->key.init (true,
 219                                        face,
 220                                        props,
 221                                        user_features,
 222                                        num_user_features,
 223                                        coords,
 224                                        num_coords,
 225                                        shaper_list)))
 226     goto bail2;
 227   if (unlikely (!shape_plan->ot.init0 (face, &shape_plan->key)))
 228     goto bail3;
 229 
 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 ();
 238 }
 239 
 240 /**
 241  * hb_shape_plan_get_empty:
 242  *
 243  *
 244  *
 245  * Return value: (transfer full):
 246  *
 247  * Since: 0.9.7
 248  **/
 249 hb_shape_plan_t *
 250 hb_shape_plan_get_empty ()
 251 {
 252   return const_cast<hb_shape_plan_t *> (&Null(hb_shape_plan_t));























 253 }
 254 
 255 /**
 256  * hb_shape_plan_reference: (skip)
 257  * @shape_plan: a shape plan.
 258  *
 259  *
 260  *
 261  * Return value: (transfer full):
 262  *
 263  * Since: 0.9.7
 264  **/
 265 hb_shape_plan_t *
 266 hb_shape_plan_reference (hb_shape_plan_t *shape_plan)
 267 {
 268   return hb_object_reference (shape_plan);
 269 }
 270 
 271 /**
 272  * hb_shape_plan_destroy: (skip)
 273  * @shape_plan: a shape plan.
 274  *
 275  *
 276  *
 277  * Since: 0.9.7
 278  **/
 279 void
 280 hb_shape_plan_destroy (hb_shape_plan_t *shape_plan)
 281 {
 282   if (!hb_object_destroy (shape_plan)) return;
 283 
 284   shape_plan->ot.fini ();
 285   shape_plan->key.free ();





 286   free (shape_plan);
 287 }
 288 
 289 /**
 290  * hb_shape_plan_set_user_data: (skip)
 291  * @shape_plan: a shape plan.
 292  * @key:
 293  * @data:
 294  * @destroy:
 295  * @replace:
 296  *
 297  *
 298  *
 299  * Return value:
 300  *
 301  * Since: 0.9.7
 302  **/
 303 hb_bool_t
 304 hb_shape_plan_set_user_data (hb_shape_plan_t    *shape_plan,
 305                              hb_user_data_key_t *key,


 311 }
 312 
 313 /**
 314  * hb_shape_plan_get_user_data: (skip)
 315  * @shape_plan: a shape plan.
 316  * @key:
 317  *
 318  *
 319  *
 320  * Return value: (transfer none):
 321  *
 322  * Since: 0.9.7
 323  **/
 324 void *
 325 hb_shape_plan_get_user_data (hb_shape_plan_t    *shape_plan,
 326                              hb_user_data_key_t *key)
 327 {
 328   return hb_object_get_user_data (shape_plan, key);
 329 }
 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 
 347 
 348 /**
 349  * hb_shape_plan_execute:
 350  * @shape_plan: a shape plan.
 351  * @font: a font.
 352  * @buffer: a buffer.
 353  * @features: (array length=num_features):
 354  * @num_features:
 355  *
 356  *
 357  *
 358  * Return value:
 359  *
 360  * Since: 0.9.7
 361  **/
 362 hb_bool_t
 363 hb_shape_plan_execute (hb_shape_plan_t    *shape_plan,
 364                        hb_font_t          *font,
 365                        hb_buffer_t        *buffer,
 366                        const hb_feature_t *features,
 367                        unsigned int        num_features)
 368 {
 369   DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan,
 370                   "num_features=%d shaper_func=%p, shaper_name=%s",
 371                   num_features,
 372                   shape_plan->key.shaper_func,
 373                   shape_plan->key.shaper_name);
 374 
 375   if (unlikely (!buffer->len))
 376     return true;
 377 
 378   assert (!hb_object_is_immutable (buffer));
 379   assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE);
 380 
 381   if (unlikely (hb_object_is_inert (shape_plan)))
 382     return false;
 383 
 384   assert (shape_plan->face_unsafe == font->face);
 385   assert (hb_segment_properties_equal (&shape_plan->key.props, &buffer->props));
 386 
 387 #define HB_SHAPER_EXECUTE(shaper) \
 388         HB_STMT_START { \
 389           return font->data.shaper && \

 390                  _hb_##shaper##_shape (shape_plan, font, buffer, features, num_features); \
 391         } HB_STMT_END
 392 
 393   if (false)
 394     ;
 395 #define HB_SHAPER_IMPLEMENT(shaper) \
 396   else if (shape_plan->key.shaper_func == _hb_##shaper##_shape) \
 397     HB_SHAPER_EXECUTE (shaper);
 398 #include "hb-shaper-list.hh"
 399 #undef HB_SHAPER_IMPLEMENT
 400 
 401 #undef HB_SHAPER_EXECUTE
 402 
 403   return false;
 404 }
 405 
 406 
 407 /*
 408  * Caching















 409  */




































































 410 
 411 /**
 412  * hb_shape_plan_create_cached:
 413  * @face:
 414  * @props:
 415  * @user_features: (array length=num_user_features):
 416  * @num_user_features:
 417  * @shaper_list: (array zero-terminated=1):
 418  *
 419  *
 420  *
 421  * Return value: (transfer full):
 422  *
 423  * Since: 0.9.7
 424  **/
 425 hb_shape_plan_t *
 426 hb_shape_plan_create_cached (hb_face_t                     *face,
 427                              const hb_segment_properties_t *props,
 428                              const hb_feature_t            *user_features,
 429                              unsigned int                   num_user_features,


 433                                        user_features, num_user_features,
 434                                        nullptr, 0,
 435                                        shaper_list);
 436 }
 437 
 438 hb_shape_plan_t *
 439 hb_shape_plan_create_cached2 (hb_face_t                     *face,
 440                               const hb_segment_properties_t *props,
 441                               const hb_feature_t            *user_features,
 442                               unsigned int                   num_user_features,
 443                               const int                     *coords,
 444                               unsigned int                   num_coords,
 445                               const char * const            *shaper_list)
 446 {
 447   DEBUG_MSG_FUNC (SHAPE_PLAN, nullptr,
 448                   "face=%p num_features=%d shaper_list=%p",
 449                   face,
 450                   num_user_features,
 451                   shaper_list);
 452 
 453 retry:
 454   hb_face_t::plan_node_t *cached_plan_nodes = face->shape_plans;





 455 
 456   bool dont_cache = hb_object_is_inert (face);














 457 
 458   if (likely (!dont_cache))
 459   {
 460     hb_shape_plan_key_t key;
 461     if (!key.init (false,
 462                    face,
 463                    props,
 464                    user_features,
 465                    num_user_features,
 466                    coords,
 467                    num_coords,
 468                    shaper_list))
 469       return hb_shape_plan_get_empty ();





 470 


 471     for (hb_face_t::plan_node_t *node = cached_plan_nodes; node; node = node->next)
 472       if (node->shape_plan->key.equal (&key))
 473       {
 474         DEBUG_MSG_FUNC (SHAPE_PLAN, node->shape_plan, "fulfilled from cache");
 475         return hb_shape_plan_reference (node->shape_plan);
 476       }
 477   }
 478 

 479   hb_shape_plan_t *shape_plan = hb_shape_plan_create2 (face, props,
 480                                                        user_features, num_user_features,
 481                                                        coords, num_coords,
 482                                                        shaper_list);
 483 
 484   if (unlikely (dont_cache))








 485     return shape_plan;
 486 
 487   hb_face_t::plan_node_t *node = (hb_face_t::plan_node_t *) calloc (1, sizeof (hb_face_t::plan_node_t));
 488   if (unlikely (!node))
 489     return shape_plan;
 490 
 491   node->shape_plan = shape_plan;
 492   node->next = cached_plan_nodes;
 493 
 494   if (unlikely (!face->shape_plans.cmpexch (cached_plan_nodes, node)))
 495   {
 496     hb_shape_plan_destroy (shape_plan);
 497     free (node);
 498     goto retry;
 499   }
 500   DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan, "inserted into cache");
 501 
 502   return hb_shape_plan_reference (shape_plan);
















 503 }
< prev index next >