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