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 typedef enum
  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 } hb_ot_layout_glyph_class_mask_t;
  68 
  69 
  70 /*
  71  * GSUB/GPOS
  72  */
  73 
  74 HB_INTERNAL hb_bool_t
  75 hb_ot_layout_lookup_would_substitute_fast (hb_face_t            *face,
  76                                            unsigned int          lookup_index,
  77                                            const hb_codepoint_t *glyphs,
  78                                            unsigned int          glyphs_length,
  79                                            hb_bool_t             zero_context);
  80 
  81 
  82 /* Should be called before all the substitute_lookup's are done. */
  83 HB_INTERNAL void
  84 hb_ot_layout_substitute_start (hb_font_t    *font,
  85                                hb_buffer_t  *buffer);
  86 
  87 
  88 struct hb_ot_layout_lookup_accelerator_t;
  89 
  90 namespace OT {
  91   struct hb_apply_context_t;
  92   struct SubstLookup;
  93 }
  94 
  95 HB_INTERNAL void
  96 hb_ot_layout_substitute_lookup (OT::hb_apply_context_t *c,
  97                                 const OT::SubstLookup &lookup,
  98                                 const hb_ot_layout_lookup_accelerator_t &accel);
  99 
 100 
 101 /* Should be called after all the substitute_lookup's are done */
 102 HB_INTERNAL void
 103 hb_ot_layout_substitute_finish (hb_font_t    *font,
 104                                 hb_buffer_t  *buffer);
 105 
 106 
 107 /* Should be called before all the position_lookup's are done.  Resets positions to zero. */
 108 HB_INTERNAL void
 109 hb_ot_layout_position_start (hb_font_t    *font,
 110                              hb_buffer_t  *buffer);
 111 
 112 /* Should be called after all the position_lookup's are done */
 113 HB_INTERNAL void
 114 hb_ot_layout_position_finish (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 }
 128 
 129 struct hb_ot_layout_lookup_accelerator_t
 130 {
 131   template <typename TLookup>
 132   inline void init (const TLookup &lookup)
 133   {
 134     digest.init ();
 135     lookup.add_coverage (&digest);
 136   }
 137 
 138   inline void fini (void)
 139   {
 140   }
 141 
 142   inline bool may_have (hb_codepoint_t g) const {
 143     return digest.may_have (g);
 144   }
 145 
 146   private:
 147   hb_set_digest_t digest;
 148 };
 149 
 150 struct hb_ot_layout_t
 151 {
 152   hb_blob_t *gdef_blob;
 153   hb_blob_t *gsub_blob;
 154   hb_blob_t *gpos_blob;
 155 
 156   const struct OT::GDEF *gdef;
 157   const struct OT::GSUB *gsub;
 158   const struct OT::GPOS *gpos;
 159 
 160   unsigned int gsub_lookup_count;
 161   unsigned int gpos_lookup_count;
 162 
 163   hb_ot_layout_lookup_accelerator_t *gsub_accels;
 164   hb_ot_layout_lookup_accelerator_t *gpos_accels;
 165 };
 166 
 167 
 168 HB_INTERNAL hb_ot_layout_t *
 169 _hb_ot_layout_create (hb_face_t *face);
 170 
 171 HB_INTERNAL void
 172 _hb_ot_layout_destroy (hb_ot_layout_t *layout);
 173 
 174 
 175 #define hb_ot_layout_from_face(face) ((hb_ot_layout_t *) face->shaper_data.ot)
 176 
 177 
 178 /*
 179  * Buffer var routines.
 180  */
 181 
 182 /* buffer var allocations, used during the entire shaping process */
 183 #define unicode_props0()        var2.u8[0]
 184 #define unicode_props1()        var2.u8[1]
 185 
 186 /* buffer var allocations, used during the GSUB/GPOS processing */
 187 #define glyph_props()           var1.u16[0] /* GDEF glyph properties */
 188 #define lig_props()             var1.u8[2] /* GSUB/GPOS ligature tracking */
 189 #define syllable()              var1.u8[3] /* GSUB/GPOS shaping boundaries */
 190 
 191 
 192 /* loop over syllables */
 193 
 194 #define foreach_syllable(buffer, start, end) \
 195   for (unsigned int \
 196        _count = buffer->len, \
 197        start = 0, end = _count ? _next_syllable (buffer, 0) : 0; \
 198        start < _count; \
 199        start = end, end = _next_syllable (buffer, start))
 200 
 201 static inline unsigned int
 202 _next_syllable (hb_buffer_t *buffer, unsigned int start)
 203 {
 204   hb_glyph_info_t *info = buffer->info;
 205   unsigned int count = buffer->len;
 206 
 207   unsigned int syllable = info[start].syllable();
 208   while (++start < count && syllable == info[start].syllable())
 209     ;
 210 
 211   return start;
 212 }
 213 
 214 
 215 /* unicode_props */
 216 
 217 enum {
 218   MASK0_ZWJ       = 0x20u,
 219   MASK0_ZWNJ      = 0x40u,
 220   MASK0_IGNORABLE = 0x80u,
 221   MASK0_GEN_CAT   = 0x1Fu
 222 };
 223 
 224 static inline void
 225 _hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_unicode_funcs_t *unicode)
 226 {
 227   /* XXX This shouldn't be inlined, or at least not while is_default_ignorable() is inline. */
 228   info->unicode_props0() = ((unsigned int) unicode->general_category (info->codepoint)) |
 229                            (unicode->is_default_ignorable (info->codepoint) ? MASK0_IGNORABLE : 0) |
 230                            (info->codepoint == 0x200Cu ? MASK0_ZWNJ : 0) |
 231                            (info->codepoint == 0x200Du ? MASK0_ZWJ : 0);
 232   info->unicode_props1() = unicode->modified_combining_class (info->codepoint);
 233 }
 234 
 235 static inline void
 236 _hb_glyph_info_set_general_category (hb_glyph_info_t *info,
 237                                      hb_unicode_general_category_t gen_cat)
 238 {
 239   info->unicode_props0() = (unsigned int) gen_cat | ((info->unicode_props0()) & ~MASK0_GEN_CAT);
 240 }
 241 
 242 static inline hb_unicode_general_category_t
 243 _hb_glyph_info_get_general_category (const hb_glyph_info_t *info)
 244 {
 245   return (hb_unicode_general_category_t) (info->unicode_props0() & MASK0_GEN_CAT);
 246 }
 247 
 248 static inline void
 249 _hb_glyph_info_set_modified_combining_class (hb_glyph_info_t *info,
 250                                              unsigned int modified_class)
 251 {
 252   info->unicode_props1() = modified_class;
 253 }
 254 
 255 static inline unsigned int
 256 _hb_glyph_info_get_modified_combining_class (const hb_glyph_info_t *info)
 257 {
 258   return info->unicode_props1();
 259 }
 260 
 261 static inline bool _hb_glyph_info_ligated (const hb_glyph_info_t *info);
 262 
 263 static inline hb_bool_t
 264 _hb_glyph_info_is_default_ignorable (const hb_glyph_info_t *info)
 265 {
 266   return (info->unicode_props0() & MASK0_IGNORABLE) && !_hb_glyph_info_ligated (info);
 267 }
 268 
 269 static inline hb_bool_t
 270 _hb_glyph_info_is_zwnj (const hb_glyph_info_t *info)
 271 {
 272   return !!(info->unicode_props0() & MASK0_ZWNJ);
 273 }
 274 
 275 static inline hb_bool_t
 276 _hb_glyph_info_is_zwj (const hb_glyph_info_t *info)
 277 {
 278   return !!(info->unicode_props0() & MASK0_ZWJ);
 279 }
 280 
 281 static inline void
 282 _hb_glyph_info_flip_joiners (hb_glyph_info_t *info)
 283 {
 284   info->unicode_props0() ^= MASK0_ZWNJ | MASK0_ZWJ;
 285 }
 286 
 287 /* lig_props: aka lig_id / lig_comp
 288  *
 289  * When a ligature is formed:
 290  *
 291  *   - The ligature glyph and any marks in between all the same newly allocated
 292  *     lig_id,
 293  *   - The ligature glyph will get lig_num_comps set to the number of components
 294  *   - The marks get lig_comp > 0, reflecting which component of the ligature
 295  *     they were applied to.
 296  *   - This is used in GPOS to attach marks to the right component of a ligature
 297  *     in MarkLigPos,
 298  *   - Note that when marks are ligated together, much of the above is skipped
 299  *     and the current lig_id reused.
 300  *
 301  * When a multiple-substitution is done:
 302  *
 303  *   - All resulting glyphs will have lig_id = 0,
 304  *   - The resulting glyphs will have lig_comp = 0, 1, 2, ... respectively.
 305  *   - This is used in GPOS to attach marks to the first component of a
 306  *     multiple substitution in MarkBasePos.
 307  *
 308  * The numbers are also used in GPOS to do mark-to-mark positioning only
 309  * to marks that belong to the same component of the same ligature.
 310  */
 311 
 312 static inline void
 313 _hb_glyph_info_clear_lig_props (hb_glyph_info_t *info)
 314 {
 315   info->lig_props() = 0;
 316 }
 317 
 318 #define IS_LIG_BASE 0x10
 319 
 320 static inline void
 321 _hb_glyph_info_set_lig_props_for_ligature (hb_glyph_info_t *info,
 322                                            unsigned int lig_id,
 323                                            unsigned int lig_num_comps)
 324 {
 325   info->lig_props() = (lig_id << 5) | IS_LIG_BASE | (lig_num_comps & 0x0F);
 326 }
 327 
 328 static inline void
 329 _hb_glyph_info_set_lig_props_for_mark (hb_glyph_info_t *info,
 330                                        unsigned int lig_id,
 331                                        unsigned int lig_comp)
 332 {
 333   info->lig_props() = (lig_id << 5) | (lig_comp & 0x0F);
 334 }
 335 
 336 static inline void
 337 _hb_glyph_info_set_lig_props_for_component (hb_glyph_info_t *info, unsigned int comp)
 338 {
 339   _hb_glyph_info_set_lig_props_for_mark (info, 0, comp);
 340 }
 341 
 342 static inline unsigned int
 343 _hb_glyph_info_get_lig_id (const hb_glyph_info_t *info)
 344 {
 345   return info->lig_props() >> 5;
 346 }
 347 
 348 static inline bool
 349 _hb_glyph_info_ligated_internal (const hb_glyph_info_t *info)
 350 {
 351   return !!(info->lig_props() & IS_LIG_BASE);
 352 }
 353 
 354 static inline unsigned int
 355 _hb_glyph_info_get_lig_comp (const hb_glyph_info_t *info)
 356 {
 357   if (_hb_glyph_info_ligated_internal (info))
 358     return 0;
 359   else
 360     return info->lig_props() & 0x0F;
 361 }
 362 
 363 static inline unsigned int
 364 _hb_glyph_info_get_lig_num_comps (const hb_glyph_info_t *info)
 365 {
 366   if ((info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE) &&
 367       _hb_glyph_info_ligated_internal (info))
 368     return info->lig_props() & 0x0F;
 369   else
 370     return 1;
 371 }
 372 
 373 static inline uint8_t
 374 _hb_allocate_lig_id (hb_buffer_t *buffer) {
 375   uint8_t lig_id = buffer->next_serial () & 0x07;
 376   if (unlikely (!lig_id))
 377     lig_id = _hb_allocate_lig_id (buffer); /* in case of overflow */
 378   return lig_id;
 379 }
 380 
 381 /* glyph_props: */
 382 
 383 static inline void
 384 _hb_glyph_info_set_glyph_props (hb_glyph_info_t *info, unsigned int props)
 385 {
 386   info->glyph_props() = props;
 387 }
 388 
 389 static inline unsigned int
 390 _hb_glyph_info_get_glyph_props (const hb_glyph_info_t *info)
 391 {
 392   return info->glyph_props();
 393 }
 394 
 395 static inline bool
 396 _hb_glyph_info_is_base_glyph (const hb_glyph_info_t *info)
 397 {
 398   return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH);
 399 }
 400 
 401 static inline bool
 402 _hb_glyph_info_is_ligature (const hb_glyph_info_t *info)
 403 {
 404   return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE);
 405 }
 406 
 407 static inline bool
 408 _hb_glyph_info_is_mark (const hb_glyph_info_t *info)
 409 {
 410   return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK);
 411 }
 412 
 413 static inline bool
 414 _hb_glyph_info_substituted (const hb_glyph_info_t *info)
 415 {
 416   return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED);
 417 }
 418 
 419 static inline bool
 420 _hb_glyph_info_ligated (const hb_glyph_info_t *info)
 421 {
 422   return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATED);
 423 }
 424 
 425 static inline bool
 426 _hb_glyph_info_multiplied (const hb_glyph_info_t *info)
 427 {
 428   return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED);
 429 }
 430 
 431 static inline bool
 432 _hb_glyph_info_ligated_and_didnt_multiply (const hb_glyph_info_t *info)
 433 {
 434   return _hb_glyph_info_ligated (info) && !_hb_glyph_info_multiplied (info);
 435 }
 436 
 437 static inline void
 438 _hb_glyph_info_clear_ligated_and_multiplied (hb_glyph_info_t *info)
 439 {
 440   info->glyph_props() &= ~(HB_OT_LAYOUT_GLYPH_PROPS_LIGATED |
 441                            HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED);
 442 }
 443 
 444 static inline void
 445 _hb_glyph_info_clear_substituted_and_ligated_and_multiplied (hb_glyph_info_t *info)
 446 {
 447   info->glyph_props() &= ~(HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED |
 448                            HB_OT_LAYOUT_GLYPH_PROPS_LIGATED |
 449                            HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED);
 450 }
 451 
 452 
 453 /* Allocation / deallocation. */
 454 
 455 static inline void
 456 _hb_buffer_allocate_unicode_vars (hb_buffer_t *buffer)
 457 {
 458   HB_BUFFER_ALLOCATE_VAR (buffer, unicode_props0);
 459   HB_BUFFER_ALLOCATE_VAR (buffer, unicode_props1);
 460 }
 461 
 462 static inline void
 463 _hb_buffer_deallocate_unicode_vars (hb_buffer_t *buffer)
 464 {
 465   HB_BUFFER_DEALLOCATE_VAR (buffer, unicode_props0);
 466   HB_BUFFER_DEALLOCATE_VAR (buffer, unicode_props1);
 467 }
 468 
 469 static inline void
 470 _hb_buffer_assert_unicode_vars (hb_buffer_t *buffer)
 471 {
 472   HB_BUFFER_ASSERT_VAR (buffer, unicode_props0);
 473   HB_BUFFER_ASSERT_VAR (buffer, unicode_props1);
 474 }
 475 
 476 static inline void
 477 _hb_buffer_allocate_gsubgpos_vars (hb_buffer_t *buffer)
 478 {
 479   HB_BUFFER_ALLOCATE_VAR (buffer, glyph_props);
 480   HB_BUFFER_ALLOCATE_VAR (buffer, lig_props);
 481   HB_BUFFER_ALLOCATE_VAR (buffer, syllable);
 482 }
 483 
 484 static inline void
 485 _hb_buffer_deallocate_gsubgpos_vars (hb_buffer_t *buffer)
 486 {
 487   HB_BUFFER_DEALLOCATE_VAR (buffer, syllable);
 488   HB_BUFFER_DEALLOCATE_VAR (buffer, lig_props);
 489   HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_props);
 490 }
 491 
 492 static inline void
 493 _hb_buffer_assert_gsubgpos_vars (hb_buffer_t *buffer)
 494 {
 495   HB_BUFFER_ASSERT_VAR (buffer, glyph_props);
 496   HB_BUFFER_ASSERT_VAR (buffer, lig_props);
 497   HB_BUFFER_ASSERT_VAR (buffer, syllable);
 498 }
 499 
 500 /* Make sure no one directly touches our props... */
 501 #undef unicode_props0
 502 #undef unicode_props1
 503 #undef lig_props
 504 #undef glyph_props
 505 
 506 
 507 #endif /* HB_OT_LAYOUT_PRIVATE_HH */