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