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