1 /*
   2  * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
   3  * Copyright © 2010,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_GPOS_TABLE_HH
  30 #define HB_OT_LAYOUT_GPOS_TABLE_HH
  31 
  32 #include "hb-ot-layout-gsubgpos.hh"
  33 
  34 
  35 namespace OT {
  36 
  37 
  38 /* buffer **position** var allocations */
  39 #define attach_chain() var.i16[0] /* glyph to which this attaches to, relative to current glyphs; negative for going back, positive for forward. */
  40 #define attach_type() var.u8[2] /* attachment type */
  41 /* Note! if attach_chain() is zero, the value of attach_type() is irrelevant. */
  42 
  43 enum attach_type_t {
  44   ATTACH_TYPE_NONE      = 0X00,
  45 
  46   /* Each attachment should be either a mark or a cursive; can't be both. */
  47   ATTACH_TYPE_MARK      = 0X01,
  48   ATTACH_TYPE_CURSIVE   = 0X02,
  49 };
  50 
  51 
  52 /* Shared Tables: ValueRecord, Anchor Table, and MarkArray */
  53 
  54 typedef HBUINT16 Value;
  55 
  56 typedef UnsizedArrayOf<Value> ValueRecord;
  57 
  58 struct ValueFormat : HBUINT16
  59 {
  60   enum Flags {
  61     xPlacement  = 0x0001u,      /* Includes horizontal adjustment for placement */
  62     yPlacement  = 0x0002u,      /* Includes vertical adjustment for placement */
  63     xAdvance    = 0x0004u,      /* Includes horizontal adjustment for advance */
  64     yAdvance    = 0x0008u,      /* Includes vertical adjustment for advance */
  65     xPlaDevice  = 0x0010u,      /* Includes horizontal Device table for placement */
  66     yPlaDevice  = 0x0020u,      /* Includes vertical Device table for placement */
  67     xAdvDevice  = 0x0040u,      /* Includes horizontal Device table for advance */
  68     yAdvDevice  = 0x0080u,      /* Includes vertical Device table for advance */
  69     ignored     = 0x0F00u,      /* Was used in TrueType Open for MM fonts */
  70     reserved    = 0xF000u,      /* For future use */
  71 
  72     devices     = 0x00F0u       /* Mask for having any Device table */
  73   };
  74 
  75 /* All fields are options.  Only those available advance the value pointer. */
  76 #if 0
  77   HBINT16               xPlacement;             /* Horizontal adjustment for
  78                                          * placement--in design units */
  79   HBINT16               yPlacement;             /* Vertical adjustment for
  80                                          * placement--in design units */
  81   HBINT16               xAdvance;               /* Horizontal adjustment for
  82                                          * advance--in design units (only used
  83                                          * for horizontal writing) */
  84   HBINT16               yAdvance;               /* Vertical adjustment for advance--in
  85                                          * design units (only used for vertical
  86                                          * writing) */
  87   OffsetTo<Device>      xPlaDevice;     /* Offset to Device table for
  88                                          * horizontal placement--measured from
  89                                          * beginning of PosTable (may be NULL) */
  90   OffsetTo<Device>      yPlaDevice;     /* Offset to Device table for vertical
  91                                          * placement--measured from beginning
  92                                          * of PosTable (may be NULL) */
  93   OffsetTo<Device>      xAdvDevice;     /* Offset to Device table for
  94                                          * horizontal advance--measured from
  95                                          * beginning of PosTable (may be NULL) */
  96   OffsetTo<Device>      yAdvDevice;     /* Offset to Device table for vertical
  97                                          * advance--measured from beginning of
  98                                          * PosTable (may be NULL) */
  99 #endif
 100 
 101   unsigned int get_len () const  { return hb_popcount ((unsigned int) *this); }
 102   unsigned int get_size () const { return get_len () * Value::static_size; }
 103 
 104   bool apply_value (hb_ot_apply_context_t   *c,
 105                     const void           *base,
 106                     const Value          *values,
 107                     hb_glyph_position_t  &glyph_pos) const
 108   {
 109     bool ret = false;
 110     unsigned int format = *this;
 111     if (!format) return ret;
 112 
 113     hb_font_t *font = c->font;
 114     bool horizontal = HB_DIRECTION_IS_HORIZONTAL (c->direction);
 115 
 116     if (format & xPlacement) glyph_pos.x_offset  += font->em_scale_x (get_short (values++, &ret));
 117     if (format & yPlacement) glyph_pos.y_offset  += font->em_scale_y (get_short (values++, &ret));
 118     if (format & xAdvance) {
 119       if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values, &ret));
 120       values++;
 121     }
 122     /* y_advance values grow downward but font-space grows upward, hence negation */
 123     if (format & yAdvance) {
 124       if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values, &ret));
 125       values++;
 126     }
 127 
 128     if (!has_device ()) return ret;
 129 
 130     bool use_x_device = font->x_ppem || font->num_coords;
 131     bool use_y_device = font->y_ppem || font->num_coords;
 132 
 133     if (!use_x_device && !use_y_device) return ret;
 134 
 135     const VariationStore &store = c->var_store;
 136 
 137     /* pixel -> fractional pixel */
 138     if (format & xPlaDevice) {
 139       if (use_x_device) glyph_pos.x_offset  += (base + get_device (values, &ret)).get_x_delta (font, store);
 140       values++;
 141     }
 142     if (format & yPlaDevice) {
 143       if (use_y_device) glyph_pos.y_offset  += (base + get_device (values, &ret)).get_y_delta (font, store);
 144       values++;
 145     }
 146     if (format & xAdvDevice) {
 147       if (horizontal && use_x_device) glyph_pos.x_advance += (base + get_device (values, &ret)).get_x_delta (font, store);
 148       values++;
 149     }
 150     if (format & yAdvDevice) {
 151       /* y_advance values grow downward but font-space grows upward, hence negation */
 152       if (!horizontal && use_y_device) glyph_pos.y_advance -= (base + get_device (values, &ret)).get_y_delta (font, store);
 153       values++;
 154     }
 155     return ret;
 156   }
 157 
 158   private:
 159   bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const
 160   {
 161     unsigned int format = *this;
 162 
 163     if (format & xPlacement) values++;
 164     if (format & yPlacement) values++;
 165     if (format & xAdvance)   values++;
 166     if (format & yAdvance)   values++;
 167 
 168     if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
 169     if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
 170     if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
 171     if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
 172 
 173     return true;
 174   }
 175 
 176   static OffsetTo<Device>& get_device (Value* value)
 177   { return *CastP<OffsetTo<Device> > (value); }
 178   static const OffsetTo<Device>& get_device (const Value* value, bool *worked=nullptr)
 179   {
 180     if (worked) *worked |= bool (*value);
 181     return *CastP<OffsetTo<Device> > (value);
 182   }
 183 
 184   static const HBINT16& get_short (const Value* value, bool *worked=nullptr)
 185   {
 186     if (worked) *worked |= bool (*value);
 187     return *CastP<HBINT16> (value);
 188   }
 189 
 190   public:
 191 
 192   bool has_device () const
 193   {
 194     unsigned int format = *this;
 195     return (format & devices) != 0;
 196   }
 197 
 198   bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const
 199   {
 200     TRACE_SANITIZE (this);
 201     return_trace (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values)));
 202   }
 203 
 204   bool sanitize_values (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count) const
 205   {
 206     TRACE_SANITIZE (this);
 207     unsigned int len = get_len ();
 208 
 209     if (!c->check_range (values, count, get_size ())) return_trace (false);
 210 
 211     if (!has_device ()) return_trace (true);
 212 
 213     for (unsigned int i = 0; i < count; i++) {
 214       if (!sanitize_value_devices (c, base, values))
 215         return_trace (false);
 216       values += len;
 217     }
 218 
 219     return_trace (true);
 220   }
 221 
 222   /* Just sanitize referenced Device tables.  Doesn't check the values themselves. */
 223   bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count, unsigned int stride) const
 224   {
 225     TRACE_SANITIZE (this);
 226 
 227     if (!has_device ()) return_trace (true);
 228 
 229     for (unsigned int i = 0; i < count; i++) {
 230       if (!sanitize_value_devices (c, base, values))
 231         return_trace (false);
 232       values += stride;
 233     }
 234 
 235     return_trace (true);
 236   }
 237 };
 238 
 239 
 240 struct AnchorFormat1
 241 {
 242   void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED,
 243                    float *x, float *y) const
 244   {
 245     hb_font_t *font = c->font;
 246     *x = font->em_fscale_x (xCoordinate);
 247     *y = font->em_fscale_y (yCoordinate);
 248   }
 249 
 250   bool sanitize (hb_sanitize_context_t *c) const
 251   {
 252     TRACE_SANITIZE (this);
 253     return_trace (c->check_struct (this));
 254   }
 255 
 256   protected:
 257   HBUINT16      format;                 /* Format identifier--format = 1 */
 258   FWORD         xCoordinate;            /* Horizontal value--in design units */
 259   FWORD         yCoordinate;            /* Vertical value--in design units */
 260   public:
 261   DEFINE_SIZE_STATIC (6);
 262 };
 263 
 264 struct AnchorFormat2
 265 {
 266   void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id,
 267                    float *x, float *y) const
 268   {
 269     hb_font_t *font = c->font;
 270     unsigned int x_ppem = font->x_ppem;
 271     unsigned int y_ppem = font->y_ppem;
 272     hb_position_t cx = 0, cy = 0;
 273     bool ret;
 274 
 275     ret = (x_ppem || y_ppem) &&
 276           font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
 277     *x = ret && x_ppem ? cx : font->em_fscale_x (xCoordinate);
 278     *y = ret && y_ppem ? cy : font->em_fscale_y (yCoordinate);
 279   }
 280 
 281   bool sanitize (hb_sanitize_context_t *c) const
 282   {
 283     TRACE_SANITIZE (this);
 284     return_trace (c->check_struct (this));
 285   }
 286 
 287   protected:
 288   HBUINT16      format;                 /* Format identifier--format = 2 */
 289   FWORD         xCoordinate;            /* Horizontal value--in design units */
 290   FWORD         yCoordinate;            /* Vertical value--in design units */
 291   HBUINT16      anchorPoint;            /* Index to glyph contour point */
 292   public:
 293   DEFINE_SIZE_STATIC (8);
 294 };
 295 
 296 struct AnchorFormat3
 297 {
 298   void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED,
 299                    float *x, float *y) const
 300   {
 301     hb_font_t *font = c->font;
 302     *x = font->em_fscale_x (xCoordinate);
 303     *y = font->em_fscale_y (yCoordinate);
 304 
 305     if (font->x_ppem || font->num_coords)
 306       *x += (this+xDeviceTable).get_x_delta (font, c->var_store);
 307     if (font->y_ppem || font->num_coords)
 308       *y += (this+yDeviceTable).get_y_delta (font, c->var_store);
 309   }
 310 
 311   bool sanitize (hb_sanitize_context_t *c) const
 312   {
 313     TRACE_SANITIZE (this);
 314     return_trace (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
 315   }
 316 
 317   protected:
 318   HBUINT16      format;                 /* Format identifier--format = 3 */
 319   FWORD         xCoordinate;            /* Horizontal value--in design units */
 320   FWORD         yCoordinate;            /* Vertical value--in design units */
 321   OffsetTo<Device>
 322                 xDeviceTable;           /* Offset to Device table for X
 323                                          * coordinate-- from beginning of
 324                                          * Anchor table (may be NULL) */
 325   OffsetTo<Device>
 326                 yDeviceTable;           /* Offset to Device table for Y
 327                                          * coordinate-- from beginning of
 328                                          * Anchor table (may be NULL) */
 329   public:
 330   DEFINE_SIZE_STATIC (10);
 331 };
 332 
 333 struct Anchor
 334 {
 335   void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id,
 336                    float *x, float *y) const
 337   {
 338     *x = *y = 0;
 339     switch (u.format) {
 340     case 1: u.format1.get_anchor (c, glyph_id, x, y); return;
 341     case 2: u.format2.get_anchor (c, glyph_id, x, y); return;
 342     case 3: u.format3.get_anchor (c, glyph_id, x, y); return;
 343     default:                                          return;
 344     }
 345   }
 346 
 347   bool sanitize (hb_sanitize_context_t *c) const
 348   {
 349     TRACE_SANITIZE (this);
 350     if (!u.format.sanitize (c)) return_trace (false);
 351     switch (u.format) {
 352     case 1: return_trace (u.format1.sanitize (c));
 353     case 2: return_trace (u.format2.sanitize (c));
 354     case 3: return_trace (u.format3.sanitize (c));
 355     default:return_trace (true);
 356     }
 357   }
 358 
 359   protected:
 360   union {
 361   HBUINT16              format;         /* Format identifier */
 362   AnchorFormat1         format1;
 363   AnchorFormat2         format2;
 364   AnchorFormat3         format3;
 365   } u;
 366   public:
 367   DEFINE_SIZE_UNION (2, format);
 368 };
 369 
 370 
 371 struct AnchorMatrix
 372 {
 373   const Anchor& get_anchor (unsigned int row, unsigned int col,
 374                             unsigned int cols, bool *found) const
 375   {
 376     *found = false;
 377     if (unlikely (row >= rows || col >= cols)) return Null(Anchor);
 378     *found = !matrixZ[row * cols + col].is_null ();
 379     return this+matrixZ[row * cols + col];
 380   }
 381 
 382   bool sanitize (hb_sanitize_context_t *c, unsigned int cols) const
 383   {
 384     TRACE_SANITIZE (this);
 385     if (!c->check_struct (this)) return_trace (false);
 386     if (unlikely (hb_unsigned_mul_overflows (rows, cols))) return_trace (false);
 387     unsigned int count = rows * cols;
 388     if (!c->check_array (matrixZ.arrayZ, count)) return_trace (false);
 389     for (unsigned int i = 0; i < count; i++)
 390       if (!matrixZ[i].sanitize (c, this)) return_trace (false);
 391     return_trace (true);
 392   }
 393 
 394   HBUINT16      rows;                   /* Number of rows */
 395   protected:
 396   UnsizedArrayOf<OffsetTo<Anchor> >
 397                 matrixZ;                /* Matrix of offsets to Anchor tables--
 398                                          * from beginning of AnchorMatrix table */
 399   public:
 400   DEFINE_SIZE_ARRAY (2, matrixZ);
 401 };
 402 
 403 
 404 struct MarkRecord
 405 {
 406   friend struct MarkArray;
 407 
 408   bool sanitize (hb_sanitize_context_t *c, const void *base) const
 409   {
 410     TRACE_SANITIZE (this);
 411     return_trace (c->check_struct (this) && markAnchor.sanitize (c, base));
 412   }
 413 
 414   protected:
 415   HBUINT16      klass;                  /* Class defined for this mark */
 416   OffsetTo<Anchor>
 417                 markAnchor;             /* Offset to Anchor table--from
 418                                          * beginning of MarkArray table */
 419   public:
 420   DEFINE_SIZE_STATIC (4);
 421 };
 422 
 423 struct MarkArray : ArrayOf<MarkRecord>  /* Array of MarkRecords--in Coverage order */
 424 {
 425   bool apply (hb_ot_apply_context_t *c,
 426               unsigned int mark_index, unsigned int glyph_index,
 427               const AnchorMatrix &anchors, unsigned int class_count,
 428               unsigned int glyph_pos) const
 429   {
 430     TRACE_APPLY (this);
 431     hb_buffer_t *buffer = c->buffer;
 432     const MarkRecord &record = ArrayOf<MarkRecord>::operator[](mark_index);
 433     unsigned int mark_class = record.klass;
 434 
 435     const Anchor& mark_anchor = this + record.markAnchor;
 436     bool found;
 437     const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count, &found);
 438     /* If this subtable doesn't have an anchor for this base and this class,
 439      * return false such that the subsequent subtables have a chance at it. */
 440     if (unlikely (!found)) return_trace (false);
 441 
 442     float mark_x, mark_y, base_x, base_y;
 443 
 444     buffer->unsafe_to_break (glyph_pos, buffer->idx);
 445     mark_anchor.get_anchor (c, buffer->cur().codepoint, &mark_x, &mark_y);
 446     glyph_anchor.get_anchor (c, buffer->info[glyph_pos].codepoint, &base_x, &base_y);
 447 
 448     hb_glyph_position_t &o = buffer->cur_pos();
 449     o.x_offset = round (base_x - mark_x);
 450     o.y_offset = round (base_y - mark_y);
 451     o.attach_type() = ATTACH_TYPE_MARK;
 452     o.attach_chain() = (int) glyph_pos - (int) buffer->idx;
 453     buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
 454 
 455     buffer->idx++;
 456     return_trace (true);
 457   }
 458 
 459   bool sanitize (hb_sanitize_context_t *c) const
 460   {
 461     TRACE_SANITIZE (this);
 462     return_trace (ArrayOf<MarkRecord>::sanitize (c, this));
 463   }
 464 };
 465 
 466 
 467 /* Lookups */
 468 
 469 struct SinglePosFormat1
 470 {
 471   bool intersects (const hb_set_t *glyphs) const
 472   { return (this+coverage).intersects (glyphs); }
 473 
 474   void collect_glyphs (hb_collect_glyphs_context_t *c) const
 475   { if (unlikely (!(this+coverage).add_coverage (c->input))) return; }
 476 
 477   const Coverage &get_coverage () const { return this+coverage; }
 478 
 479   bool apply (hb_ot_apply_context_t *c) const
 480   {
 481     TRACE_APPLY (this);
 482     hb_buffer_t *buffer = c->buffer;
 483     unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
 484     if (likely (index == NOT_COVERED)) return_trace (false);
 485 
 486     valueFormat.apply_value (c, this, values, buffer->cur_pos());
 487 
 488     buffer->idx++;
 489     return_trace (true);
 490   }
 491 
 492   bool subset (hb_subset_context_t *c) const
 493   {
 494     TRACE_SUBSET (this);
 495     // TODO(subset)
 496     return_trace (false);
 497   }
 498 
 499   bool sanitize (hb_sanitize_context_t *c) const
 500   {
 501     TRACE_SANITIZE (this);
 502     return_trace (c->check_struct (this) &&
 503                   coverage.sanitize (c, this) &&
 504                   valueFormat.sanitize_value (c, this, values));
 505   }
 506 
 507   protected:
 508   HBUINT16      format;                 /* Format identifier--format = 1 */
 509   OffsetTo<Coverage>
 510                 coverage;               /* Offset to Coverage table--from
 511                                          * beginning of subtable */
 512   ValueFormat   valueFormat;            /* Defines the types of data in the
 513                                          * ValueRecord */
 514   ValueRecord   values;                 /* Defines positioning
 515                                          * value(s)--applied to all glyphs in
 516                                          * the Coverage table */
 517   public:
 518   DEFINE_SIZE_ARRAY (6, values);
 519 };
 520 
 521 struct SinglePosFormat2
 522 {
 523   bool intersects (const hb_set_t *glyphs) const
 524   { return (this+coverage).intersects (glyphs); }
 525 
 526   void collect_glyphs (hb_collect_glyphs_context_t *c) const
 527   { if (unlikely (!(this+coverage).add_coverage (c->input))) return; }
 528 
 529   const Coverage &get_coverage () const { return this+coverage; }
 530 
 531   bool apply (hb_ot_apply_context_t *c) const
 532   {
 533     TRACE_APPLY (this);
 534     hb_buffer_t *buffer = c->buffer;
 535     unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
 536     if (likely (index == NOT_COVERED)) return_trace (false);
 537 
 538     if (likely (index >= valueCount)) return_trace (false);
 539 
 540     valueFormat.apply_value (c, this,
 541                              &values[index * valueFormat.get_len ()],
 542                              buffer->cur_pos());
 543 
 544     buffer->idx++;
 545     return_trace (true);
 546   }
 547 
 548   bool subset (hb_subset_context_t *c) const
 549   {
 550     TRACE_SUBSET (this);
 551     // TODO(subset)
 552     return_trace (false);
 553   }
 554 
 555   bool sanitize (hb_sanitize_context_t *c) const
 556   {
 557     TRACE_SANITIZE (this);
 558     return_trace (c->check_struct (this) &&
 559                   coverage.sanitize (c, this) &&
 560                   valueFormat.sanitize_values (c, this, values, valueCount));
 561   }
 562 
 563   protected:
 564   HBUINT16      format;                 /* Format identifier--format = 2 */
 565   OffsetTo<Coverage>
 566                 coverage;               /* Offset to Coverage table--from
 567                                          * beginning of subtable */
 568   ValueFormat   valueFormat;            /* Defines the types of data in the
 569                                          * ValueRecord */
 570   HBUINT16      valueCount;             /* Number of ValueRecords */
 571   ValueRecord   values;                 /* Array of ValueRecords--positioning
 572                                          * values applied to glyphs */
 573   public:
 574   DEFINE_SIZE_ARRAY (8, values);
 575 };
 576 
 577 struct SinglePos
 578 {
 579   template <typename context_t>
 580   typename context_t::return_t dispatch (context_t *c) const
 581   {
 582     TRACE_DISPATCH (this, u.format);
 583     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
 584     switch (u.format) {
 585     case 1: return_trace (c->dispatch (u.format1));
 586     case 2: return_trace (c->dispatch (u.format2));
 587     default:return_trace (c->default_return_value ());
 588     }
 589   }
 590 
 591   protected:
 592   union {
 593   HBUINT16              format;         /* Format identifier */
 594   SinglePosFormat1      format1;
 595   SinglePosFormat2      format2;
 596   } u;
 597 };
 598 
 599 
 600 struct PairValueRecord
 601 {
 602   friend struct PairSet;
 603 
 604   protected:
 605   GlyphID       secondGlyph;            /* GlyphID of second glyph in the
 606                                          * pair--first glyph is listed in the
 607                                          * Coverage table */
 608   ValueRecord   values;                 /* Positioning data for the first glyph
 609                                          * followed by for second glyph */
 610   public:
 611   DEFINE_SIZE_ARRAY (2, values);
 612 };
 613 
 614 struct PairSet
 615 {
 616   friend struct PairPosFormat1;
 617 
 618   bool intersects (const hb_set_t *glyphs,
 619                           const ValueFormat *valueFormats) const
 620   {
 621     unsigned int len1 = valueFormats[0].get_len ();
 622     unsigned int len2 = valueFormats[1].get_len ();
 623     unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
 624 
 625     const PairValueRecord *record = &firstPairValueRecord;
 626     unsigned int count = len;
 627     for (unsigned int i = 0; i < count; i++)
 628     {
 629       if (glyphs->has (record->secondGlyph))
 630         return true;
 631       record = &StructAtOffset<const PairValueRecord> (record, record_size);
 632     }
 633     return false;
 634   }
 635 
 636   void collect_glyphs (hb_collect_glyphs_context_t *c,
 637                               const ValueFormat *valueFormats) const
 638   {
 639     unsigned int len1 = valueFormats[0].get_len ();
 640     unsigned int len2 = valueFormats[1].get_len ();
 641     unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
 642 
 643     const PairValueRecord *record = &firstPairValueRecord;
 644     c->input->add_array (&record->secondGlyph, len, record_size);
 645   }
 646 
 647   bool apply (hb_ot_apply_context_t *c,
 648                      const ValueFormat *valueFormats,
 649                      unsigned int pos) const
 650   {
 651     TRACE_APPLY (this);
 652     hb_buffer_t *buffer = c->buffer;
 653     unsigned int len1 = valueFormats[0].get_len ();
 654     unsigned int len2 = valueFormats[1].get_len ();
 655     unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
 656 
 657     unsigned int count = len;
 658 
 659     /* Hand-coded bsearch. */
 660     if (unlikely (!count))
 661       return_trace (false);
 662     hb_codepoint_t x = buffer->info[pos].codepoint;
 663     int min = 0, max = (int) count - 1;
 664     while (min <= max)
 665     {
 666       int mid = ((unsigned int) min + (unsigned int) max) / 2;
 667       const PairValueRecord *record = &StructAtOffset<PairValueRecord> (&firstPairValueRecord, record_size * mid);
 668       hb_codepoint_t mid_x = record->secondGlyph;
 669       if (x < mid_x)
 670         max = mid - 1;
 671       else if (x > mid_x)
 672         min = mid + 1;
 673       else
 674       {
 675         /* Note the intentional use of "|" instead of short-circuit "||". */
 676         if (valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos()) |
 677             valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]))
 678           buffer->unsafe_to_break (buffer->idx, pos + 1);
 679         if (len2)
 680           pos++;
 681         buffer->idx = pos;
 682         return_trace (true);
 683       }
 684     }
 685 
 686     return_trace (false);
 687   }
 688 
 689   struct sanitize_closure_t
 690   {
 691     const void *base;
 692     const ValueFormat *valueFormats;
 693     unsigned int len1; /* valueFormats[0].get_len() */
 694     unsigned int stride; /* 1 + len1 + len2 */
 695   };
 696 
 697   bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const
 698   {
 699     TRACE_SANITIZE (this);
 700     if (!(c->check_struct (this)
 701        && c->check_range (&firstPairValueRecord,
 702                           len,
 703                           HBUINT16::static_size,
 704                           closure->stride))) return_trace (false);
 705 
 706     unsigned int count = len;
 707     const PairValueRecord *record = &firstPairValueRecord;
 708     return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride) &&
 709                   closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride));
 710   }
 711 
 712   protected:
 713   HBUINT16              len;    /* Number of PairValueRecords */
 714   PairValueRecord       firstPairValueRecord;
 715                                 /* Array of PairValueRecords--ordered
 716                                  * by GlyphID of the second glyph */
 717   public:
 718   DEFINE_SIZE_MIN (2);
 719 };
 720 
 721 struct PairPosFormat1
 722 {
 723   bool intersects (const hb_set_t *glyphs) const
 724   {
 725     unsigned int count = pairSet.len;
 726     for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
 727     {
 728       if (unlikely (iter.get_coverage () >= count))
 729         break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
 730       if (glyphs->has (iter.get_glyph ()) &&
 731           (this+pairSet[iter.get_coverage ()]).intersects (glyphs, valueFormat))
 732         return true;
 733     }
 734     return false;
 735   }
 736 
 737   void collect_glyphs (hb_collect_glyphs_context_t *c) const
 738   {
 739     if (unlikely (!(this+coverage).add_coverage (c->input))) return;
 740     unsigned int count = pairSet.len;
 741     for (unsigned int i = 0; i < count; i++)
 742       (this+pairSet[i]).collect_glyphs (c, valueFormat);
 743   }
 744 
 745   const Coverage &get_coverage () const { return this+coverage; }
 746 
 747   bool apply (hb_ot_apply_context_t *c) const
 748   {
 749     TRACE_APPLY (this);
 750     hb_buffer_t *buffer = c->buffer;
 751     unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
 752     if (likely (index == NOT_COVERED)) return_trace (false);
 753 
 754     hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
 755     skippy_iter.reset (buffer->idx, 1);
 756     if (!skippy_iter.next ()) return_trace (false);
 757 
 758     return_trace ((this+pairSet[index]).apply (c, valueFormat, skippy_iter.idx));
 759   }
 760 
 761   bool subset (hb_subset_context_t *c) const
 762   {
 763     TRACE_SUBSET (this);
 764     // TODO(subset)
 765     return_trace (false);
 766   }
 767 
 768   bool sanitize (hb_sanitize_context_t *c) const
 769   {
 770     TRACE_SANITIZE (this);
 771 
 772     if (!c->check_struct (this)) return_trace (false);
 773 
 774     unsigned int len1 = valueFormat[0].get_len ();
 775     unsigned int len2 = valueFormat[1].get_len ();
 776     PairSet::sanitize_closure_t closure =
 777     {
 778       this,
 779       valueFormat,
 780       len1,
 781       1 + len1 + len2
 782     };
 783 
 784     return_trace (coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
 785   }
 786 
 787   protected:
 788   HBUINT16      format;                 /* Format identifier--format = 1 */
 789   OffsetTo<Coverage>
 790                 coverage;               /* Offset to Coverage table--from
 791                                          * beginning of subtable */
 792   ValueFormat   valueFormat[2];         /* [0] Defines the types of data in
 793                                          * ValueRecord1--for the first glyph
 794                                          * in the pair--may be zero (0) */
 795                                         /* [1] Defines the types of data in
 796                                          * ValueRecord2--for the second glyph
 797                                          * in the pair--may be zero (0) */
 798   OffsetArrayOf<PairSet>
 799                 pairSet;                /* Array of PairSet tables
 800                                          * ordered by Coverage Index */
 801   public:
 802   DEFINE_SIZE_ARRAY (10, pairSet);
 803 };
 804 
 805 struct PairPosFormat2
 806 {
 807   bool intersects (const hb_set_t *glyphs) const
 808   {
 809     return (this+coverage).intersects (glyphs) &&
 810            (this+classDef2).intersects (glyphs);
 811   }
 812 
 813   void collect_glyphs (hb_collect_glyphs_context_t *c) const
 814   {
 815     if (unlikely (!(this+coverage).add_coverage (c->input))) return;
 816     if (unlikely (!(this+classDef2).add_coverage (c->input))) return;
 817   }
 818 
 819   const Coverage &get_coverage () const { return this+coverage; }
 820 
 821   bool apply (hb_ot_apply_context_t *c) const
 822   {
 823     TRACE_APPLY (this);
 824     hb_buffer_t *buffer = c->buffer;
 825     unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
 826     if (likely (index == NOT_COVERED)) return_trace (false);
 827 
 828     hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
 829     skippy_iter.reset (buffer->idx, 1);
 830     if (!skippy_iter.next ()) return_trace (false);
 831 
 832     unsigned int len1 = valueFormat1.get_len ();
 833     unsigned int len2 = valueFormat2.get_len ();
 834     unsigned int record_len = len1 + len2;
 835 
 836     unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint);
 837     unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint);
 838     if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return_trace (false);
 839 
 840     const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
 841     /* Note the intentional use of "|" instead of short-circuit "||". */
 842     if (valueFormat1.apply_value (c, this, v, buffer->cur_pos()) |
 843         valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]))
 844       buffer->unsafe_to_break (buffer->idx, skippy_iter.idx + 1);
 845 
 846     buffer->idx = skippy_iter.idx;
 847     if (len2)
 848       buffer->idx++;
 849 
 850     return_trace (true);
 851   }
 852 
 853   bool subset (hb_subset_context_t *c) const
 854   {
 855     TRACE_SUBSET (this);
 856     // TODO(subset)
 857     return_trace (false);
 858   }
 859 
 860   bool sanitize (hb_sanitize_context_t *c) const
 861   {
 862     TRACE_SANITIZE (this);
 863     if (!(c->check_struct (this)
 864        && coverage.sanitize (c, this)
 865        && classDef1.sanitize (c, this)
 866        && classDef2.sanitize (c, this))) return_trace (false);
 867 
 868     unsigned int len1 = valueFormat1.get_len ();
 869     unsigned int len2 = valueFormat2.get_len ();
 870     unsigned int stride = len1 + len2;
 871     unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
 872     unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
 873     return_trace (c->check_range ((const void *) values,
 874                                   count,
 875                                   record_size) &&
 876                   valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
 877                   valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride));
 878   }
 879 
 880   protected:
 881   HBUINT16      format;                 /* Format identifier--format = 2 */
 882   OffsetTo<Coverage>
 883                 coverage;               /* Offset to Coverage table--from
 884                                          * beginning of subtable */
 885   ValueFormat   valueFormat1;           /* ValueRecord definition--for the
 886                                          * first glyph of the pair--may be zero
 887                                          * (0) */
 888   ValueFormat   valueFormat2;           /* ValueRecord definition--for the
 889                                          * second glyph of the pair--may be
 890                                          * zero (0) */
 891   OffsetTo<ClassDef>
 892                 classDef1;              /* Offset to ClassDef table--from
 893                                          * beginning of PairPos subtable--for
 894                                          * the first glyph of the pair */
 895   OffsetTo<ClassDef>
 896                 classDef2;              /* Offset to ClassDef table--from
 897                                          * beginning of PairPos subtable--for
 898                                          * the second glyph of the pair */
 899   HBUINT16      class1Count;            /* Number of classes in ClassDef1
 900                                          * table--includes Class0 */
 901   HBUINT16      class2Count;            /* Number of classes in ClassDef2
 902                                          * table--includes Class0 */
 903   ValueRecord   values;                 /* Matrix of value pairs:
 904                                          * class1-major, class2-minor,
 905                                          * Each entry has value1 and value2 */
 906   public:
 907   DEFINE_SIZE_ARRAY (16, values);
 908 };
 909 
 910 struct PairPos
 911 {
 912   template <typename context_t>
 913   typename context_t::return_t dispatch (context_t *c) const
 914   {
 915     TRACE_DISPATCH (this, u.format);
 916     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
 917     switch (u.format) {
 918     case 1: return_trace (c->dispatch (u.format1));
 919     case 2: return_trace (c->dispatch (u.format2));
 920     default:return_trace (c->default_return_value ());
 921     }
 922   }
 923 
 924   protected:
 925   union {
 926   HBUINT16              format;         /* Format identifier */
 927   PairPosFormat1        format1;
 928   PairPosFormat2        format2;
 929   } u;
 930 };
 931 
 932 
 933 struct EntryExitRecord
 934 {
 935   friend struct CursivePosFormat1;
 936 
 937   bool sanitize (hb_sanitize_context_t *c, const void *base) const
 938   {
 939     TRACE_SANITIZE (this);
 940     return_trace (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
 941   }
 942 
 943   protected:
 944   OffsetTo<Anchor>
 945                 entryAnchor;            /* Offset to EntryAnchor table--from
 946                                          * beginning of CursivePos
 947                                          * subtable--may be NULL */
 948   OffsetTo<Anchor>
 949                 exitAnchor;             /* Offset to ExitAnchor table--from
 950                                          * beginning of CursivePos
 951                                          * subtable--may be NULL */
 952   public:
 953   DEFINE_SIZE_STATIC (4);
 954 };
 955 
 956 static void
 957 reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent);
 958 
 959 struct CursivePosFormat1
 960 {
 961   bool intersects (const hb_set_t *glyphs) const
 962   { return (this+coverage).intersects (glyphs); }
 963 
 964   void collect_glyphs (hb_collect_glyphs_context_t *c) const
 965   { if (unlikely (!(this+coverage).add_coverage (c->input))) return; }
 966 
 967   const Coverage &get_coverage () const { return this+coverage; }
 968 
 969   bool apply (hb_ot_apply_context_t *c) const
 970   {
 971     TRACE_APPLY (this);
 972     hb_buffer_t *buffer = c->buffer;
 973 
 974     const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage  (buffer->cur().codepoint)];
 975     if (!this_record.entryAnchor) return_trace (false);
 976 
 977     hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
 978     skippy_iter.reset (buffer->idx, 1);
 979     if (!skippy_iter.prev ()) return_trace (false);
 980 
 981     const EntryExitRecord &prev_record = entryExitRecord[(this+coverage).get_coverage  (buffer->info[skippy_iter.idx].codepoint)];
 982     if (!prev_record.exitAnchor) return_trace (false);
 983 
 984     unsigned int i = skippy_iter.idx;
 985     unsigned int j = buffer->idx;
 986 
 987     buffer->unsafe_to_break (i, j);
 988     float entry_x, entry_y, exit_x, exit_y;
 989     (this+prev_record.exitAnchor).get_anchor (c, buffer->info[i].codepoint, &exit_x, &exit_y);
 990     (this+this_record.entryAnchor).get_anchor (c, buffer->info[j].codepoint, &entry_x, &entry_y);
 991 
 992     hb_glyph_position_t *pos = buffer->pos;
 993 
 994     hb_position_t d;
 995     /* Main-direction adjustment */
 996     switch (c->direction) {
 997       case HB_DIRECTION_LTR:
 998         pos[i].x_advance  = round (exit_x) + pos[i].x_offset;
 999 
1000         d = round (entry_x) + pos[j].x_offset;
1001         pos[j].x_advance -= d;
1002         pos[j].x_offset  -= d;
1003         break;
1004       case HB_DIRECTION_RTL:
1005         d = round (exit_x) + pos[i].x_offset;
1006         pos[i].x_advance -= d;
1007         pos[i].x_offset  -= d;
1008 
1009         pos[j].x_advance  = round (entry_x) + pos[j].x_offset;
1010         break;
1011       case HB_DIRECTION_TTB:
1012         pos[i].y_advance  = round (exit_y) + pos[i].y_offset;
1013 
1014         d = round (entry_y) + pos[j].y_offset;
1015         pos[j].y_advance -= d;
1016         pos[j].y_offset  -= d;
1017         break;
1018       case HB_DIRECTION_BTT:
1019         d = round (exit_y) + pos[i].y_offset;
1020         pos[i].y_advance -= d;
1021         pos[i].y_offset  -= d;
1022 
1023         pos[j].y_advance  = round (entry_y);
1024         break;
1025       case HB_DIRECTION_INVALID:
1026       default:
1027         break;
1028     }
1029 
1030     /* Cross-direction adjustment */
1031 
1032     /* We attach child to parent (think graph theory and rooted trees whereas
1033      * the root stays on baseline and each node aligns itself against its
1034      * parent.
1035      *
1036      * Optimize things for the case of RightToLeft, as that's most common in
1037      * Arabic. */
1038     unsigned int child  = i;
1039     unsigned int parent = j;
1040     hb_position_t x_offset = entry_x - exit_x;
1041     hb_position_t y_offset = entry_y - exit_y;
1042     if  (!(c->lookup_props & LookupFlag::RightToLeft))
1043     {
1044       unsigned int k = child;
1045       child = parent;
1046       parent = k;
1047       x_offset = -x_offset;
1048       y_offset = -y_offset;
1049     }
1050 
1051     /* If child was already connected to someone else, walk through its old
1052      * chain and reverse the link direction, such that the whole tree of its
1053      * previous connection now attaches to new parent.  Watch out for case
1054      * where new parent is on the path from old chain...
1055      */
1056     reverse_cursive_minor_offset (pos, child, c->direction, parent);
1057 
1058     pos[child].attach_type() = ATTACH_TYPE_CURSIVE;
1059     pos[child].attach_chain() = (int) parent - (int) child;
1060     buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
1061     if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
1062       pos[child].y_offset = y_offset;
1063     else
1064       pos[child].x_offset = x_offset;
1065 
1066     buffer->idx++;
1067     return_trace (true);
1068   }
1069 
1070   bool subset (hb_subset_context_t *c) const
1071   {
1072     TRACE_SUBSET (this);
1073     // TODO(subset)
1074     return_trace (false);
1075   }
1076 
1077   bool sanitize (hb_sanitize_context_t *c) const
1078   {
1079     TRACE_SANITIZE (this);
1080     return_trace (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
1081   }
1082 
1083   protected:
1084   HBUINT16      format;                 /* Format identifier--format = 1 */
1085   OffsetTo<Coverage>
1086                 coverage;               /* Offset to Coverage table--from
1087                                          * beginning of subtable */
1088   ArrayOf<EntryExitRecord>
1089                 entryExitRecord;        /* Array of EntryExit records--in
1090                                          * Coverage Index order */
1091   public:
1092   DEFINE_SIZE_ARRAY (6, entryExitRecord);
1093 };
1094 
1095 struct CursivePos
1096 {
1097   template <typename context_t>
1098   typename context_t::return_t dispatch (context_t *c) const
1099   {
1100     TRACE_DISPATCH (this, u.format);
1101     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1102     switch (u.format) {
1103     case 1: return_trace (c->dispatch (u.format1));
1104     default:return_trace (c->default_return_value ());
1105     }
1106   }
1107 
1108   protected:
1109   union {
1110   HBUINT16              format;         /* Format identifier */
1111   CursivePosFormat1     format1;
1112   } u;
1113 };
1114 
1115 
1116 typedef AnchorMatrix BaseArray;         /* base-major--
1117                                          * in order of BaseCoverage Index--,
1118                                          * mark-minor--
1119                                          * ordered by class--zero-based. */
1120 
1121 struct MarkBasePosFormat1
1122 {
1123   bool intersects (const hb_set_t *glyphs) const
1124   { return (this+markCoverage).intersects (glyphs) &&
1125            (this+baseCoverage).intersects (glyphs); }
1126 
1127   void collect_glyphs (hb_collect_glyphs_context_t *c) const
1128   {
1129     if (unlikely (!(this+markCoverage).add_coverage (c->input))) return;
1130     if (unlikely (!(this+baseCoverage).add_coverage (c->input))) return;
1131   }
1132 
1133   const Coverage &get_coverage () const { return this+markCoverage; }
1134 
1135   bool apply (hb_ot_apply_context_t *c) const
1136   {
1137     TRACE_APPLY (this);
1138     hb_buffer_t *buffer = c->buffer;
1139     unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
1140     if (likely (mark_index == NOT_COVERED)) return_trace (false);
1141 
1142     /* Now we search backwards for a non-mark glyph */
1143     hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
1144     skippy_iter.reset (buffer->idx, 1);
1145     skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
1146     do {
1147       if (!skippy_iter.prev ()) return_trace (false);
1148       /* We only want to attach to the first of a MultipleSubst sequence.
1149        * https://github.com/harfbuzz/harfbuzz/issues/740
1150        * Reject others...
1151        * ...but stop if we find a mark in the MultipleSubst sequence:
1152        * https://github.com/harfbuzz/harfbuzz/issues/1020 */
1153       if (!_hb_glyph_info_multiplied (&buffer->info[skippy_iter.idx]) ||
1154           0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) ||
1155           (skippy_iter.idx == 0 ||
1156            _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx - 1]) ||
1157            _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]) !=
1158            _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx - 1]) ||
1159            _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) !=
1160            _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx - 1]) + 1
1161            ))
1162         break;
1163       skippy_iter.reject ();
1164     } while (true);
1165 
1166     /* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */
1167     //if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { return_trace (false); }
1168 
1169     unsigned int base_index = (this+baseCoverage).get_coverage  (buffer->info[skippy_iter.idx].codepoint);
1170     if (base_index == NOT_COVERED) return_trace (false);
1171 
1172     return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx));
1173   }
1174 
1175   bool subset (hb_subset_context_t *c) const
1176   {
1177     TRACE_SUBSET (this);
1178     // TODO(subset)
1179     return_trace (false);
1180   }
1181 
1182   bool sanitize (hb_sanitize_context_t *c) const
1183   {
1184     TRACE_SANITIZE (this);
1185     return_trace (c->check_struct (this) &&
1186                   markCoverage.sanitize (c, this) &&
1187                   baseCoverage.sanitize (c, this) &&
1188                   markArray.sanitize (c, this) &&
1189                   baseArray.sanitize (c, this, (unsigned int) classCount));
1190   }
1191 
1192   protected:
1193   HBUINT16      format;                 /* Format identifier--format = 1 */
1194   OffsetTo<Coverage>
1195                 markCoverage;           /* Offset to MarkCoverage table--from
1196                                          * beginning of MarkBasePos subtable */
1197   OffsetTo<Coverage>
1198                 baseCoverage;           /* Offset to BaseCoverage table--from
1199                                          * beginning of MarkBasePos subtable */
1200   HBUINT16      classCount;             /* Number of classes defined for marks */
1201   OffsetTo<MarkArray>
1202                 markArray;              /* Offset to MarkArray table--from
1203                                          * beginning of MarkBasePos subtable */
1204   OffsetTo<BaseArray>
1205                 baseArray;              /* Offset to BaseArray table--from
1206                                          * beginning of MarkBasePos subtable */
1207   public:
1208   DEFINE_SIZE_STATIC (12);
1209 };
1210 
1211 struct MarkBasePos
1212 {
1213   template <typename context_t>
1214   typename context_t::return_t dispatch (context_t *c) const
1215   {
1216     TRACE_DISPATCH (this, u.format);
1217     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1218     switch (u.format) {
1219     case 1: return_trace (c->dispatch (u.format1));
1220     default:return_trace (c->default_return_value ());
1221     }
1222   }
1223 
1224   protected:
1225   union {
1226   HBUINT16              format;         /* Format identifier */
1227   MarkBasePosFormat1    format1;
1228   } u;
1229 };
1230 
1231 
1232 typedef AnchorMatrix LigatureAttach;    /* component-major--
1233                                          * in order of writing direction--,
1234                                          * mark-minor--
1235                                          * ordered by class--zero-based. */
1236 
1237 typedef OffsetListOf<LigatureAttach> LigatureArray;
1238                                         /* Array of LigatureAttach
1239                                          * tables ordered by
1240                                          * LigatureCoverage Index */
1241 
1242 struct MarkLigPosFormat1
1243 {
1244   bool intersects (const hb_set_t *glyphs) const
1245   { return (this+markCoverage).intersects (glyphs) &&
1246            (this+ligatureCoverage).intersects (glyphs); }
1247 
1248   void collect_glyphs (hb_collect_glyphs_context_t *c) const
1249   {
1250     if (unlikely (!(this+markCoverage).add_coverage (c->input))) return;
1251     if (unlikely (!(this+ligatureCoverage).add_coverage (c->input))) return;
1252   }
1253 
1254   const Coverage &get_coverage () const { return this+markCoverage; }
1255 
1256   bool apply (hb_ot_apply_context_t *c) const
1257   {
1258     TRACE_APPLY (this);
1259     hb_buffer_t *buffer = c->buffer;
1260     unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
1261     if (likely (mark_index == NOT_COVERED)) return_trace (false);
1262 
1263     /* Now we search backwards for a non-mark glyph */
1264     hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
1265     skippy_iter.reset (buffer->idx, 1);
1266     skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
1267     if (!skippy_iter.prev ()) return_trace (false);
1268 
1269     /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */
1270     //if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { return_trace (false); }
1271 
1272     unsigned int j = skippy_iter.idx;
1273     unsigned int lig_index = (this+ligatureCoverage).get_coverage  (buffer->info[j].codepoint);
1274     if (lig_index == NOT_COVERED) return_trace (false);
1275 
1276     const LigatureArray& lig_array = this+ligatureArray;
1277     const LigatureAttach& lig_attach = lig_array[lig_index];
1278 
1279     /* Find component to attach to */
1280     unsigned int comp_count = lig_attach.rows;
1281     if (unlikely (!comp_count)) return_trace (false);
1282 
1283     /* We must now check whether the ligature ID of the current mark glyph
1284      * is identical to the ligature ID of the found ligature.  If yes, we
1285      * can directly use the component index.  If not, we attach the mark
1286      * glyph to the last component of the ligature. */
1287     unsigned int comp_index;
1288     unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[j]);
1289     unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur());
1290     unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
1291     if (lig_id && lig_id == mark_id && mark_comp > 0)
1292       comp_index = MIN (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1;
1293     else
1294       comp_index = comp_count - 1;
1295 
1296     return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
1297   }
1298 
1299   bool subset (hb_subset_context_t *c) const
1300   {
1301     TRACE_SUBSET (this);
1302     // TODO(subset)
1303     return_trace (false);
1304   }
1305 
1306   bool sanitize (hb_sanitize_context_t *c) const
1307   {
1308     TRACE_SANITIZE (this);
1309     return_trace (c->check_struct (this) &&
1310                   markCoverage.sanitize (c, this) &&
1311                   ligatureCoverage.sanitize (c, this) &&
1312                   markArray.sanitize (c, this) &&
1313                   ligatureArray.sanitize (c, this, (unsigned int) classCount));
1314   }
1315 
1316   protected:
1317   HBUINT16      format;                 /* Format identifier--format = 1 */
1318   OffsetTo<Coverage>
1319                 markCoverage;           /* Offset to Mark Coverage table--from
1320                                          * beginning of MarkLigPos subtable */
1321   OffsetTo<Coverage>
1322                 ligatureCoverage;       /* Offset to Ligature Coverage
1323                                          * table--from beginning of MarkLigPos
1324                                          * subtable */
1325   HBUINT16      classCount;             /* Number of defined mark classes */
1326   OffsetTo<MarkArray>
1327                 markArray;              /* Offset to MarkArray table--from
1328                                          * beginning of MarkLigPos subtable */
1329   OffsetTo<LigatureArray>
1330                 ligatureArray;          /* Offset to LigatureArray table--from
1331                                          * beginning of MarkLigPos subtable */
1332   public:
1333   DEFINE_SIZE_STATIC (12);
1334 };
1335 
1336 struct MarkLigPos
1337 {
1338   template <typename context_t>
1339   typename context_t::return_t dispatch (context_t *c) const
1340   {
1341     TRACE_DISPATCH (this, u.format);
1342     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1343     switch (u.format) {
1344     case 1: return_trace (c->dispatch (u.format1));
1345     default:return_trace (c->default_return_value ());
1346     }
1347   }
1348 
1349   protected:
1350   union {
1351   HBUINT16              format;         /* Format identifier */
1352   MarkLigPosFormat1     format1;
1353   } u;
1354 };
1355 
1356 
1357 typedef AnchorMatrix Mark2Array;        /* mark2-major--
1358                                          * in order of Mark2Coverage Index--,
1359                                          * mark1-minor--
1360                                          * ordered by class--zero-based. */
1361 
1362 struct MarkMarkPosFormat1
1363 {
1364   bool intersects (const hb_set_t *glyphs) const
1365   { return (this+mark1Coverage).intersects (glyphs) &&
1366            (this+mark2Coverage).intersects (glyphs); }
1367 
1368   void collect_glyphs (hb_collect_glyphs_context_t *c) const
1369   {
1370     if (unlikely (!(this+mark1Coverage).add_coverage (c->input))) return;
1371     if (unlikely (!(this+mark2Coverage).add_coverage (c->input))) return;
1372   }
1373 
1374   const Coverage &get_coverage () const { return this+mark1Coverage; }
1375 
1376   bool apply (hb_ot_apply_context_t *c) const
1377   {
1378     TRACE_APPLY (this);
1379     hb_buffer_t *buffer = c->buffer;
1380     unsigned int mark1_index = (this+mark1Coverage).get_coverage  (buffer->cur().codepoint);
1381     if (likely (mark1_index == NOT_COVERED)) return_trace (false);
1382 
1383     /* now we search backwards for a suitable mark glyph until a non-mark glyph */
1384     hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
1385     skippy_iter.reset (buffer->idx, 1);
1386     skippy_iter.set_lookup_props (c->lookup_props & ~LookupFlag::IgnoreFlags);
1387     if (!skippy_iter.prev ()) return_trace (false);
1388 
1389     if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])) { return_trace (false); }
1390 
1391     unsigned int j = skippy_iter.idx;
1392 
1393     unsigned int id1 = _hb_glyph_info_get_lig_id (&buffer->cur());
1394     unsigned int id2 = _hb_glyph_info_get_lig_id (&buffer->info[j]);
1395     unsigned int comp1 = _hb_glyph_info_get_lig_comp (&buffer->cur());
1396     unsigned int comp2 = _hb_glyph_info_get_lig_comp (&buffer->info[j]);
1397 
1398     if (likely (id1 == id2)) {
1399       if (id1 == 0) /* Marks belonging to the same base. */
1400         goto good;
1401       else if (comp1 == comp2) /* Marks belonging to the same ligature component. */
1402         goto good;
1403     } else {
1404       /* If ligature ids don't match, it may be the case that one of the marks
1405        * itself is a ligature.  In which case match. */
1406       if ((id1 > 0 && !comp1) || (id2 > 0 && !comp2))
1407         goto good;
1408     }
1409 
1410     /* Didn't match. */
1411     return_trace (false);
1412 
1413     good:
1414     unsigned int mark2_index = (this+mark2Coverage).get_coverage  (buffer->info[j].codepoint);
1415     if (mark2_index == NOT_COVERED) return_trace (false);
1416 
1417     return_trace ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j));
1418   }
1419 
1420   bool subset (hb_subset_context_t *c) const
1421   {
1422     TRACE_SUBSET (this);
1423     // TODO(subset)
1424     return_trace (false);
1425   }
1426 
1427   bool sanitize (hb_sanitize_context_t *c) const
1428   {
1429     TRACE_SANITIZE (this);
1430     return_trace (c->check_struct (this) &&
1431                   mark1Coverage.sanitize (c, this) &&
1432                   mark2Coverage.sanitize (c, this) &&
1433                   mark1Array.sanitize (c, this) &&
1434                   mark2Array.sanitize (c, this, (unsigned int) classCount));
1435   }
1436 
1437   protected:
1438   HBUINT16      format;                 /* Format identifier--format = 1 */
1439   OffsetTo<Coverage>
1440                 mark1Coverage;          /* Offset to Combining Mark1 Coverage
1441                                          * table--from beginning of MarkMarkPos
1442                                          * subtable */
1443   OffsetTo<Coverage>
1444                 mark2Coverage;          /* Offset to Combining Mark2 Coverage
1445                                          * table--from beginning of MarkMarkPos
1446                                          * subtable */
1447   HBUINT16      classCount;             /* Number of defined mark classes */
1448   OffsetTo<MarkArray>
1449                 mark1Array;             /* Offset to Mark1Array table--from
1450                                          * beginning of MarkMarkPos subtable */
1451   OffsetTo<Mark2Array>
1452                 mark2Array;             /* Offset to Mark2Array table--from
1453                                          * beginning of MarkMarkPos subtable */
1454   public:
1455   DEFINE_SIZE_STATIC (12);
1456 };
1457 
1458 struct MarkMarkPos
1459 {
1460   template <typename context_t>
1461   typename context_t::return_t dispatch (context_t *c) const
1462   {
1463     TRACE_DISPATCH (this, u.format);
1464     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1465     switch (u.format) {
1466     case 1: return_trace (c->dispatch (u.format1));
1467     default:return_trace (c->default_return_value ());
1468     }
1469   }
1470 
1471   protected:
1472   union {
1473   HBUINT16              format;         /* Format identifier */
1474   MarkMarkPosFormat1    format1;
1475   } u;
1476 };
1477 
1478 
1479 struct ContextPos : Context {};
1480 
1481 struct ChainContextPos : ChainContext {};
1482 
1483 struct ExtensionPos : Extension<ExtensionPos>
1484 {
1485   typedef struct PosLookupSubTable SubTable;
1486 };
1487 
1488 
1489 
1490 /*
1491  * PosLookup
1492  */
1493 
1494 
1495 struct PosLookupSubTable
1496 {
1497   friend struct Lookup;
1498   friend struct PosLookup;
1499 
1500   enum Type {
1501     Single              = 1,
1502     Pair                = 2,
1503     Cursive             = 3,
1504     MarkBase            = 4,
1505     MarkLig             = 5,
1506     MarkMark            = 6,
1507     Context             = 7,
1508     ChainContext        = 8,
1509     Extension           = 9
1510   };
1511 
1512   template <typename context_t>
1513   typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
1514   {
1515     TRACE_DISPATCH (this, lookup_type);
1516     switch (lookup_type) {
1517     case Single:                return_trace (u.single.dispatch (c));
1518     case Pair:                  return_trace (u.pair.dispatch (c));
1519     case Cursive:               return_trace (u.cursive.dispatch (c));
1520     case MarkBase:              return_trace (u.markBase.dispatch (c));
1521     case MarkLig:               return_trace (u.markLig.dispatch (c));
1522     case MarkMark:              return_trace (u.markMark.dispatch (c));
1523     case Context:               return_trace (u.context.dispatch (c));
1524     case ChainContext:          return_trace (u.chainContext.dispatch (c));
1525     case Extension:             return_trace (u.extension.dispatch (c));
1526     default:                    return_trace (c->default_return_value ());
1527     }
1528   }
1529 
1530   protected:
1531   union {
1532   SinglePos             single;
1533   PairPos               pair;
1534   CursivePos            cursive;
1535   MarkBasePos           markBase;
1536   MarkLigPos            markLig;
1537   MarkMarkPos           markMark;
1538   ContextPos            context;
1539   ChainContextPos       chainContext;
1540   ExtensionPos          extension;
1541   } u;
1542   public:
1543   DEFINE_SIZE_MIN (0);
1544 };
1545 
1546 
1547 struct PosLookup : Lookup
1548 {
1549   typedef struct PosLookupSubTable SubTable;
1550 
1551   const SubTable& get_subtable (unsigned int i) const
1552   { return Lookup::get_subtable<SubTable> (i); }
1553 
1554   bool is_reverse () const
1555   {
1556     return false;
1557   }
1558 
1559   bool apply (hb_ot_apply_context_t *c) const
1560   {
1561     TRACE_APPLY (this);
1562     return_trace (dispatch (c));
1563   }
1564 
1565   bool intersects (const hb_set_t *glyphs) const
1566   {
1567     hb_intersects_context_t c (glyphs);
1568     return dispatch (&c);
1569   }
1570 
1571   hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
1572   { return dispatch (c); }
1573 
1574   template <typename set_t>
1575   void add_coverage (set_t *glyphs) const
1576   {
1577     hb_add_coverage_context_t<set_t> c (glyphs);
1578     dispatch (&c);
1579   }
1580 
1581   static bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index);
1582 
1583   template <typename context_t>
1584   static typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
1585 
1586   template <typename context_t>
1587   typename context_t::return_t dispatch (context_t *c) const
1588   { return Lookup::dispatch<SubTable> (c); }
1589 
1590   bool subset (hb_subset_context_t *c) const
1591   { return Lookup::subset<SubTable> (c); }
1592 
1593   bool sanitize (hb_sanitize_context_t *c) const
1594   { return Lookup::sanitize<SubTable> (c); }
1595 };
1596 
1597 /*
1598  * GPOS -- Glyph Positioning
1599  * https://docs.microsoft.com/en-us/typography/opentype/spec/gpos
1600  */
1601 
1602 struct GPOS : GSUBGPOS
1603 {
1604   static constexpr hb_tag_t tableTag = HB_OT_TAG_GPOS;
1605 
1606   const PosLookup& get_lookup (unsigned int i) const
1607   { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
1608 
1609   static inline void position_start (hb_font_t *font, hb_buffer_t *buffer);
1610   static inline void position_finish_advances (hb_font_t *font, hb_buffer_t *buffer);
1611   static inline void position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer);
1612 
1613   bool subset (hb_subset_context_t *c) const
1614   { return GSUBGPOS::subset<PosLookup> (c); }
1615 
1616   bool sanitize (hb_sanitize_context_t *c) const
1617   { return GSUBGPOS::sanitize<PosLookup> (c); }
1618 
1619   HB_INTERNAL bool is_blacklisted (hb_blob_t *blob,
1620                                    hb_face_t *face) const;
1621 
1622   typedef GSUBGPOS::accelerator_t<GPOS> accelerator_t;
1623 };
1624 
1625 
1626 static void
1627 reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent)
1628 {
1629   int chain = pos[i].attach_chain(), type = pos[i].attach_type();
1630   if (likely (!chain || 0 == (type & ATTACH_TYPE_CURSIVE)))
1631     return;
1632 
1633   pos[i].attach_chain() = 0;
1634 
1635   unsigned int j = (int) i + chain;
1636 
1637   /* Stop if we see new parent in the chain. */
1638   if (j == new_parent)
1639     return;
1640 
1641   reverse_cursive_minor_offset (pos, j, direction, new_parent);
1642 
1643   if (HB_DIRECTION_IS_HORIZONTAL (direction))
1644     pos[j].y_offset = -pos[i].y_offset;
1645   else
1646     pos[j].x_offset = -pos[i].x_offset;
1647 
1648   pos[j].attach_chain() = -chain;
1649   pos[j].attach_type() = type;
1650 }
1651 static void
1652 propagate_attachment_offsets (hb_glyph_position_t *pos,
1653                               unsigned int len,
1654                               unsigned int i,
1655                               hb_direction_t direction)
1656 {
1657   /* Adjusts offsets of attached glyphs (both cursive and mark) to accumulate
1658    * offset of glyph they are attached to. */
1659   int chain = pos[i].attach_chain(), type = pos[i].attach_type();
1660   if (likely (!chain))
1661     return;
1662 
1663   pos[i].attach_chain() = 0;
1664 
1665   unsigned int j = (int) i + chain;
1666 
1667   if (unlikely (j >= len))
1668     return;
1669 
1670   propagate_attachment_offsets (pos, len, j, direction);
1671 
1672   assert (!!(type & ATTACH_TYPE_MARK) ^ !!(type & ATTACH_TYPE_CURSIVE));
1673 
1674   if (type & ATTACH_TYPE_CURSIVE)
1675   {
1676     if (HB_DIRECTION_IS_HORIZONTAL (direction))
1677       pos[i].y_offset += pos[j].y_offset;
1678     else
1679       pos[i].x_offset += pos[j].x_offset;
1680   }
1681   else /*if (type & ATTACH_TYPE_MARK)*/
1682   {
1683     pos[i].x_offset += pos[j].x_offset;
1684     pos[i].y_offset += pos[j].y_offset;
1685 
1686     assert (j < i);
1687     if (HB_DIRECTION_IS_FORWARD (direction))
1688       for (unsigned int k = j; k < i; k++) {
1689         pos[i].x_offset -= pos[k].x_advance;
1690         pos[i].y_offset -= pos[k].y_advance;
1691       }
1692     else
1693       for (unsigned int k = j + 1; k < i + 1; k++) {
1694         pos[i].x_offset += pos[k].x_advance;
1695         pos[i].y_offset += pos[k].y_advance;
1696       }
1697   }
1698 }
1699 
1700 void
1701 GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
1702 {
1703   unsigned int count = buffer->len;
1704   for (unsigned int i = 0; i < count; i++)
1705     buffer->pos[i].attach_chain() = buffer->pos[i].attach_type() = 0;
1706 }
1707 
1708 void
1709 GPOS::position_finish_advances (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSED)
1710 {
1711   //_hb_buffer_assert_gsubgpos_vars (buffer);
1712 }
1713 
1714 void
1715 GPOS::position_finish_offsets (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
1716 {
1717   _hb_buffer_assert_gsubgpos_vars (buffer);
1718 
1719   unsigned int len;
1720   hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
1721   hb_direction_t direction = buffer->props.direction;
1722 
1723   /* Handle attachments */
1724   if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT)
1725     for (unsigned int i = 0; i < len; i++)
1726       propagate_attachment_offsets (pos, len, i, direction);
1727 }
1728 
1729 
1730 struct GPOS_accelerator_t : GPOS::accelerator_t {};
1731 
1732 
1733 /* Out-of-class implementation for methods recursing */
1734 
1735 template <typename context_t>
1736 /*static*/ inline typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
1737 {
1738   const PosLookup &l = c->face->table.GPOS.get_relaxed ()->table->get_lookup (lookup_index);
1739   return l.dispatch (c);
1740 }
1741 
1742 /*static*/ inline bool PosLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
1743 {
1744   const PosLookup &l = c->face->table.GPOS.get_relaxed ()->table->get_lookup (lookup_index);
1745   unsigned int saved_lookup_props = c->lookup_props;
1746   unsigned int saved_lookup_index = c->lookup_index;
1747   c->set_lookup_index (lookup_index);
1748   c->set_lookup_props (l.get_props ());
1749   bool ret = l.dispatch (c);
1750   c->set_lookup_index (saved_lookup_index);
1751   c->set_lookup_props (saved_lookup_props);
1752   return ret;
1753 }
1754 
1755 
1756 } /* namespace OT */
1757 
1758 
1759 #endif /* HB_OT_LAYOUT_GPOS_TABLE_HH */