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