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