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