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