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