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