1 /*
   2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   3  *
   4  * This code is free software; you can redistribute it and/or modify it
   5  * under the terms of the GNU General Public License version 2 only, as
   6  * published by the Free Software Foundation.  Oracle designates this
   7  * particular file as subject to the "Classpath" exception as provided
   8  * by Oracle in the LICENSE file that accompanied this code.
   9  *
  10  * This code is distributed in the hope that it will be useful, but WITHOUT
  11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13  * version 2 for more details (a copy is included in the LICENSE file that
  14  * accompanied this code).
  15  *
  16  * You should have received a copy of the GNU General Public License version
  17  * 2 along with this work; if not, write to the Free Software Foundation,
  18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  19  *
  20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  21  * or visit www.oracle.com if you need additional information or have any
  22  * questions.
  23  */
  24 
  25 // This file is available under and governed by the GNU General Public
  26 // License version 2 only, as published by the Free Software Foundation.
  27 // However, the following notice accompanied the original version of this
  28 // file:
  29 //
  30 /*
  31  * Copyright © 2007,2008,2009  Red Hat, Inc.
  32  * Copyright © 2012,2013  Google, Inc.
  33  *
  34  *  This is part of HarfBuzz, a text shaping library.
  35  *
  36  * Permission is hereby granted, without written agreement and without
  37  * license or royalty fees, to use, copy, modify, and distribute this
  38  * software and its documentation for any purpose, provided that the
  39  * above copyright notice and the following two paragraphs appear in
  40  * all copies of this software.
  41  *
  42  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
  43  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
  44  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
  45  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
  46  * DAMAGE.
  47  *
  48  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
  49  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  50  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  51  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  52  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  53  *
  54  * Red Hat Author(s): Behdad Esfahbod
  55  * Google Author(s): Behdad Esfahbod
  56  */
  57 
  58 #ifndef HB_OT_LAYOUT_PRIVATE_HH
  59 #define HB_OT_LAYOUT_PRIVATE_HH
  60 
  61 #include "hb-private.hh"
  62 
  63 #include "hb-font-private.hh"
  64 #include "hb-buffer-private.hh"
  65 #include "hb-set-private.hh"
  66 
  67 
  68 /* Private API corresponding to hb-ot-layout.h: */
  69 
  70 HB_INTERNAL hb_bool_t
  71 hb_ot_layout_table_find_feature (hb_face_t    *face,
  72                                  hb_tag_t      table_tag,
  73                                  hb_tag_t      feature_tag,
  74                                  unsigned int *feature_index);
  75 
  76 
  77 /*
  78  * GDEF
  79  */
  80 
  81 typedef enum
  82 {
  83   /* The following three match LookupFlags::Ignore* numbers. */
  84   HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH   = 0x02u,
  85   HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE     = 0x04u,
  86   HB_OT_LAYOUT_GLYPH_PROPS_MARK         = 0x08u,
  87 
  88   /* The following are used internally; not derived from GDEF. */
  89   HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED  = 0x10u,
  90   HB_OT_LAYOUT_GLYPH_PROPS_LIGATED      = 0x20u,
  91   HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED   = 0x40u,
  92 
  93   HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE     = HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED |
  94                                           HB_OT_LAYOUT_GLYPH_PROPS_LIGATED |
  95                                           HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED
  96 } hb_ot_layout_glyph_class_mask_t;
  97 
  98 
  99 /*
 100  * GSUB/GPOS
 101  */
 102 
 103 HB_INTERNAL hb_bool_t
 104 hb_ot_layout_lookup_would_substitute_fast (hb_face_t            *face,
 105                                            unsigned int          lookup_index,
 106                                            const hb_codepoint_t *glyphs,
 107                                            unsigned int          glyphs_length,
 108                                            hb_bool_t             zero_context);
 109 
 110 
 111 /* Should be called before all the substitute_lookup's are done. */
 112 HB_INTERNAL void
 113 hb_ot_layout_substitute_start (hb_font_t    *font,
 114                                hb_buffer_t  *buffer);
 115 
 116 
 117 struct hb_ot_layout_lookup_accelerator_t;
 118 
 119 namespace OT {
 120   struct hb_apply_context_t;
 121   struct SubstLookup;
 122 }
 123 
 124 HB_INTERNAL void
 125 hb_ot_layout_substitute_lookup (OT::hb_apply_context_t *c,
 126                                 const OT::SubstLookup &lookup,
 127                                 const hb_ot_layout_lookup_accelerator_t &accel);
 128 
 129 
 130 /* Should be called after all the substitute_lookup's are done */
 131 HB_INTERNAL void
 132 hb_ot_layout_substitute_finish (hb_font_t    *font,
 133                                 hb_buffer_t  *buffer);
 134 
 135 
 136 /* Should be called before all the position_lookup's are done.  Resets positions to zero. */
 137 HB_INTERNAL void
 138 hb_ot_layout_position_start (hb_font_t    *font,
 139                              hb_buffer_t  *buffer);
 140 
 141 /* Should be called after all the position_lookup's are done */
 142 HB_INTERNAL void
 143 hb_ot_layout_position_finish (hb_font_t    *font,
 144                               hb_buffer_t  *buffer);
 145 
 146 
 147 
 148 /*
 149  * hb_ot_layout_t
 150  */
 151 
 152 namespace OT {
 153   struct GDEF;
 154   struct GSUB;
 155   struct GPOS;
 156 }
 157 
 158 struct hb_ot_layout_lookup_accelerator_t
 159 {
 160   template <typename TLookup>
 161   inline void init (const TLookup &lookup)
 162   {
 163     digest.init ();
 164     lookup.add_coverage (&digest);
 165   }
 166 
 167   inline void fini (void)
 168   {
 169   }
 170 
 171   inline bool may_have (hb_codepoint_t g) const {
 172     return digest.may_have (g);
 173   }
 174 
 175   private:
 176   hb_set_digest_t digest;
 177 };
 178 
 179 struct hb_ot_layout_t
 180 {
 181   hb_blob_t *gdef_blob;
 182   hb_blob_t *gsub_blob;
 183   hb_blob_t *gpos_blob;
 184 
 185   const struct OT::GDEF *gdef;
 186   const struct OT::GSUB *gsub;
 187   const struct OT::GPOS *gpos;
 188 
 189   unsigned int gsub_lookup_count;
 190   unsigned int gpos_lookup_count;
 191 
 192   hb_ot_layout_lookup_accelerator_t *gsub_accels;
 193   hb_ot_layout_lookup_accelerator_t *gpos_accels;
 194 };
 195 
 196 
 197 HB_INTERNAL hb_ot_layout_t *
 198 _hb_ot_layout_create (hb_face_t *face);
 199 
 200 HB_INTERNAL void
 201 _hb_ot_layout_destroy (hb_ot_layout_t *layout);
 202 
 203 
 204 #define hb_ot_layout_from_face(face) ((hb_ot_layout_t *) face->shaper_data.ot)
 205 
 206 
 207 /*
 208  * Buffer var routines.
 209  */
 210 
 211 /* buffer var allocations, used during the entire shaping process */
 212 #define unicode_props0()        var2.u8[0]
 213 #define unicode_props1()        var2.u8[1]
 214 
 215 /* buffer var allocations, used during the GSUB/GPOS processing */
 216 #define glyph_props()           var1.u16[0] /* GDEF glyph properties */
 217 #define lig_props()             var1.u8[2] /* GSUB/GPOS ligature tracking */
 218 #define syllable()              var1.u8[3] /* GSUB/GPOS shaping boundaries */
 219 
 220 
 221 /* loop over syllables */
 222 
 223 #define foreach_syllable(buffer, start, end) \
 224   for (unsigned int \
 225        _count = buffer->len, \
 226        start = 0, end = _count ? _next_syllable (buffer, 0) : 0; \
 227        start < _count; \
 228        start = end, end = _next_syllable (buffer, start))
 229 
 230 static inline unsigned int
 231 _next_syllable (hb_buffer_t *buffer, unsigned int start)
 232 {
 233   hb_glyph_info_t *info = buffer->info;
 234   unsigned int count = buffer->len;
 235 
 236   unsigned int syllable = info[start].syllable();
 237   while (++start < count && syllable == info[start].syllable())
 238     ;
 239 
 240   return start;
 241 }
 242 
 243 
 244 /* unicode_props */
 245 
 246 enum {
 247   MASK0_ZWJ       = 0x20u,
 248   MASK0_ZWNJ      = 0x40u,
 249   MASK0_IGNORABLE = 0x80u,
 250   MASK0_GEN_CAT   = 0x1Fu
 251 };
 252 
 253 static inline void
 254 _hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_unicode_funcs_t *unicode)
 255 {
 256   /* XXX This shouldn't be inlined, or at least not while is_default_ignorable() is inline. */
 257   info->unicode_props0() = ((unsigned int) unicode->general_category (info->codepoint)) |
 258                            (unicode->is_default_ignorable (info->codepoint) ? MASK0_IGNORABLE : 0) |
 259                            (info->codepoint == 0x200Cu ? MASK0_ZWNJ : 0) |
 260                            (info->codepoint == 0x200Du ? MASK0_ZWJ : 0);
 261   info->unicode_props1() = unicode->modified_combining_class (info->codepoint);
 262 }
 263 
 264 static inline void
 265 _hb_glyph_info_set_general_category (hb_glyph_info_t *info,
 266                                      hb_unicode_general_category_t gen_cat)
 267 {
 268   info->unicode_props0() = (unsigned int) gen_cat | ((info->unicode_props0()) & ~MASK0_GEN_CAT);
 269 }
 270 
 271 static inline hb_unicode_general_category_t
 272 _hb_glyph_info_get_general_category (const hb_glyph_info_t *info)
 273 {
 274   return (hb_unicode_general_category_t) (info->unicode_props0() & MASK0_GEN_CAT);
 275 }
 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   info->unicode_props1() = modified_class;
 282 }
 283 
 284 static inline unsigned int
 285 _hb_glyph_info_get_modified_combining_class (const hb_glyph_info_t *info)
 286 {
 287   return info->unicode_props1();
 288 }
 289 
 290 static inline bool _hb_glyph_info_ligated (const hb_glyph_info_t *info);
 291 
 292 static inline hb_bool_t
 293 _hb_glyph_info_is_default_ignorable (const hb_glyph_info_t *info)
 294 {
 295   return (info->unicode_props0() & MASK0_IGNORABLE) && !_hb_glyph_info_ligated (info);
 296 }
 297 
 298 static inline hb_bool_t
 299 _hb_glyph_info_is_zwnj (const hb_glyph_info_t *info)
 300 {
 301   return !!(info->unicode_props0() & MASK0_ZWNJ);
 302 }
 303 
 304 static inline hb_bool_t
 305 _hb_glyph_info_is_zwj (const hb_glyph_info_t *info)
 306 {
 307   return !!(info->unicode_props0() & MASK0_ZWJ);
 308 }
 309 
 310 static inline void
 311 _hb_glyph_info_flip_joiners (hb_glyph_info_t *info)
 312 {
 313   info->unicode_props0() ^= MASK0_ZWNJ | MASK0_ZWJ;
 314 }
 315 
 316 /* lig_props: aka lig_id / lig_comp
 317  *
 318  * When a ligature is formed:
 319  *
 320  *   - The ligature glyph and any marks in between all the same newly allocated
 321  *     lig_id,
 322  *   - The ligature glyph will get lig_num_comps set to the number of components
 323  *   - The marks get lig_comp > 0, reflecting which component of the ligature
 324  *     they were applied to.
 325  *   - This is used in GPOS to attach marks to the right component of a ligature
 326  *     in MarkLigPos,
 327  *   - Note that when marks are ligated together, much of the above is skipped
 328  *     and the current lig_id reused.
 329  *
 330  * When a multiple-substitution is done:
 331  *
 332  *   - All resulting glyphs will have lig_id = 0,
 333  *   - The resulting glyphs will have lig_comp = 0, 1, 2, ... respectively.
 334  *   - This is used in GPOS to attach marks to the first component of a
 335  *     multiple substitution in MarkBasePos.
 336  *
 337  * The numbers are also used in GPOS to do mark-to-mark positioning only
 338  * to marks that belong to the same component of the same ligature.
 339  */
 340 
 341 static inline void
 342 _hb_glyph_info_clear_lig_props (hb_glyph_info_t *info)
 343 {
 344   info->lig_props() = 0;
 345 }
 346 
 347 #define IS_LIG_BASE 0x10
 348 
 349 static inline void
 350 _hb_glyph_info_set_lig_props_for_ligature (hb_glyph_info_t *info,
 351                                            unsigned int lig_id,
 352                                            unsigned int lig_num_comps)
 353 {
 354   info->lig_props() = (lig_id << 5) | IS_LIG_BASE | (lig_num_comps & 0x0F);
 355 }
 356 
 357 static inline void
 358 _hb_glyph_info_set_lig_props_for_mark (hb_glyph_info_t *info,
 359                                        unsigned int lig_id,
 360                                        unsigned int lig_comp)
 361 {
 362   info->lig_props() = (lig_id << 5) | (lig_comp & 0x0F);
 363 }
 364 
 365 static inline void
 366 _hb_glyph_info_set_lig_props_for_component (hb_glyph_info_t *info, unsigned int comp)
 367 {
 368   _hb_glyph_info_set_lig_props_for_mark (info, 0, comp);
 369 }
 370 
 371 static inline unsigned int
 372 _hb_glyph_info_get_lig_id (const hb_glyph_info_t *info)
 373 {
 374   return info->lig_props() >> 5;
 375 }
 376 
 377 static inline bool
 378 _hb_glyph_info_ligated_internal (const hb_glyph_info_t *info)
 379 {
 380   return !!(info->lig_props() & IS_LIG_BASE);
 381 }
 382 
 383 static inline unsigned int
 384 _hb_glyph_info_get_lig_comp (const hb_glyph_info_t *info)
 385 {
 386   if (_hb_glyph_info_ligated_internal (info))
 387     return 0;
 388   else
 389     return info->lig_props() & 0x0F;
 390 }
 391 
 392 static inline unsigned int
 393 _hb_glyph_info_get_lig_num_comps (const hb_glyph_info_t *info)
 394 {
 395   if ((info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE) &&
 396       _hb_glyph_info_ligated_internal (info))
 397     return info->lig_props() & 0x0F;
 398   else
 399     return 1;
 400 }
 401 
 402 static inline uint8_t
 403 _hb_allocate_lig_id (hb_buffer_t *buffer) {
 404   uint8_t lig_id = buffer->next_serial () & 0x07;
 405   if (unlikely (!lig_id))
 406     lig_id = _hb_allocate_lig_id (buffer); /* in case of overflow */
 407   return lig_id;
 408 }
 409 
 410 /* glyph_props: */
 411 
 412 static inline void
 413 _hb_glyph_info_set_glyph_props (hb_glyph_info_t *info, unsigned int props)
 414 {
 415   info->glyph_props() = props;
 416 }
 417 
 418 static inline unsigned int
 419 _hb_glyph_info_get_glyph_props (const hb_glyph_info_t *info)
 420 {
 421   return info->glyph_props();
 422 }
 423 
 424 static inline bool
 425 _hb_glyph_info_is_base_glyph (const hb_glyph_info_t *info)
 426 {
 427   return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH);
 428 }
 429 
 430 static inline bool
 431 _hb_glyph_info_is_ligature (const hb_glyph_info_t *info)
 432 {
 433   return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE);
 434 }
 435 
 436 static inline bool
 437 _hb_glyph_info_is_mark (const hb_glyph_info_t *info)
 438 {
 439   return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK);
 440 }
 441 
 442 static inline bool
 443 _hb_glyph_info_substituted (const hb_glyph_info_t *info)
 444 {
 445   return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED);
 446 }
 447 
 448 static inline bool
 449 _hb_glyph_info_ligated (const hb_glyph_info_t *info)
 450 {
 451   return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATED);
 452 }
 453 
 454 static inline bool
 455 _hb_glyph_info_multiplied (const hb_glyph_info_t *info)
 456 {
 457   return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED);
 458 }
 459 
 460 static inline bool
 461 _hb_glyph_info_ligated_and_didnt_multiply (const hb_glyph_info_t *info)
 462 {
 463   return _hb_glyph_info_ligated (info) && !_hb_glyph_info_multiplied (info);
 464 }
 465 
 466 static inline void
 467 _hb_glyph_info_clear_ligated_and_multiplied (hb_glyph_info_t *info)
 468 {
 469   info->glyph_props() &= ~(HB_OT_LAYOUT_GLYPH_PROPS_LIGATED |
 470                            HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED);
 471 }
 472 
 473 static inline void
 474 _hb_glyph_info_clear_substituted_and_ligated_and_multiplied (hb_glyph_info_t *info)
 475 {
 476   info->glyph_props() &= ~(HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED |
 477                            HB_OT_LAYOUT_GLYPH_PROPS_LIGATED |
 478                            HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED);
 479 }
 480 
 481 
 482 /* Allocation / deallocation. */
 483 
 484 static inline void
 485 _hb_buffer_allocate_unicode_vars (hb_buffer_t *buffer)
 486 {
 487   HB_BUFFER_ALLOCATE_VAR (buffer, unicode_props0);
 488   HB_BUFFER_ALLOCATE_VAR (buffer, unicode_props1);
 489 }
 490 
 491 static inline void
 492 _hb_buffer_deallocate_unicode_vars (hb_buffer_t *buffer)
 493 {
 494   HB_BUFFER_DEALLOCATE_VAR (buffer, unicode_props0);
 495   HB_BUFFER_DEALLOCATE_VAR (buffer, unicode_props1);
 496 }
 497 
 498 static inline void
 499 _hb_buffer_assert_unicode_vars (hb_buffer_t *buffer)
 500 {
 501   HB_BUFFER_ASSERT_VAR (buffer, unicode_props0);
 502   HB_BUFFER_ASSERT_VAR (buffer, unicode_props1);
 503 }
 504 
 505 static inline void
 506 _hb_buffer_allocate_gsubgpos_vars (hb_buffer_t *buffer)
 507 {
 508   HB_BUFFER_ALLOCATE_VAR (buffer, glyph_props);
 509   HB_BUFFER_ALLOCATE_VAR (buffer, lig_props);
 510   HB_BUFFER_ALLOCATE_VAR (buffer, syllable);
 511 }
 512 
 513 static inline void
 514 _hb_buffer_deallocate_gsubgpos_vars (hb_buffer_t *buffer)
 515 {
 516   HB_BUFFER_DEALLOCATE_VAR (buffer, syllable);
 517   HB_BUFFER_DEALLOCATE_VAR (buffer, lig_props);
 518   HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_props);
 519 }
 520 
 521 static inline void
 522 _hb_buffer_assert_gsubgpos_vars (hb_buffer_t *buffer)
 523 {
 524   HB_BUFFER_ASSERT_VAR (buffer, glyph_props);
 525   HB_BUFFER_ASSERT_VAR (buffer, lig_props);
 526   HB_BUFFER_ASSERT_VAR (buffer, syllable);
 527 }
 528 
 529 /* Make sure no one directly touches our props... */
 530 #undef unicode_props0
 531 #undef unicode_props1
 532 #undef lig_props
 533 #undef glyph_props
 534 
 535 
 536 #endif /* HB_OT_LAYOUT_PRIVATE_HH */