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_HH
  30 #define HB_OT_LAYOUT_HH
  31 
  32 #include "hb.hh"
  33 
  34 #include "hb-font.hh"
  35 #include "hb-buffer.hh"
  36 #include "hb-open-type.hh"
  37 #include "hb-ot-shape.hh"
  38 #include "hb-set-digest.hh"
  39 
  40 
  41 struct hb_ot_shape_plan_t;
  42 
  43 
  44 /*
  45  * kern
  46  */
  47 
  48 HB_INTERNAL bool
  49 hb_ot_layout_has_kerning (hb_face_t *face);
  50 
  51 HB_INTERNAL bool
  52 hb_ot_layout_has_machine_kerning (hb_face_t *face);
  53 
  54 HB_INTERNAL bool
  55 hb_ot_layout_has_cross_kerning (hb_face_t *face);
  56 
  57 HB_INTERNAL void
  58 hb_ot_layout_kern (const hb_ot_shape_plan_t *plan,
  59                    hb_font_t *font,
  60                    hb_buffer_t  *buffer);
  61 
  62 
  63 /* Private API corresponding to hb-ot-layout.h: */
  64 
  65 HB_INTERNAL bool
  66 hb_ot_layout_table_find_feature (hb_face_t    *face,
  67                                  hb_tag_t      table_tag,
  68                                  hb_tag_t      feature_tag,
  69                                  unsigned int *feature_index);
  70 
  71 
  72 /*
  73  * GDEF
  74  */
  75 
  76 enum hb_ot_layout_glyph_props_flags_t
  77 {
  78   /* The following three match LookupFlags::Ignore* numbers. */
  79   HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH   = 0x02u,
  80   HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE     = 0x04u,
  81   HB_OT_LAYOUT_GLYPH_PROPS_MARK         = 0x08u,
  82 
  83   /* The following are used internally; not derived from GDEF. */
  84   HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED  = 0x10u,
  85   HB_OT_LAYOUT_GLYPH_PROPS_LIGATED      = 0x20u,
  86   HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED   = 0x40u,
  87 
  88   HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE     = HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED |
  89                                           HB_OT_LAYOUT_GLYPH_PROPS_LIGATED |
  90                                           HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED
  91 };
  92 HB_MARK_AS_FLAG_T (hb_ot_layout_glyph_props_flags_t);
  93 
  94 
  95 /*
  96  * GSUB/GPOS
  97  */
  98 
  99 HB_INTERNAL bool
 100 hb_ot_layout_lookup_would_substitute_fast (hb_face_t            *face,
 101                                            unsigned int          lookup_index,
 102                                            const hb_codepoint_t *glyphs,
 103                                            unsigned int          glyphs_length,
 104                                            bool                  zero_context);
 105 
 106 
 107 /* Should be called before all the substitute_lookup's are done. */
 108 HB_INTERNAL void
 109 hb_ot_layout_substitute_start (hb_font_t    *font,
 110                                hb_buffer_t  *buffer);
 111 
 112 HB_INTERNAL void
 113 hb_ot_layout_delete_glyphs_inplace (hb_buffer_t *buffer,
 114                                     bool (*filter) (const hb_glyph_info_t *info));
 115 
 116 namespace OT {
 117   struct hb_ot_apply_context_t;
 118   struct SubstLookup;
 119   struct hb_ot_layout_lookup_accelerator_t;
 120 }
 121 
 122 HB_INTERNAL void
 123 hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c,
 124                                 const OT::SubstLookup &lookup,
 125                                 const OT::hb_ot_layout_lookup_accelerator_t &accel);
 126 
 127 
 128 /* Should be called before all the position_lookup's are done. */
 129 HB_INTERNAL void
 130 hb_ot_layout_position_start (hb_font_t    *font,
 131                              hb_buffer_t  *buffer);
 132 
 133 /* Should be called after all the position_lookup's are done, to fini advances. */
 134 HB_INTERNAL void
 135 hb_ot_layout_position_finish_advances (hb_font_t    *font,
 136                                        hb_buffer_t  *buffer);
 137 
 138 /* Should be called after hb_ot_layout_position_finish_advances, to fini offsets. */
 139 HB_INTERNAL void
 140 hb_ot_layout_position_finish_offsets (hb_font_t    *font,
 141                                       hb_buffer_t  *buffer);
 142 
 143 
 144 /*
 145  * Buffer var routines.
 146  */
 147 
 148 /* buffer var allocations, used during the entire shaping process */
 149 #define unicode_props()         var2.u16[0]
 150 
 151 /* buffer var allocations, used during the GSUB/GPOS processing */
 152 #define glyph_props()           var1.u16[0] /* GDEF glyph properties */
 153 #define lig_props()             var1.u8[2] /* GSUB/GPOS ligature tracking */
 154 #define syllable()              var1.u8[3] /* GSUB/GPOS shaping boundaries */
 155 
 156 
 157 /* Loop over syllables. Based on foreach_cluster(). */
 158 #define foreach_syllable(buffer, start, end) \
 159   for (unsigned int \
 160        _count = buffer->len, \
 161        start = 0, end = _count ? _hb_next_syllable (buffer, 0) : 0; \
 162        start < _count; \
 163        start = end, end = _hb_next_syllable (buffer, start))
 164 
 165 static inline unsigned int
 166 _hb_next_syllable (hb_buffer_t *buffer, unsigned int start)
 167 {
 168   hb_glyph_info_t *info = buffer->info;
 169   unsigned int count = buffer->len;
 170 
 171   unsigned int syllable = info[start].syllable();
 172   while (++start < count && syllable == info[start].syllable())
 173     ;
 174 
 175   return start;
 176 }
 177 
 178 
 179 /* unicode_props */
 180 
 181 /* Design:
 182  * unicode_props() is a two-byte number.  The low byte includes:
 183  * - General_Category: 5 bits.
 184  * - A bit each for:
 185  *   * Is it Default_Ignorable(); we have a modified Default_Ignorable().
 186  *   * Whether it's one of the three Mongolian Free Variation Selectors,
 187  *     CGJ, or other characters that are hidden but should not be ignored
 188  *     like most other Default_Ignorable()s do during matching.
 189  *   * Whether it's a grapheme continuation.
 190  *
 191  * The high-byte has different meanings, switched by the Gen-Cat:
 192  * - For Mn,Mc,Me: the modified Combining_Class.
 193  * - For Cf: whether it's ZWJ, ZWNJ, or something else.
 194  * - For Ws: index of which space character this is, if space fallback
 195  *   is needed, ie. we don't set this by default, only if asked to.
 196  */
 197 
 198 enum hb_unicode_props_flags_t {
 199   UPROPS_MASK_GEN_CAT   = 0x001Fu,
 200   UPROPS_MASK_IGNORABLE = 0x0020u,
 201   UPROPS_MASK_HIDDEN    = 0x0040u, /* MONGOLIAN FREE VARIATION SELECTOR 1..3, or TAG characters */
 202   UPROPS_MASK_CONTINUATION=0x0080u,
 203 
 204   /* If GEN_CAT=FORMAT, top byte masks: */
 205   UPROPS_MASK_Cf_ZWJ    = 0x0100u,
 206   UPROPS_MASK_Cf_ZWNJ   = 0x0200u
 207 };
 208 HB_MARK_AS_FLAG_T (hb_unicode_props_flags_t);
 209 
 210 static inline void
 211 _hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_buffer_t *buffer)
 212 {
 213   hb_unicode_funcs_t *unicode = buffer->unicode;
 214   unsigned int u = info->codepoint;
 215   unsigned int gen_cat = (unsigned int) unicode->general_category (u);
 216   unsigned int props = gen_cat;
 217 
 218   if (u >= 0x80)
 219   {
 220     buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII;
 221 
 222     if (unlikely (unicode->is_default_ignorable (u)))
 223     {
 224       buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES;
 225       props |=  UPROPS_MASK_IGNORABLE;
 226       if (u == 0x200Cu) props |= UPROPS_MASK_Cf_ZWNJ;
 227       else if (u == 0x200Du) props |= UPROPS_MASK_Cf_ZWJ;
 228       /* Mongolian Free Variation Selectors need to be remembered
 229        * because although we need to hide them like default-ignorables,
 230        * they need to non-ignorable during shaping.  This is similar to
 231        * what we do for joiners in Indic-like shapers, but since the
 232        * FVSes are GC=Mn, we have use a separate bit to remember them.
 233        * Fixes:
 234        * https://github.com/harfbuzz/harfbuzz/issues/234 */
 235       else if (unlikely (hb_in_range (u, 0x180Bu, 0x180Du))) props |= UPROPS_MASK_HIDDEN;
 236       /* TAG characters need similar treatment. Fixes:
 237        * https://github.com/harfbuzz/harfbuzz/issues/463 */
 238       else if (unlikely (hb_in_range (u, 0xE0020u, 0xE007Fu))) props |= UPROPS_MASK_HIDDEN;
 239       /* COMBINING GRAPHEME JOINER should not be skipped; at least some times.
 240        * https://github.com/harfbuzz/harfbuzz/issues/554 */
 241       else if (unlikely (u == 0x034Fu))
 242       {
 243         buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_CGJ;
 244         props |= UPROPS_MASK_HIDDEN;
 245       }
 246     }
 247 
 248     if (unlikely (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (gen_cat)))
 249     {
 250       props |= UPROPS_MASK_CONTINUATION;
 251       props |= unicode->modified_combining_class (u)<<8;
 252     }
 253   }
 254 
 255   info->unicode_props() = props;
 256 }
 257 
 258 static inline void
 259 _hb_glyph_info_set_general_category (hb_glyph_info_t *info,
 260                                      hb_unicode_general_category_t gen_cat)
 261 {
 262   /* Clears top-byte. */
 263   info->unicode_props() = (unsigned int) gen_cat | (info->unicode_props() & (0xFF & ~UPROPS_MASK_GEN_CAT));
 264 }
 265 
 266 static inline hb_unicode_general_category_t
 267 _hb_glyph_info_get_general_category (const hb_glyph_info_t *info)
 268 {
 269   return (hb_unicode_general_category_t) (info->unicode_props() & UPROPS_MASK_GEN_CAT);
 270 }
 271 
 272 static inline bool
 273 _hb_glyph_info_is_unicode_mark (const hb_glyph_info_t *info)
 274 {
 275   return HB_UNICODE_GENERAL_CATEGORY_IS_MARK (info->unicode_props() & UPROPS_MASK_GEN_CAT);
 276 }
 277 static inline void
 278 _hb_glyph_info_set_modified_combining_class (hb_glyph_info_t *info,
 279                                              unsigned int modified_class)
 280 {
 281   if (unlikely (!_hb_glyph_info_is_unicode_mark (info)))
 282     return;
 283   info->unicode_props() = (modified_class<<8) | (info->unicode_props() & 0xFF);
 284 }
 285 static inline unsigned int
 286 _hb_glyph_info_get_modified_combining_class (const hb_glyph_info_t *info)
 287 {
 288   return _hb_glyph_info_is_unicode_mark (info) ? info->unicode_props()>>8 : 0;
 289 }
 290 #define info_cc(info) (_hb_glyph_info_get_modified_combining_class (&(info)))
 291 
 292 static inline bool
 293 _hb_glyph_info_is_unicode_space (const hb_glyph_info_t *info)
 294 {
 295   return _hb_glyph_info_get_general_category (info) ==
 296          HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR;
 297 }
 298 static inline void
 299 _hb_glyph_info_set_unicode_space_fallback_type (hb_glyph_info_t *info, hb_unicode_funcs_t::space_t s)
 300 {
 301   if (unlikely (!_hb_glyph_info_is_unicode_space (info)))
 302     return;
 303   info->unicode_props() = (((unsigned int) s)<<8) | (info->unicode_props() & 0xFF);
 304 }
 305 static inline hb_unicode_funcs_t::space_t
 306 _hb_glyph_info_get_unicode_space_fallback_type (const hb_glyph_info_t *info)
 307 {
 308   return _hb_glyph_info_is_unicode_space (info) ?
 309          (hb_unicode_funcs_t::space_t) (info->unicode_props()>>8) :
 310          hb_unicode_funcs_t::NOT_SPACE;
 311 }
 312 
 313 static inline bool _hb_glyph_info_ligated (const hb_glyph_info_t *info);
 314 
 315 static inline bool
 316 _hb_glyph_info_is_default_ignorable (const hb_glyph_info_t *info)
 317 {
 318   return (info->unicode_props() & UPROPS_MASK_IGNORABLE) &&
 319          !_hb_glyph_info_ligated (info);
 320 }
 321 static inline bool
 322 _hb_glyph_info_is_default_ignorable_and_not_hidden (const hb_glyph_info_t *info)
 323 {
 324   return ((info->unicode_props() & (UPROPS_MASK_IGNORABLE|UPROPS_MASK_HIDDEN))
 325           == UPROPS_MASK_IGNORABLE) &&
 326          !_hb_glyph_info_ligated (info);
 327 }
 328 static inline void
 329 _hb_glyph_info_unhide (hb_glyph_info_t *info)
 330 {
 331   info->unicode_props() &= ~ UPROPS_MASK_HIDDEN;
 332 }
 333 
 334 static inline void
 335 _hb_glyph_info_set_continuation (hb_glyph_info_t *info)
 336 {
 337   info->unicode_props() |= UPROPS_MASK_CONTINUATION;
 338 }
 339 static inline void
 340 _hb_glyph_info_reset_continuation (hb_glyph_info_t *info)
 341 {
 342   info->unicode_props() &= ~ UPROPS_MASK_CONTINUATION;
 343 }
 344 static inline bool
 345 _hb_glyph_info_is_continuation (const hb_glyph_info_t *info)
 346 {
 347   return info->unicode_props() & UPROPS_MASK_CONTINUATION;
 348 }
 349 /* Loop over grapheme. Based on foreach_cluster(). */
 350 #define foreach_grapheme(buffer, start, end) \
 351   for (unsigned int \
 352        _count = buffer->len, \
 353        start = 0, end = _count ? _hb_next_grapheme (buffer, 0) : 0; \
 354        start < _count; \
 355        start = end, end = _hb_next_grapheme (buffer, start))
 356 
 357 static inline unsigned int
 358 _hb_next_grapheme (hb_buffer_t *buffer, unsigned int start)
 359 {
 360   hb_glyph_info_t *info = buffer->info;
 361   unsigned int count = buffer->len;
 362 
 363   while (++start < count && _hb_glyph_info_is_continuation (&info[start]))
 364     ;
 365 
 366   return start;
 367 }
 368 
 369 static inline bool
 370 _hb_glyph_info_is_unicode_format (const hb_glyph_info_t *info)
 371 {
 372   return _hb_glyph_info_get_general_category (info) ==
 373          HB_UNICODE_GENERAL_CATEGORY_FORMAT;
 374 }
 375 static inline bool
 376 _hb_glyph_info_is_zwnj (const hb_glyph_info_t *info)
 377 {
 378   return _hb_glyph_info_is_unicode_format (info) && (info->unicode_props() & UPROPS_MASK_Cf_ZWNJ);
 379 }
 380 static inline bool
 381 _hb_glyph_info_is_zwj (const hb_glyph_info_t *info)
 382 {
 383   return _hb_glyph_info_is_unicode_format (info) && (info->unicode_props() & UPROPS_MASK_Cf_ZWJ);
 384 }
 385 static inline bool
 386 _hb_glyph_info_is_joiner (const hb_glyph_info_t *info)
 387 {
 388   return _hb_glyph_info_is_unicode_format (info) && (info->unicode_props() & (UPROPS_MASK_Cf_ZWNJ|UPROPS_MASK_Cf_ZWJ));
 389 }
 390 static inline void
 391 _hb_glyph_info_flip_joiners (hb_glyph_info_t *info)
 392 {
 393   if (!_hb_glyph_info_is_unicode_format (info))
 394     return;
 395   info->unicode_props() ^= UPROPS_MASK_Cf_ZWNJ | UPROPS_MASK_Cf_ZWJ;
 396 }
 397 
 398 /* lig_props: aka lig_id / lig_comp
 399  *
 400  * When a ligature is formed:
 401  *
 402  *   - The ligature glyph and any marks in between all the same newly allocated
 403  *     lig_id,
 404  *   - The ligature glyph will get lig_num_comps set to the number of components
 405  *   - The marks get lig_comp > 0, reflecting which component of the ligature
 406  *     they were applied to.
 407  *   - This is used in GPOS to attach marks to the right component of a ligature
 408  *     in MarkLigPos,
 409  *   - Note that when marks are ligated together, much of the above is skipped
 410  *     and the current lig_id reused.
 411  *
 412  * When a multiple-substitution is done:
 413  *
 414  *   - All resulting glyphs will have lig_id = 0,
 415  *   - The resulting glyphs will have lig_comp = 0, 1, 2, ... respectively.
 416  *   - This is used in GPOS to attach marks to the first component of a
 417  *     multiple substitution in MarkBasePos.
 418  *
 419  * The numbers are also used in GPOS to do mark-to-mark positioning only
 420  * to marks that belong to the same component of the same ligature.
 421  */
 422 
 423 static inline void
 424 _hb_glyph_info_clear_lig_props (hb_glyph_info_t *info)
 425 {
 426   info->lig_props() = 0;
 427 }
 428 
 429 #define IS_LIG_BASE 0x10
 430 
 431 static inline void
 432 _hb_glyph_info_set_lig_props_for_ligature (hb_glyph_info_t *info,
 433                                            unsigned int lig_id,
 434                                            unsigned int lig_num_comps)
 435 {
 436   info->lig_props() = (lig_id << 5) | IS_LIG_BASE | (lig_num_comps & 0x0F);
 437 }
 438 
 439 static inline void
 440 _hb_glyph_info_set_lig_props_for_mark (hb_glyph_info_t *info,
 441                                        unsigned int lig_id,
 442                                        unsigned int lig_comp)
 443 {
 444   info->lig_props() = (lig_id << 5) | (lig_comp & 0x0F);
 445 }
 446 
 447 static inline void
 448 _hb_glyph_info_set_lig_props_for_component (hb_glyph_info_t *info, unsigned int comp)
 449 {
 450   _hb_glyph_info_set_lig_props_for_mark (info, 0, comp);
 451 }
 452 
 453 static inline unsigned int
 454 _hb_glyph_info_get_lig_id (const hb_glyph_info_t *info)
 455 {
 456   return info->lig_props() >> 5;
 457 }
 458 
 459 static inline bool
 460 _hb_glyph_info_ligated_internal (const hb_glyph_info_t *info)
 461 {
 462   return !!(info->lig_props() & IS_LIG_BASE);
 463 }
 464 
 465 static inline unsigned int
 466 _hb_glyph_info_get_lig_comp (const hb_glyph_info_t *info)
 467 {
 468   if (_hb_glyph_info_ligated_internal (info))
 469     return 0;
 470   else
 471     return info->lig_props() & 0x0F;
 472 }
 473 
 474 static inline unsigned int
 475 _hb_glyph_info_get_lig_num_comps (const hb_glyph_info_t *info)
 476 {
 477   if ((info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE) &&
 478       _hb_glyph_info_ligated_internal (info))
 479     return info->lig_props() & 0x0F;
 480   else
 481     return 1;
 482 }
 483 
 484 static inline uint8_t
 485 _hb_allocate_lig_id (hb_buffer_t *buffer) {
 486   uint8_t lig_id = buffer->next_serial () & 0x07;
 487   if (unlikely (!lig_id))
 488     lig_id = _hb_allocate_lig_id (buffer); /* in case of overflow */
 489   return lig_id;
 490 }
 491 
 492 /* glyph_props: */
 493 
 494 static inline void
 495 _hb_glyph_info_set_glyph_props (hb_glyph_info_t *info, unsigned int props)
 496 {
 497   info->glyph_props() = props;
 498 }
 499 
 500 static inline unsigned int
 501 _hb_glyph_info_get_glyph_props (const hb_glyph_info_t *info)
 502 {
 503   return info->glyph_props();
 504 }
 505 
 506 static inline bool
 507 _hb_glyph_info_is_base_glyph (const hb_glyph_info_t *info)
 508 {
 509   return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH);
 510 }
 511 
 512 static inline bool
 513 _hb_glyph_info_is_ligature (const hb_glyph_info_t *info)
 514 {
 515   return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE);
 516 }
 517 
 518 static inline bool
 519 _hb_glyph_info_is_mark (const hb_glyph_info_t *info)
 520 {
 521   return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK);
 522 }
 523 
 524 static inline bool
 525 _hb_glyph_info_substituted (const hb_glyph_info_t *info)
 526 {
 527   return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED);
 528 }
 529 
 530 static inline bool
 531 _hb_glyph_info_ligated (const hb_glyph_info_t *info)
 532 {
 533   return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATED);
 534 }
 535 
 536 static inline bool
 537 _hb_glyph_info_multiplied (const hb_glyph_info_t *info)
 538 {
 539   return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED);
 540 }
 541 
 542 static inline bool
 543 _hb_glyph_info_ligated_and_didnt_multiply (const hb_glyph_info_t *info)
 544 {
 545   return _hb_glyph_info_ligated (info) && !_hb_glyph_info_multiplied (info);
 546 }
 547 
 548 static inline void
 549 _hb_glyph_info_clear_ligated_and_multiplied (hb_glyph_info_t *info)
 550 {
 551   info->glyph_props() &= ~(HB_OT_LAYOUT_GLYPH_PROPS_LIGATED |
 552                            HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED);
 553 }
 554 
 555 static inline void
 556 _hb_glyph_info_clear_substituted (hb_glyph_info_t *info)
 557 {
 558   info->glyph_props() &= ~(HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED);
 559 }
 560 
 561 
 562 /* Allocation / deallocation. */
 563 
 564 static inline void
 565 _hb_buffer_allocate_unicode_vars (hb_buffer_t *buffer)
 566 {
 567   HB_BUFFER_ALLOCATE_VAR (buffer, unicode_props);
 568 }
 569 
 570 static inline void
 571 _hb_buffer_deallocate_unicode_vars (hb_buffer_t *buffer)
 572 {
 573   HB_BUFFER_DEALLOCATE_VAR (buffer, unicode_props);
 574 }
 575 
 576 static inline void
 577 _hb_buffer_assert_unicode_vars (hb_buffer_t *buffer)
 578 {
 579   HB_BUFFER_ASSERT_VAR (buffer, unicode_props);
 580 }
 581 
 582 static inline void
 583 _hb_buffer_allocate_gsubgpos_vars (hb_buffer_t *buffer)
 584 {
 585   HB_BUFFER_ALLOCATE_VAR (buffer, glyph_props);
 586   HB_BUFFER_ALLOCATE_VAR (buffer, lig_props);
 587   HB_BUFFER_ALLOCATE_VAR (buffer, syllable);
 588 }
 589 
 590 static inline void
 591 _hb_buffer_deallocate_gsubgpos_vars (hb_buffer_t *buffer)
 592 {
 593   HB_BUFFER_DEALLOCATE_VAR (buffer, syllable);
 594   HB_BUFFER_DEALLOCATE_VAR (buffer, lig_props);
 595   HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_props);
 596 }
 597 
 598 static inline void
 599 _hb_buffer_assert_gsubgpos_vars (hb_buffer_t *buffer)
 600 {
 601   HB_BUFFER_ASSERT_VAR (buffer, glyph_props);
 602   HB_BUFFER_ASSERT_VAR (buffer, lig_props);
 603   HB_BUFFER_ASSERT_VAR (buffer, syllable);
 604 }
 605 
 606 /* Make sure no one directly touches our props... */
 607 #undef unicode_props0
 608 #undef unicode_props1
 609 #undef lig_props
 610 #undef glyph_props
 611 
 612 #endif /* HB_OT_LAYOUT_HH */