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