1 /*
   2  * Copyright © 2007,2008,2009  Red Hat, Inc.
   3  * Copyright © 2012,2013  Google, Inc.
   4  *
   5  *  This is part of HarfBuzz, a text shaping library.
   6  *
   7  * Permission is hereby granted, without written agreement and without
   8  * license or royalty fees, to use, copy, modify, and distribute this
   9  * software and its documentation for any purpose, provided that the
  10  * above copyright notice and the following two paragraphs appear in
  11  * all copies of this software.
  12  *
  13  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
  14  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
  15  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
  16  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
  17  * DAMAGE.
  18  *
  19  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
  20  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  21  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  22  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  23  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  24  *
  25  * Red Hat Author(s): Behdad Esfahbod
  26  * Google Author(s): Behdad Esfahbod
  27  */
  28 
  29 #ifndef HB_OT_LAYOUT_PRIVATE_HH
  30 #define HB_OT_LAYOUT_PRIVATE_HH
  31 
  32 #include "hb-private.hh"
  33 
  34 #include "hb-font-private.hh"
  35 #include "hb-buffer-private.hh"
  36 #include "hb-set-private.hh"
  37 
  38 
  39 /* Private API corresponding to hb-ot-layout.h: */
  40 
  41 HB_INTERNAL hb_bool_t
  42 hb_ot_layout_table_find_feature (hb_face_t    *face,
  43                                  hb_tag_t      table_tag,
  44                                  hb_tag_t      feature_tag,
  45                                  unsigned int *feature_index);
  46 
  47 
  48 /*
  49  * GDEF
  50  */
  51 
  52 enum hb_ot_layout_glyph_props_flags_t
  53 {
  54   /* The following three match LookupFlags::Ignore* numbers. */
  55   HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH   = 0x02u,
  56   HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE     = 0x04u,
  57   HB_OT_LAYOUT_GLYPH_PROPS_MARK         = 0x08u,
  58 
  59   /* The following are used internally; not derived from GDEF. */
  60   HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED  = 0x10u,
  61   HB_OT_LAYOUT_GLYPH_PROPS_LIGATED      = 0x20u,
  62   HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED   = 0x40u,
  63 
  64   HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE     = HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED |
  65                                           HB_OT_LAYOUT_GLYPH_PROPS_LIGATED |
  66                                           HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED
  67 };
  68 HB_MARK_AS_FLAG_T (hb_ot_layout_glyph_props_flags_t);
  69 
  70 
  71 /*
  72  * GSUB/GPOS
  73  */
  74 
  75 HB_INTERNAL hb_bool_t
  76 hb_ot_layout_lookup_would_substitute_fast (hb_face_t            *face,
  77                                            unsigned int          lookup_index,
  78                                            const hb_codepoint_t *glyphs,
  79                                            unsigned int          glyphs_length,
  80                                            hb_bool_t             zero_context);
  81 
  82 
  83 /* Should be called before all the substitute_lookup's are done. */
  84 HB_INTERNAL void
  85 hb_ot_layout_substitute_start (hb_font_t    *font,
  86                                hb_buffer_t  *buffer);
  87 
  88 
  89 struct hb_ot_layout_lookup_accelerator_t;
  90 
  91 namespace OT {
  92   struct hb_apply_context_t;
  93   struct SubstLookup;
  94 }
  95 
  96 HB_INTERNAL void
  97 hb_ot_layout_substitute_lookup (OT::hb_apply_context_t *c,
  98                                 const OT::SubstLookup &lookup,
  99                                 const hb_ot_layout_lookup_accelerator_t &accel);
 100 
 101 
 102 /* Should be called before all the position_lookup's are done. */
 103 HB_INTERNAL void
 104 hb_ot_layout_position_start (hb_font_t    *font,
 105                              hb_buffer_t  *buffer);
 106 
 107 /* Should be called after all the position_lookup's are done, to finish advances. */
 108 HB_INTERNAL void
 109 hb_ot_layout_position_finish_advances (hb_font_t    *font,
 110                                        hb_buffer_t  *buffer);
 111 
 112 /* Should be called after hb_ot_layout_position_finish_advances, to finish offsets. */
 113 HB_INTERNAL void
 114 hb_ot_layout_position_finish_offsets (hb_font_t    *font,
 115                                       hb_buffer_t  *buffer);
 116 
 117 
 118 
 119 /*
 120  * hb_ot_layout_t
 121  */
 122 
 123 namespace OT {
 124   struct GDEF;
 125   struct GSUB;
 126   struct GPOS;
 127   struct MATH;
 128 }
 129 
 130 struct hb_ot_layout_lookup_accelerator_t
 131 {
 132   template <typename TLookup>
 133   inline void init (const TLookup &lookup)
 134   {
 135     digest.init ();
 136     lookup.add_coverage (&digest);
 137   }
 138 
 139   inline void fini (void)
 140   {
 141   }
 142 
 143   inline bool may_have (hb_codepoint_t g) const {
 144     return digest.may_have (g);
 145   }
 146 
 147   private:
 148   hb_set_digest_t digest;
 149 };
 150 
 151 struct hb_ot_layout_t
 152 {
 153   hb_blob_t *gdef_blob;
 154   hb_blob_t *gsub_blob;
 155   hb_blob_t *gpos_blob;
 156   hb_blob_t *math_blob;
 157 
 158   const struct OT::GDEF *gdef;
 159   const struct OT::GSUB *gsub;
 160   const struct OT::GPOS *gpos;
 161   const struct OT::MATH *math;
 162 
 163   unsigned int gsub_lookup_count;
 164   unsigned int gpos_lookup_count;
 165 
 166   hb_ot_layout_lookup_accelerator_t *gsub_accels;
 167   hb_ot_layout_lookup_accelerator_t *gpos_accels;
 168 };
 169 
 170 
 171 HB_INTERNAL hb_ot_layout_t *
 172 _hb_ot_layout_create (hb_face_t *face);
 173 
 174 HB_INTERNAL void
 175 _hb_ot_layout_destroy (hb_ot_layout_t *layout);
 176 
 177 
 178 #define hb_ot_layout_from_face(face) ((hb_ot_layout_t *) face->shaper_data.ot)
 179 
 180 
 181 /*
 182  * Buffer var routines.
 183  */
 184 
 185 /* buffer var allocations, used during the entire shaping process */
 186 #define unicode_props()         var2.u16[0]
 187 
 188 /* buffer var allocations, used during the GSUB/GPOS processing */
 189 #define glyph_props()           var1.u16[0] /* GDEF glyph properties */
 190 #define lig_props()             var1.u8[2] /* GSUB/GPOS ligature tracking */
 191 #define syllable()              var1.u8[3] /* GSUB/GPOS shaping boundaries */
 192 
 193 
 194 /* loop over syllables */
 195 
 196 #define foreach_syllable(buffer, start, end) \
 197   for (unsigned int \
 198        _count = buffer->len, \
 199        start = 0, end = _count ? _next_syllable (buffer, 0) : 0; \
 200        start < _count; \
 201        start = end, end = _next_syllable (buffer, start))
 202 
 203 static inline unsigned int
 204 _next_syllable (hb_buffer_t *buffer, unsigned int start)
 205 {
 206   hb_glyph_info_t *info = buffer->info;
 207   unsigned int count = buffer->len;
 208 
 209   unsigned int syllable = info[start].syllable();
 210   while (++start < count && syllable == info[start].syllable())
 211     ;
 212 
 213   return start;
 214 }
 215 
 216 
 217 /* unicode_props */
 218 
 219 /* Design:
 220  * unicode_props() is a two-byte number.  The low byte includes:
 221  * - General_Category: 5 bits.
 222  * - A bit each for:
 223  *   * Is it Default_Ignorable(); we have a modified Default_Ignorable().
 224  *   * Whether it's one of the three Mongolian Free Variation Selectors.
 225  *   * One free bit right now.
 226  *
 227  * The high-byte has different meanings, switched by the Gen-Cat:
 228  * - For Mn,Mc,Me: the modified Combining_Class.
 229  * - For Cf: whether it's ZWJ, ZWNJ, or something else.
 230  * - For Ws: index of which space character this is, if space fallback
 231  *   is needed, ie. we don't set this by default, only if asked to.
 232  */
 233 
 234 enum hb_unicode_props_flags_t {
 235   UPROPS_MASK_GEN_CAT   = 0x001Fu,
 236   UPROPS_MASK_IGNORABLE = 0x0020u,
 237   UPROPS_MASK_FVS       = 0x0040u, /* MONGOLIAN FREE VARIATION SELECTOR 1..3 */
 238 
 239   /* If GEN_CAT=FORMAT, top byte masks: */
 240   UPROPS_MASK_Cf_ZWJ    = 0x0100u,
 241   UPROPS_MASK_Cf_ZWNJ   = 0x0200u
 242 };
 243 HB_MARK_AS_FLAG_T (hb_unicode_props_flags_t);
 244 
 245 static inline void
 246 _hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_buffer_t *buffer)
 247 {
 248   hb_unicode_funcs_t *unicode = buffer->unicode;
 249   unsigned int u = info->codepoint;
 250   unsigned int gen_cat = (unsigned int) unicode->general_category (u);
 251   unsigned int props = gen_cat;
 252 
 253   if (u >= 0x80)
 254   {
 255     buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII;
 256     if (unlikely (unicode->is_default_ignorable (u)))
 257     {
 258       buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES;
 259       props |=  UPROPS_MASK_IGNORABLE;
 260       if (u == 0x200Cu) props |= UPROPS_MASK_Cf_ZWNJ;
 261       if (u == 0x200Du) props |= UPROPS_MASK_Cf_ZWJ;
 262       /* Mongolian Free Variation Selectors need to be remembered
 263        * because although we need to hide them like default-ignorables,
 264        * they need to non-ignorable during shaping.  This is similar to
 265        * what we do for joiners in Indic-like shapers, but since the
 266        * FVSes are GC=Mn, we have use a separate bit to remember them.
 267        * Fixes:
 268        * https://github.com/behdad/harfbuzz/issues/234
 269        */
 270       if (unlikely (hb_in_range (u, 0x180Bu, 0x180Du))) props |= UPROPS_MASK_FVS;
 271     }
 272     else if (unlikely (HB_UNICODE_GENERAL_CATEGORY_IS_NON_ENCLOSING_MARK_OR_MODIFIER_SYMBOL (gen_cat)))
 273     {
 274       /* The above check is just an optimization to let in only things we need further
 275        * processing on. */
 276 
 277       /* Only Mn and Mc can have non-zero ccc:
 278        * http://www.unicode.org/policies/stability_policy.html#Property_Value
 279        * """
 280        * Canonical_Combining_Class, General_Category
 281        * All characters other than those with General_Category property values
 282        * Spacing_Mark (Mc) and Nonspacing_Mark (Mn) have the Canonical_Combining_Class
 283        * property value 0.
 284        * 1.1.5+
 285        * """
 286        *
 287        * Also, all Mn's that are Default_Ignorable, have ccc=0, hence
 288        * the "else if".
 289        */
 290       props |= unicode->modified_combining_class (info->codepoint)<<8;
 291 
 292       /* Recategorize emoji skin-tone modifiers as Unicode mark, so they
 293        * behave correctly in non-native directionality.  They originally
 294        * are MODIFIER_SYMBOL.  Fixes:
 295        * https://github.com/behdad/harfbuzz/issues/169
 296        */
 297       if (unlikely (hb_in_range (u, 0x1F3FBu, 0x1F3FFu)))
 298       {
 299         props = gen_cat = HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK;
 300       }
 301     }
 302   }
 303 
 304   info->unicode_props() = props;
 305 }
 306 
 307 static inline void
 308 _hb_glyph_info_set_general_category (hb_glyph_info_t *info,
 309                                      hb_unicode_general_category_t gen_cat)
 310 {
 311   /* Clears top-byte. */
 312   info->unicode_props() = (unsigned int) gen_cat | (info->unicode_props() & (0xFF & ~UPROPS_MASK_GEN_CAT));
 313 }
 314 
 315 static inline hb_unicode_general_category_t
 316 _hb_glyph_info_get_general_category (const hb_glyph_info_t *info)
 317 {
 318   return (hb_unicode_general_category_t) (info->unicode_props() & UPROPS_MASK_GEN_CAT);
 319 }
 320 
 321 static inline bool
 322 _hb_glyph_info_is_unicode_mark (const hb_glyph_info_t *info)
 323 {
 324   return HB_UNICODE_GENERAL_CATEGORY_IS_MARK (info->unicode_props() & UPROPS_MASK_GEN_CAT);
 325 }
 326 static inline void
 327 _hb_glyph_info_set_modified_combining_class (hb_glyph_info_t *info,
 328                                              unsigned int modified_class)
 329 {
 330   if (unlikely (!_hb_glyph_info_is_unicode_mark (info)))
 331     return;
 332   info->unicode_props() = (modified_class<<8) | (info->unicode_props() & 0xFF);
 333 }
 334 static inline unsigned int
 335 _hb_glyph_info_get_modified_combining_class (const hb_glyph_info_t *info)
 336 {
 337   return _hb_glyph_info_is_unicode_mark (info) ? info->unicode_props()>>8 : 0;
 338 }
 339 
 340 static inline bool
 341 _hb_glyph_info_is_unicode_space (const hb_glyph_info_t *info)
 342 {
 343   return _hb_glyph_info_get_general_category (info) ==
 344          HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR;
 345 }
 346 static inline void
 347 _hb_glyph_info_set_unicode_space_fallback_type (hb_glyph_info_t *info, hb_unicode_funcs_t::space_t s)
 348 {
 349   if (unlikely (!_hb_glyph_info_is_unicode_space (info)))
 350     return;
 351   info->unicode_props() = (((unsigned int) s)<<8) | (info->unicode_props() & 0xFF);
 352 }
 353 static inline hb_unicode_funcs_t::space_t
 354 _hb_glyph_info_get_unicode_space_fallback_type (const hb_glyph_info_t *info)
 355 {
 356   return _hb_glyph_info_is_unicode_space (info) ?
 357          (hb_unicode_funcs_t::space_t) (info->unicode_props()>>8) :
 358          hb_unicode_funcs_t::NOT_SPACE;
 359 }
 360 
 361 static inline bool _hb_glyph_info_ligated (const hb_glyph_info_t *info);
 362 
 363 static inline hb_bool_t
 364 _hb_glyph_info_is_default_ignorable (const hb_glyph_info_t *info)
 365 {
 366   return (info->unicode_props() & UPROPS_MASK_IGNORABLE) &&
 367          !_hb_glyph_info_ligated (info);
 368 }
 369 static inline hb_bool_t
 370 _hb_glyph_info_is_default_ignorable_and_not_fvs (const hb_glyph_info_t *info)
 371 {
 372   return ((info->unicode_props() & (UPROPS_MASK_IGNORABLE|UPROPS_MASK_FVS))
 373           == UPROPS_MASK_IGNORABLE) &&
 374          !_hb_glyph_info_ligated (info);
 375 }
 376 
 377 static inline bool
 378 _hb_glyph_info_is_unicode_format (const hb_glyph_info_t *info)
 379 {
 380   return _hb_glyph_info_get_general_category (info) ==
 381          HB_UNICODE_GENERAL_CATEGORY_FORMAT;
 382 }
 383 static inline hb_bool_t
 384 _hb_glyph_info_is_zwnj (const hb_glyph_info_t *info)
 385 {
 386   return _hb_glyph_info_is_unicode_format (info) && (info->unicode_props() & UPROPS_MASK_Cf_ZWNJ);
 387 }
 388 static inline hb_bool_t
 389 _hb_glyph_info_is_zwj (const hb_glyph_info_t *info)
 390 {
 391   return _hb_glyph_info_is_unicode_format (info) && (info->unicode_props() & UPROPS_MASK_Cf_ZWJ);
 392 }
 393 static inline hb_bool_t
 394 _hb_glyph_info_is_joiner (const hb_glyph_info_t *info)
 395 {
 396   return _hb_glyph_info_is_unicode_format (info) && (info->unicode_props() & (UPROPS_MASK_Cf_ZWNJ|UPROPS_MASK_Cf_ZWJ));
 397 }
 398 static inline void
 399 _hb_glyph_info_flip_joiners (hb_glyph_info_t *info)
 400 {
 401   if (!_hb_glyph_info_is_unicode_format (info))
 402     return;
 403   info->unicode_props() ^= UPROPS_MASK_Cf_ZWNJ | UPROPS_MASK_Cf_ZWJ;
 404 }
 405 
 406 /* lig_props: aka lig_id / lig_comp
 407  *
 408  * When a ligature is formed:
 409  *
 410  *   - The ligature glyph and any marks in between all the same newly allocated
 411  *     lig_id,
 412  *   - The ligature glyph will get lig_num_comps set to the number of components
 413  *   - The marks get lig_comp > 0, reflecting which component of the ligature
 414  *     they were applied to.
 415  *   - This is used in GPOS to attach marks to the right component of a ligature
 416  *     in MarkLigPos,
 417  *   - Note that when marks are ligated together, much of the above is skipped
 418  *     and the current lig_id reused.
 419  *
 420  * When a multiple-substitution is done:
 421  *
 422  *   - All resulting glyphs will have lig_id = 0,
 423  *   - The resulting glyphs will have lig_comp = 0, 1, 2, ... respectively.
 424  *   - This is used in GPOS to attach marks to the first component of a
 425  *     multiple substitution in MarkBasePos.
 426  *
 427  * The numbers are also used in GPOS to do mark-to-mark positioning only
 428  * to marks that belong to the same component of the same ligature.
 429  */
 430 
 431 static inline void
 432 _hb_glyph_info_clear_lig_props (hb_glyph_info_t *info)
 433 {
 434   info->lig_props() = 0;
 435 }
 436 
 437 #define IS_LIG_BASE 0x10
 438 
 439 static inline void
 440 _hb_glyph_info_set_lig_props_for_ligature (hb_glyph_info_t *info,
 441                                            unsigned int lig_id,
 442                                            unsigned int lig_num_comps)
 443 {
 444   info->lig_props() = (lig_id << 5) | IS_LIG_BASE | (lig_num_comps & 0x0F);
 445 }
 446 
 447 static inline void
 448 _hb_glyph_info_set_lig_props_for_mark (hb_glyph_info_t *info,
 449                                        unsigned int lig_id,
 450                                        unsigned int lig_comp)
 451 {
 452   info->lig_props() = (lig_id << 5) | (lig_comp & 0x0F);
 453 }
 454 
 455 static inline void
 456 _hb_glyph_info_set_lig_props_for_component (hb_glyph_info_t *info, unsigned int comp)
 457 {
 458   _hb_glyph_info_set_lig_props_for_mark (info, 0, comp);
 459 }
 460 
 461 static inline unsigned int
 462 _hb_glyph_info_get_lig_id (const hb_glyph_info_t *info)
 463 {
 464   return info->lig_props() >> 5;
 465 }
 466 
 467 static inline bool
 468 _hb_glyph_info_ligated_internal (const hb_glyph_info_t *info)
 469 {
 470   return !!(info->lig_props() & IS_LIG_BASE);
 471 }
 472 
 473 static inline unsigned int
 474 _hb_glyph_info_get_lig_comp (const hb_glyph_info_t *info)
 475 {
 476   if (_hb_glyph_info_ligated_internal (info))
 477     return 0;
 478   else
 479     return info->lig_props() & 0x0F;
 480 }
 481 
 482 static inline unsigned int
 483 _hb_glyph_info_get_lig_num_comps (const hb_glyph_info_t *info)
 484 {
 485   if ((info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE) &&
 486       _hb_glyph_info_ligated_internal (info))
 487     return info->lig_props() & 0x0F;
 488   else
 489     return 1;
 490 }
 491 
 492 static inline uint8_t
 493 _hb_allocate_lig_id (hb_buffer_t *buffer) {
 494   uint8_t lig_id = buffer->next_serial () & 0x07;
 495   if (unlikely (!lig_id))
 496     lig_id = _hb_allocate_lig_id (buffer); /* in case of overflow */
 497   return lig_id;
 498 }
 499 
 500 /* glyph_props: */
 501 
 502 static inline void
 503 _hb_glyph_info_set_glyph_props (hb_glyph_info_t *info, unsigned int props)
 504 {
 505   info->glyph_props() = props;
 506 }
 507 
 508 static inline unsigned int
 509 _hb_glyph_info_get_glyph_props (const hb_glyph_info_t *info)
 510 {
 511   return info->glyph_props();
 512 }
 513 
 514 static inline bool
 515 _hb_glyph_info_is_base_glyph (const hb_glyph_info_t *info)
 516 {
 517   return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH);
 518 }
 519 
 520 static inline bool
 521 _hb_glyph_info_is_ligature (const hb_glyph_info_t *info)
 522 {
 523   return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE);
 524 }
 525 
 526 static inline bool
 527 _hb_glyph_info_is_mark (const hb_glyph_info_t *info)
 528 {
 529   return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK);
 530 }
 531 
 532 static inline bool
 533 _hb_glyph_info_substituted (const hb_glyph_info_t *info)
 534 {
 535   return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED);
 536 }
 537 
 538 static inline bool
 539 _hb_glyph_info_ligated (const hb_glyph_info_t *info)
 540 {
 541   return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATED);
 542 }
 543 
 544 static inline bool
 545 _hb_glyph_info_multiplied (const hb_glyph_info_t *info)
 546 {
 547   return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED);
 548 }
 549 
 550 static inline bool
 551 _hb_glyph_info_ligated_and_didnt_multiply (const hb_glyph_info_t *info)
 552 {
 553   return _hb_glyph_info_ligated (info) && !_hb_glyph_info_multiplied (info);
 554 }
 555 
 556 static inline void
 557 _hb_glyph_info_clear_ligated_and_multiplied (hb_glyph_info_t *info)
 558 {
 559   info->glyph_props() &= ~(HB_OT_LAYOUT_GLYPH_PROPS_LIGATED |
 560                            HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED);
 561 }
 562 
 563 static inline void
 564 _hb_glyph_info_clear_substituted (hb_glyph_info_t *info)
 565 {
 566   info->glyph_props() &= ~(HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED);
 567 }
 568 
 569 
 570 /* Allocation / deallocation. */
 571 
 572 static inline void
 573 _hb_buffer_allocate_unicode_vars (hb_buffer_t *buffer)
 574 {
 575   HB_BUFFER_ALLOCATE_VAR (buffer, unicode_props);
 576 }
 577 
 578 static inline void
 579 _hb_buffer_deallocate_unicode_vars (hb_buffer_t *buffer)
 580 {
 581   HB_BUFFER_DEALLOCATE_VAR (buffer, unicode_props);
 582 }
 583 
 584 static inline void
 585 _hb_buffer_assert_unicode_vars (hb_buffer_t *buffer)
 586 {
 587   HB_BUFFER_ASSERT_VAR (buffer, unicode_props);
 588 }
 589 
 590 static inline void
 591 _hb_buffer_allocate_gsubgpos_vars (hb_buffer_t *buffer)
 592 {
 593   HB_BUFFER_ALLOCATE_VAR (buffer, glyph_props);
 594   HB_BUFFER_ALLOCATE_VAR (buffer, lig_props);
 595   HB_BUFFER_ALLOCATE_VAR (buffer, syllable);
 596 }
 597 
 598 static inline void
 599 _hb_buffer_deallocate_gsubgpos_vars (hb_buffer_t *buffer)
 600 {
 601   HB_BUFFER_DEALLOCATE_VAR (buffer, syllable);
 602   HB_BUFFER_DEALLOCATE_VAR (buffer, lig_props);
 603   HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_props);
 604 }
 605 
 606 static inline void
 607 _hb_buffer_assert_gsubgpos_vars (hb_buffer_t *buffer)
 608 {
 609   HB_BUFFER_ASSERT_VAR (buffer, glyph_props);
 610   HB_BUFFER_ASSERT_VAR (buffer, lig_props);
 611   HB_BUFFER_ASSERT_VAR (buffer, syllable);
 612 }
 613 
 614 /* Make sure no one directly touches our props... */
 615 #undef unicode_props0
 616 #undef unicode_props1
 617 #undef lig_props
 618 #undef glyph_props
 619 
 620 
 621 #endif /* HB_OT_LAYOUT_PRIVATE_HH */