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