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