Further cleanup of sizeof
[framework/uifw/harfbuzz.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[VAR0];
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[VAR];
335   AnchorFormat2         format2[VAR];
336   AnchorFormat3         format3[VAR];
337   } u;
338   public:
339   DEFINE_SIZE_MIN (2);
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_VAR (2, OffsetTo<Anchor>);
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_VAR (6, Value);
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_VAR (8, Value);
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[VAR];
541   SinglePosFormat2      format2[VAR];
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_VAR (2, Value);
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   PairValueRecord
575                 array[VAR];             /* Array of PairValueRecords--ordered
576                                          * by GlyphID of the second glyph */
577   public:
578   DEFINE_SIZE_VAR (2, PairValueRecord);
579 };
580
581 struct PairPosFormat1
582 {
583   friend struct PairPos;
584
585   private:
586   inline bool apply (hb_apply_context_t *context) const
587   {
588     TRACE_APPLY ();
589     unsigned int end = MIN (context->buffer->in_length, context->buffer->in_pos + context->context_length);
590     if (unlikely (context->buffer->in_pos + 2 > end))
591       return false;
592
593     unsigned int index = (this+coverage) (IN_CURGLYPH ());
594     if (likely (index == NOT_COVERED))
595       return false;
596
597     unsigned int j = context->buffer->in_pos + 1;
598     while (_hb_ot_layout_skip_mark (context->layout->face, IN_INFO (j), context->lookup_flag, NULL))
599     {
600       if (unlikely (j == end))
601         return false;
602       j++;
603     }
604
605     unsigned int len1 = valueFormat1.get_len ();
606     unsigned int len2 = valueFormat2.get_len ();
607     unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
608
609     const PairSet &pair_set = this+pairSet[index];
610     unsigned int count = pair_set.len;
611     const PairValueRecord *record = pair_set.array;
612     for (unsigned int i = 0; i < count; i++)
613     {
614       if (IN_GLYPH (j) == record->secondGlyph)
615       {
616         valueFormat1.apply_value (context->layout, this, &record->values[0], CURPOSITION ());
617         valueFormat2.apply_value (context->layout, this, &record->values[len1], POSITION (j));
618         if (len2)
619           j++;
620         context->buffer->in_pos = j;
621         return true;
622       }
623       record = &StructAtOffset<PairValueRecord> (record, record_size);
624     }
625
626     return false;
627   }
628
629   inline bool sanitize (hb_sanitize_context_t *context) {
630     TRACE_SANITIZE ();
631
632     unsigned int len1 = valueFormat1.get_len ();
633     unsigned int len2 = valueFormat2.get_len ();
634
635     if (!(context->check_struct (this)
636        && coverage.sanitize (context, this)
637        && likely (pairSet.sanitize (context, this, len1 + len2)))) return false;
638
639     if (!(valueFormat1.has_device () || valueFormat2.has_device ())) return true;
640
641     unsigned int stride = 1 + len1 + len2;
642     unsigned int count1 = pairSet.len;
643     for (unsigned int i = 0; i < count1; i++)
644     {
645       PairSet &pair_set = const_cast<PairSet &> (this+pairSet[i]); /* XXX clean this up */
646
647       unsigned int count2 = pair_set.len;
648       PairValueRecord *record = pair_set.array;
649       if (!(valueFormat1.sanitize_values_stride_unsafe (context, this, &record->values[0], count2, stride) &&
650             valueFormat2.sanitize_values_stride_unsafe (context, this, &record->values[len1], count2, stride)))
651         return false;
652     }
653
654     return true;
655   }
656
657   private:
658   USHORT        format;                 /* Format identifier--format = 1 */
659   OffsetTo<Coverage>
660                 coverage;               /* Offset to Coverage table--from
661                                          * beginning of subtable */
662   ValueFormat   valueFormat1;           /* Defines the types of data in
663                                          * ValueRecord1--for the first glyph
664                                          * in the pair--may be zero (0) */
665   ValueFormat   valueFormat2;           /* Defines the types of data in
666                                          * ValueRecord2--for the second glyph
667                                          * in the pair--may be zero (0) */
668   OffsetArrayOf<PairSet>
669                 pairSet;                /* Array of PairSet tables
670                                          * ordered by Coverage Index */
671   public:
672   DEFINE_SIZE_VAR (10, OffsetTo<PairSet>);
673 };
674
675 struct PairPosFormat2
676 {
677   friend struct PairPos;
678
679   private:
680   inline bool apply (hb_apply_context_t *context) const
681   {
682     TRACE_APPLY ();
683     unsigned int end = MIN (context->buffer->in_length, context->buffer->in_pos + context->context_length);
684     if (unlikely (context->buffer->in_pos + 2 > end))
685       return false;
686
687     unsigned int index = (this+coverage) (IN_CURGLYPH ());
688     if (likely (index == NOT_COVERED))
689       return false;
690
691     unsigned int j = context->buffer->in_pos + 1;
692     while (_hb_ot_layout_skip_mark (context->layout->face, IN_INFO (j), context->lookup_flag, NULL))
693     {
694       if (unlikely (j == end))
695         return false;
696       j++;
697     }
698
699     unsigned int len1 = valueFormat1.get_len ();
700     unsigned int len2 = valueFormat2.get_len ();
701     unsigned int record_len = len1 + len2;
702
703     unsigned int klass1 = (this+classDef1) (IN_CURGLYPH ());
704     unsigned int klass2 = (this+classDef2) (IN_GLYPH (j));
705     if (unlikely (klass1 >= class1Count || klass2 >= class2Count))
706       return false;
707
708     const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
709     valueFormat1.apply_value (context->layout, this, v, CURPOSITION ());
710     valueFormat2.apply_value (context->layout, this, v + len1, POSITION (j));
711
712     if (len2)
713       j++;
714     context->buffer->in_pos = j;
715
716     return true;
717   }
718
719   inline bool sanitize (hb_sanitize_context_t *context) {
720     TRACE_SANITIZE ();
721     if (!(context->check_struct (this)
722        && coverage.sanitize (context, this)
723        && classDef1.sanitize (context, this)
724        && classDef2.sanitize (context, this))) return false;
725
726     unsigned int len1 = valueFormat1.get_len ();
727     unsigned int len2 = valueFormat2.get_len ();
728     unsigned int stride = len1 + len2;
729     unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
730     unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
731     return context->check_array (values, record_size, count) &&
732            valueFormat1.sanitize_values_stride_unsafe (context, this, &values[0], count, stride) &&
733            valueFormat2.sanitize_values_stride_unsafe (context, this, &values[len1], count, stride);
734   }
735
736   private:
737   USHORT        format;                 /* Format identifier--format = 2 */
738   OffsetTo<Coverage>
739                 coverage;               /* Offset to Coverage table--from
740                                          * beginning of subtable */
741   ValueFormat   valueFormat1;           /* ValueRecord definition--for the
742                                          * first glyph of the pair--may be zero
743                                          * (0) */
744   ValueFormat   valueFormat2;           /* ValueRecord definition--for the
745                                          * second glyph of the pair--may be
746                                          * zero (0) */
747   OffsetTo<ClassDef>
748                 classDef1;              /* Offset to ClassDef table--from
749                                          * beginning of PairPos subtable--for
750                                          * the first glyph of the pair */
751   OffsetTo<ClassDef>
752                 classDef2;              /* Offset to ClassDef table--from
753                                          * beginning of PairPos subtable--for
754                                          * the second glyph of the pair */
755   USHORT        class1Count;            /* Number of classes in ClassDef1
756                                          * table--includes Class0 */
757   USHORT        class2Count;            /* Number of classes in ClassDef2
758                                          * table--includes Class0 */
759   ValueRecord   values;                 /* Matrix of value pairs:
760                                          * class1-major, class2-minor,
761                                          * Each entry has value1 and value2 */
762   public:
763   DEFINE_SIZE_VAR (16, ValueRecord);
764 };
765
766 struct PairPos
767 {
768   friend struct PosLookupSubTable;
769
770   private:
771   inline bool apply (hb_apply_context_t *context) const
772   {
773     TRACE_APPLY ();
774     switch (u.format) {
775     case 1: return u.format1->apply (context);
776     case 2: return u.format2->apply (context);
777     default:return false;
778     }
779   }
780
781   inline bool sanitize (hb_sanitize_context_t *context) {
782     TRACE_SANITIZE ();
783     if (!u.format.sanitize (context)) return false;
784     switch (u.format) {
785     case 1: return u.format1->sanitize (context);
786     case 2: return u.format2->sanitize (context);
787     default:return true;
788     }
789   }
790
791   private:
792   union {
793   USHORT                format;         /* Format identifier */
794   PairPosFormat1        format1[VAR];
795   PairPosFormat2        format2[VAR];
796   } u;
797 };
798
799
800 struct EntryExitRecord
801 {
802   friend struct CursivePosFormat1;
803
804   inline bool sanitize (hb_sanitize_context_t *context, void *base) {
805     TRACE_SANITIZE ();
806     return entryAnchor.sanitize (context, base)
807         && exitAnchor.sanitize (context, base);
808   }
809
810   private:
811   OffsetTo<Anchor>
812                 entryAnchor;            /* Offset to EntryAnchor table--from
813                                          * beginning of CursivePos
814                                          * subtable--may be NULL */
815   OffsetTo<Anchor>
816                 exitAnchor;             /* Offset to ExitAnchor table--from
817                                          * beginning of CursivePos
818                                          * subtable--may be NULL */
819   public:
820   DEFINE_SIZE_STATIC (4);
821 };
822
823 struct CursivePosFormat1
824 {
825   friend struct CursivePos;
826
827   private:
828   inline bool apply (hb_apply_context_t *context) const
829   {
830     TRACE_APPLY ();
831     /* Now comes the messiest part of the whole OpenType
832        specification.  At first glance, cursive connections seem easy
833        to understand, but there are pitfalls!  The reason is that
834        the specs don't mention how to compute the advance values
835        resp. glyph offsets.  I was told it would be an omission, to
836        be fixed in the next OpenType version...  Again many thanks to
837        Andrei Burago <andreib@microsoft.com> for clarifications.
838
839        Consider the following example:
840
841                         |  xadv1    |
842                          +---------+
843                          |         |
844                    +-----+--+ 1    |
845                    |     | .|      |
846                    |    0+--+------+
847                    |   2    |
848                    |        |
849                   0+--------+
850                   |  xadv2   |
851
852          glyph1: advance width = 12
853                  anchor point = (3,1)
854
855          glyph2: advance width = 11
856                  anchor point = (9,4)
857
858          LSB is 1 for both glyphs (so the boxes drawn above are glyph
859          bboxes).  Writing direction is R2L; `0' denotes the glyph's
860          coordinate origin.
861
862        Now the surprising part: The advance width of the *left* glyph
863        (resp. of the *bottom* glyph) will be modified, no matter
864        whether the writing direction is L2R or R2L (resp. T2B or
865        B2T)!  This assymetry is caused by the fact that the glyph's
866        coordinate origin is always the lower left corner for all
867        writing directions.
868
869        Continuing the above example, we can compute the new
870        (horizontal) advance width of glyph2 as
871
872          9 - 3 = 6  ,
873
874        and the new vertical offset of glyph2 as
875
876          1 - 4 = -3  .
877
878
879        Vertical writing direction is far more complicated:
880
881        a) Assuming that we recompute the advance height of the lower glyph:
882
883                                     --
884                          +---------+
885                 --       |         |
886                    +-----+--+ 1    | yadv1
887                    |     | .|      |
888              yadv2 |    0+--+------+        -- BSB1  --
889                    |   2    |       --      --        y_offset
890                    |        |
891      BSB2 --      0+--------+                        --
892           --    --
893
894          glyph1: advance height = 6
895                  anchor point = (3,1)
896
897          glyph2: advance height = 7
898                  anchor point = (9,4)
899
900          TSB is 1 for both glyphs; writing direction is T2B.
901
902
903            BSB1     = yadv1 - (TSB1 + ymax1)
904            BSB2     = yadv2 - (TSB2 + ymax2)
905            y_offset = y2 - y1
906
907          vertical advance width of glyph2
908            = y_offset + BSB2 - BSB1
909            = (y2 - y1) + (yadv2 - (TSB2 + ymax2)) - (yadv1 - (TSB1 + ymax1))
910            = y2 - y1 + yadv2 - TSB2 - ymax2 - (yadv1 - TSB1 - ymax1)
911            = y2 - y1 + yadv2 - TSB2 - ymax2 - yadv1 + TSB1 + ymax1
912
913
914        b) Assuming that we recompute the advance height of the upper glyph:
915
916                                     --      --
917                          +---------+        -- TSB1
918           --    --       |         |
919      TSB2 --       +-----+--+ 1    | yadv1   ymax1
920                    |     | .|      |
921              yadv2 |    0+--+------+        --       --
922       ymax2        |   2    |       --                y_offset
923                    |        |
924           --      0+--------+                        --
925                 --
926
927          glyph1: advance height = 6
928                  anchor point = (3,1)
929
930          glyph2: advance height = 7
931                  anchor point = (9,4)
932
933          TSB is 1 for both glyphs; writing direction is T2B.
934
935          y_offset = y2 - y1
936
937          vertical advance width of glyph2
938            = TSB1 + ymax1 + y_offset - (TSB2 + ymax2)
939            = TSB1 + ymax1 + y2 - y1 - TSB2 - ymax2
940
941
942        Comparing a) with b) shows that b) is easier to compute.  I'll wait
943        for a reply from Andrei to see what should really be implemented...
944
945        Since horizontal advance widths or vertical advance heights
946        can be used alone but not together, no ambiguity occurs.        */
947
948     struct hb_ot_layout_context_t::info_t::gpos_t *gpi = &context->layout->info.gpos;
949     hb_codepoint_t last_pos = gpi->last;
950     gpi->last = HB_OT_LAYOUT_GPOS_NO_LAST;
951
952     /* We don't handle mark glyphs here. */
953     if (context->property == HB_OT_LAYOUT_GLYPH_CLASS_MARK)
954       return false;
955
956     unsigned int index = (this+coverage) (IN_CURGLYPH ());
957     if (likely (index == NOT_COVERED))
958       return false;
959
960     const EntryExitRecord &record = entryExitRecord[index];
961
962     if (last_pos == HB_OT_LAYOUT_GPOS_NO_LAST || !record.entryAnchor)
963       goto end;
964
965     hb_position_t entry_x, entry_y;
966     (this+record.entryAnchor).get_anchor (context->layout, IN_CURGLYPH (), &entry_x, &entry_y);
967
968     /* TODO vertical */
969
970     if (context->buffer->direction == HB_DIRECTION_RTL)
971     {
972       /* advance is absolute, not relative */
973       POSITION (context->buffer->in_pos)->x_advance = entry_x - gpi->anchor_x;
974     }
975     else
976     {
977       /* advance is absolute, not relative */
978       POSITION (last_pos)->x_advance = gpi->anchor_x - entry_x;
979     }
980
981     if  (context->lookup_flag & LookupFlag::RightToLeft)
982     {
983       POSITION (last_pos)->cursive_chain = last_pos - context->buffer->in_pos;
984       POSITION (last_pos)->y_offset = entry_y - gpi->anchor_y;
985     }
986     else
987     {
988       POSITION (context->buffer->in_pos)->cursive_chain = context->buffer->in_pos - last_pos;
989       POSITION (context->buffer->in_pos)->y_offset = gpi->anchor_y - entry_y;
990     }
991
992   end:
993     if (record.exitAnchor)
994     {
995       gpi->last = context->buffer->in_pos;
996       (this+record.exitAnchor).get_anchor (context->layout, IN_CURGLYPH (), &gpi->anchor_x, &gpi->anchor_y);
997     }
998
999     context->buffer->in_pos++;
1000     return true;
1001   }
1002
1003   inline bool sanitize (hb_sanitize_context_t *context) {
1004     TRACE_SANITIZE ();
1005     return coverage.sanitize (context, this)
1006         && entryExitRecord.sanitize (context, this);
1007   }
1008
1009   private:
1010   USHORT        format;                 /* Format identifier--format = 1 */
1011   OffsetTo<Coverage>
1012                 coverage;               /* Offset to Coverage table--from
1013                                          * beginning of subtable */
1014   ArrayOf<EntryExitRecord>
1015                 entryExitRecord;        /* Array of EntryExit records--in
1016                                          * Coverage Index order */
1017   public:
1018   DEFINE_SIZE_VAR (6, EntryExitRecord);
1019 };
1020
1021 struct CursivePos
1022 {
1023   friend struct PosLookupSubTable;
1024
1025   private:
1026   inline bool apply (hb_apply_context_t *context) const
1027   {
1028     TRACE_APPLY ();
1029     switch (u.format) {
1030     case 1: return u.format1->apply (context);
1031     default:return false;
1032     }
1033   }
1034
1035   inline bool sanitize (hb_sanitize_context_t *context) {
1036     TRACE_SANITIZE ();
1037     if (!u.format.sanitize (context)) return false;
1038     switch (u.format) {
1039     case 1: return u.format1->sanitize (context);
1040     default:return true;
1041     }
1042   }
1043
1044   private:
1045   union {
1046   USHORT                format;         /* Format identifier */
1047   CursivePosFormat1     format1[VAR];
1048   } u;
1049 };
1050
1051
1052 typedef AnchorMatrix BaseArray;         /* base-major--
1053                                          * in order of BaseCoverage Index--,
1054                                          * mark-minor--
1055                                          * ordered by class--zero-based. */
1056
1057 struct MarkBasePosFormat1
1058 {
1059   friend struct MarkBasePos;
1060
1061   private:
1062   inline bool apply (hb_apply_context_t *context) const
1063   {
1064     TRACE_APPLY ();
1065     unsigned int mark_index = (this+markCoverage) (IN_CURGLYPH ());
1066     if (likely (mark_index == NOT_COVERED))
1067       return false;
1068
1069     /* now we search backwards for a non-mark glyph */
1070     unsigned int property;
1071     unsigned int j = context->buffer->in_pos;
1072     do
1073     {
1074       if (unlikely (!j))
1075         return false;
1076       j--;
1077     } while (_hb_ot_layout_skip_mark (context->layout->face, IN_INFO (j), LookupFlag::IgnoreMarks, &property));
1078
1079     /* The following assertion is too strong, so we've disabled it. */
1080     if (false && !(property & HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH))
1081       return false;
1082
1083     unsigned int base_index = (this+baseCoverage) (IN_GLYPH (j));
1084     if (base_index == NOT_COVERED)
1085       return false;
1086
1087     return (this+markArray).apply (context, mark_index, base_index, this+baseArray, classCount, j);
1088   }
1089
1090   inline bool sanitize (hb_sanitize_context_t *context) {
1091     TRACE_SANITIZE ();
1092     return context->check_struct (this)
1093         && markCoverage.sanitize (context, this)
1094         && baseCoverage.sanitize (context, this)
1095         && markArray.sanitize (context, this)
1096         && likely (baseArray.sanitize (context, this, (unsigned int) classCount));
1097   }
1098
1099   private:
1100   USHORT        format;                 /* Format identifier--format = 1 */
1101   OffsetTo<Coverage>
1102                 markCoverage;           /* Offset to MarkCoverage table--from
1103                                          * beginning of MarkBasePos subtable */
1104   OffsetTo<Coverage>
1105                 baseCoverage;           /* Offset to BaseCoverage table--from
1106                                          * beginning of MarkBasePos subtable */
1107   USHORT        classCount;             /* Number of classes defined for marks */
1108   OffsetTo<MarkArray>
1109                 markArray;              /* Offset to MarkArray table--from
1110                                          * beginning of MarkBasePos subtable */
1111   OffsetTo<BaseArray>
1112                 baseArray;              /* Offset to BaseArray table--from
1113                                          * beginning of MarkBasePos subtable */
1114   public:
1115   DEFINE_SIZE_STATIC (12);
1116 };
1117
1118 struct MarkBasePos
1119 {
1120   friend struct PosLookupSubTable;
1121
1122   private:
1123   inline bool apply (hb_apply_context_t *context) const
1124   {
1125     TRACE_APPLY ();
1126     switch (u.format) {
1127     case 1: return u.format1->apply (context);
1128     default:return false;
1129     }
1130   }
1131
1132   inline bool sanitize (hb_sanitize_context_t *context) {
1133     TRACE_SANITIZE ();
1134     if (!u.format.sanitize (context)) return false;
1135     switch (u.format) {
1136     case 1: return u.format1->sanitize (context);
1137     default:return true;
1138     }
1139   }
1140
1141   private:
1142   union {
1143   USHORT                format;         /* Format identifier */
1144   MarkBasePosFormat1    format1[VAR];
1145   } u;
1146 };
1147
1148
1149 typedef AnchorMatrix LigatureAttach;    /* component-major--
1150                                          * in order of writing direction--,
1151                                          * mark-minor--
1152                                          * ordered by class--zero-based. */
1153
1154 typedef OffsetListOf<LigatureAttach> LigatureArray;
1155                                         /* Array of LigatureAttach
1156                                          * tables ordered by
1157                                          * LigatureCoverage Index */
1158
1159 struct MarkLigPosFormat1
1160 {
1161   friend struct MarkLigPos;
1162
1163   private:
1164   inline bool apply (hb_apply_context_t *context) const
1165   {
1166     TRACE_APPLY ();
1167     unsigned int mark_index = (this+markCoverage) (IN_CURGLYPH ());
1168     if (likely (mark_index == NOT_COVERED))
1169       return false;
1170
1171     /* now we search backwards for a non-mark glyph */
1172     unsigned int property;
1173     unsigned int j = context->buffer->in_pos;
1174     do
1175     {
1176       if (unlikely (!j))
1177         return false;
1178       j--;
1179     } while (_hb_ot_layout_skip_mark (context->layout->face, IN_INFO (j), LookupFlag::IgnoreMarks, &property));
1180
1181     /* The following assertion is too strong, so we've disabled it. */
1182     if (false && !(property & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE))
1183       return false;
1184
1185     unsigned int lig_index = (this+ligatureCoverage) (IN_GLYPH (j));
1186     if (lig_index == NOT_COVERED)
1187       return false;
1188
1189     const LigatureArray& lig_array = this+ligatureArray;
1190     const LigatureAttach& lig_attach = lig_array[lig_index];
1191
1192     /* Find component to attach to */
1193     unsigned int comp_count = lig_attach.rows;
1194     if (unlikely (!comp_count))
1195       return false;
1196     unsigned int comp_index;
1197     /* We must now check whether the ligature ID of the current mark glyph
1198      * is identical to the ligature ID of the found ligature.  If yes, we
1199      * can directly use the component index.  If not, we attach the mark
1200      * glyph to the last component of the ligature. */
1201     if (IN_LIGID (j) && IN_LIGID (j) == IN_LIGID (context->buffer->in_pos) && IN_COMPONENT (context->buffer->in_pos))
1202     {
1203       comp_index = IN_COMPONENT (context->buffer->in_pos) - 1;
1204       if (comp_index >= comp_count)
1205         comp_index = comp_count - 1;
1206     }
1207     else
1208       comp_index = comp_count - 1;
1209
1210     return (this+markArray).apply (context, mark_index, comp_index, lig_attach, classCount, j);
1211   }
1212
1213   inline bool sanitize (hb_sanitize_context_t *context) {
1214     TRACE_SANITIZE ();
1215     return context->check_struct (this)
1216         && markCoverage.sanitize (context, this)
1217         && ligatureCoverage.sanitize (context, this)
1218         && markArray.sanitize (context, this)
1219         && likely (ligatureArray.sanitize (context, this, (unsigned int) classCount));
1220   }
1221
1222   private:
1223   USHORT        format;                 /* Format identifier--format = 1 */
1224   OffsetTo<Coverage>
1225                 markCoverage;           /* Offset to Mark Coverage table--from
1226                                          * beginning of MarkLigPos subtable */
1227   OffsetTo<Coverage>
1228                 ligatureCoverage;       /* Offset to Ligature Coverage
1229                                          * table--from beginning of MarkLigPos
1230                                          * subtable */
1231   USHORT        classCount;             /* Number of defined mark classes */
1232   OffsetTo<MarkArray>
1233                 markArray;              /* Offset to MarkArray table--from
1234                                          * beginning of MarkLigPos subtable */
1235   OffsetTo<LigatureArray>
1236                 ligatureArray;          /* Offset to LigatureArray table--from
1237                                          * beginning of MarkLigPos subtable */
1238   public:
1239   DEFINE_SIZE_STATIC (12);
1240 };
1241
1242 struct MarkLigPos
1243 {
1244   friend struct PosLookupSubTable;
1245
1246   private:
1247   inline bool apply (hb_apply_context_t *context) const
1248   {
1249     TRACE_APPLY ();
1250     switch (u.format) {
1251     case 1: return u.format1->apply (context);
1252     default:return false;
1253     }
1254   }
1255
1256   inline bool sanitize (hb_sanitize_context_t *context) {
1257     TRACE_SANITIZE ();
1258     if (!u.format.sanitize (context)) return false;
1259     switch (u.format) {
1260     case 1: return u.format1->sanitize (context);
1261     default:return true;
1262     }
1263   }
1264
1265   private:
1266   union {
1267   USHORT                format;         /* Format identifier */
1268   MarkLigPosFormat1     format1[VAR];
1269   } u;
1270 };
1271
1272
1273 typedef AnchorMatrix Mark2Array;        /* mark2-major--
1274                                          * in order of Mark2Coverage Index--,
1275                                          * mark1-minor--
1276                                          * ordered by class--zero-based. */
1277
1278 struct MarkMarkPosFormat1
1279 {
1280   friend struct MarkMarkPos;
1281
1282   private:
1283   inline bool apply (hb_apply_context_t *context) const
1284   {
1285     TRACE_APPLY ();
1286     unsigned int mark1_index = (this+mark1Coverage) (IN_CURGLYPH ());
1287     if (likely (mark1_index == NOT_COVERED))
1288       return false;
1289
1290     /* now we search backwards for a suitable mark glyph until a non-mark glyph */
1291     unsigned int property;
1292     unsigned int j = context->buffer->in_pos;
1293     do
1294     {
1295       if (unlikely (!j))
1296         return false;
1297       j--;
1298     } while (_hb_ot_layout_skip_mark (context->layout->face, IN_INFO (j), context->lookup_flag, &property));
1299
1300     if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK))
1301       return false;
1302
1303     /* Two marks match only if they belong to the same base, or same component
1304      * of the same ligature.  That is, the component numbers must match, and
1305      * if those are non-zero, the ligid number should also match. */
1306     if ((IN_COMPONENT (j) != IN_COMPONENT (context->buffer->in_pos)) ||
1307         (IN_COMPONENT (j) && IN_LIGID (j) != IN_LIGID (context->buffer->in_pos)))
1308       return false;
1309
1310     unsigned int mark2_index = (this+mark2Coverage) (IN_GLYPH (j));
1311     if (mark2_index == NOT_COVERED)
1312       return false;
1313
1314     return (this+mark1Array).apply (context, mark1_index, mark2_index, this+mark2Array, classCount, j);
1315   }
1316
1317   inline bool sanitize (hb_sanitize_context_t *context) {
1318     TRACE_SANITIZE ();
1319     return context->check_struct (this)
1320         && mark1Coverage.sanitize (context, this)
1321         && mark2Coverage.sanitize (context, this)
1322         && mark1Array.sanitize (context, this)
1323         && likely (mark2Array.sanitize (context, this, (unsigned int) classCount));
1324   }
1325
1326   private:
1327   USHORT        format;                 /* Format identifier--format = 1 */
1328   OffsetTo<Coverage>
1329                 mark1Coverage;          /* Offset to Combining Mark1 Coverage
1330                                          * table--from beginning of MarkMarkPos
1331                                          * subtable */
1332   OffsetTo<Coverage>
1333                 mark2Coverage;          /* Offset to Combining Mark2 Coverage
1334                                          * table--from beginning of MarkMarkPos
1335                                          * subtable */
1336   USHORT        classCount;             /* Number of defined mark classes */
1337   OffsetTo<MarkArray>
1338                 mark1Array;             /* Offset to Mark1Array table--from
1339                                          * beginning of MarkMarkPos subtable */
1340   OffsetTo<Mark2Array>
1341                 mark2Array;             /* Offset to Mark2Array table--from
1342                                          * beginning of MarkMarkPos subtable */
1343   public:
1344   DEFINE_SIZE_STATIC (12);
1345 };
1346
1347 struct MarkMarkPos
1348 {
1349   friend struct PosLookupSubTable;
1350
1351   private:
1352   inline bool apply (hb_apply_context_t *context) const
1353   {
1354     TRACE_APPLY ();
1355     switch (u.format) {
1356     case 1: return u.format1->apply (context);
1357     default:return false;
1358     }
1359   }
1360
1361   inline bool sanitize (hb_sanitize_context_t *context) {
1362     TRACE_SANITIZE ();
1363     if (!u.format.sanitize (context)) return false;
1364     switch (u.format) {
1365     case 1: return u.format1->sanitize (context);
1366     default:return true;
1367     }
1368   }
1369
1370   private:
1371   union {
1372   USHORT                format;         /* Format identifier */
1373   MarkMarkPosFormat1    format1[VAR];
1374   } u;
1375 };
1376
1377
1378 static inline bool position_lookup (hb_apply_context_t *context, unsigned int lookup_index);
1379
1380 struct ContextPos : Context
1381 {
1382   friend struct PosLookupSubTable;
1383
1384   private:
1385   inline bool apply (hb_apply_context_t *context) const
1386   {
1387     TRACE_APPLY ();
1388     return Context::apply (context, position_lookup);
1389   }
1390 };
1391
1392 struct ChainContextPos : ChainContext
1393 {
1394   friend struct PosLookupSubTable;
1395
1396   private:
1397   inline bool apply (hb_apply_context_t *context) const
1398   {
1399     TRACE_APPLY ();
1400     return ChainContext::apply (context, position_lookup);
1401   }
1402 };
1403
1404
1405 struct ExtensionPos : Extension
1406 {
1407   friend struct PosLookupSubTable;
1408
1409   private:
1410   inline const struct PosLookupSubTable& get_subtable (void) const
1411   {
1412     unsigned int offset = get_offset ();
1413     if (unlikely (!offset)) return Null(PosLookupSubTable);
1414     return StructAtOffset<PosLookupSubTable> (this, offset);
1415   }
1416
1417   inline bool apply (hb_apply_context_t *context) const;
1418
1419   inline bool sanitize (hb_sanitize_context_t *context);
1420 };
1421
1422
1423
1424 /*
1425  * PosLookup
1426  */
1427
1428
1429 struct PosLookupSubTable
1430 {
1431   friend struct PosLookup;
1432
1433   enum {
1434     Single              = 1,
1435     Pair                = 2,
1436     Cursive             = 3,
1437     MarkBase            = 4,
1438     MarkLig             = 5,
1439     MarkMark            = 6,
1440     Context             = 7,
1441     ChainContext        = 8,
1442     Extension           = 9
1443   };
1444
1445   inline bool apply (hb_apply_context_t *context, unsigned int lookup_type) const
1446   {
1447     TRACE_APPLY ();
1448     switch (lookup_type) {
1449     case Single:                return u.single->apply (context);
1450     case Pair:                  return u.pair->apply (context);
1451     case Cursive:               return u.cursive->apply (context);
1452     case MarkBase:              return u.markBase->apply (context);
1453     case MarkLig:               return u.markLig->apply (context);
1454     case MarkMark:              return u.markMark->apply (context);
1455     case Context:               return u.context->apply (context);
1456     case ChainContext:          return u.chainContext->apply (context);
1457     case Extension:             return u.extension->apply (context);
1458     default:return false;
1459     }
1460   }
1461
1462   inline bool sanitize (hb_sanitize_context_t *context) {
1463     TRACE_SANITIZE ();
1464     if (!u.format.sanitize (context)) return false;
1465     switch (u.format) {
1466     case Single:                return u.single->sanitize (context);
1467     case Pair:                  return u.pair->sanitize (context);
1468     case Cursive:               return u.cursive->sanitize (context);
1469     case MarkBase:              return u.markBase->sanitize (context);
1470     case MarkLig:               return u.markLig->sanitize (context);
1471     case MarkMark:              return u.markMark->sanitize (context);
1472     case Context:               return u.context->sanitize (context);
1473     case ChainContext:          return u.chainContext->sanitize (context);
1474     case Extension:             return u.extension->sanitize (context);
1475     default:return true;
1476     }
1477   }
1478
1479   private:
1480   union {
1481   USHORT                format;
1482   SinglePos             single[VAR];
1483   PairPos               pair[VAR];
1484   CursivePos            cursive[VAR];
1485   MarkBasePos           markBase[VAR];
1486   MarkLigPos            markLig[VAR];
1487   MarkMarkPos           markMark[VAR];
1488   ContextPos            context[VAR];
1489   ChainContextPos       chainContext[VAR];
1490   ExtensionPos          extension[VAR];
1491   } u;
1492   public:
1493   DEFINE_SIZE_MIN (2);
1494 };
1495
1496
1497 struct PosLookup : Lookup
1498 {
1499   inline const PosLookupSubTable& get_subtable (unsigned int i) const
1500   { return this+CastR<OffsetArrayOf<PosLookupSubTable> > (subTable)[i]; }
1501
1502   inline bool apply_once (hb_ot_layout_context_t *layout,
1503                           hb_buffer_t    *buffer,
1504                           unsigned int    context_length,
1505                           unsigned int    nesting_level_left) const
1506   {
1507     unsigned int lookup_type = get_type ();
1508     hb_apply_context_t context[1] = {{0}};
1509
1510     context->layout = layout;
1511     context->buffer = buffer;
1512     context->context_length = context_length;
1513     context->nesting_level_left = nesting_level_left;
1514     context->lookup_flag = get_flag ();
1515
1516     if (!_hb_ot_layout_check_glyph_property (context->layout->face, IN_CURINFO (), context->lookup_flag, &context->property))
1517       return false;
1518
1519     for (unsigned int i = 0; i < get_subtable_count (); i++)
1520       if (get_subtable (i).apply (context, lookup_type))
1521         return true;
1522
1523     return false;
1524   }
1525
1526    inline bool apply_string (hb_ot_layout_context_t *layout,
1527                              hb_buffer_t *buffer,
1528                              hb_mask_t    mask) const
1529   {
1530 #undef BUFFER
1531 #define BUFFER buffer
1532     bool ret = false;
1533
1534     if (unlikely (!buffer->in_length))
1535       return false;
1536
1537     layout->info.gpos.last = HB_OT_LAYOUT_GPOS_NO_LAST; /* no last valid glyph for cursive pos. */
1538
1539     buffer->in_pos = 0;
1540     while (buffer->in_pos < buffer->in_length)
1541     {
1542       bool done;
1543       if (~IN_MASK (buffer->in_pos) & mask)
1544       {
1545           done = apply_once (layout, buffer, NO_CONTEXT, MAX_NESTING_LEVEL);
1546           ret |= done;
1547       }
1548       else
1549       {
1550           done = false;
1551           /* Contrary to properties defined in GDEF, user-defined properties
1552              will always stop a possible cursive positioning.                */
1553           layout->info.gpos.last = HB_OT_LAYOUT_GPOS_NO_LAST;
1554       }
1555
1556       if (!done)
1557         buffer->in_pos++;
1558     }
1559
1560     return ret;
1561   }
1562
1563   inline bool sanitize (hb_sanitize_context_t *context) {
1564     TRACE_SANITIZE ();
1565     if (unlikely (!Lookup::sanitize (context))) return false;
1566     OffsetArrayOf<PosLookupSubTable> &list = CastR<OffsetArrayOf<PosLookupSubTable> > (subTable);
1567     return list.sanitize (context, this);
1568   }
1569 };
1570
1571 typedef OffsetListOf<PosLookup> PosLookupList;
1572
1573 /*
1574  * GPOS
1575  */
1576
1577 struct GPOS : GSUBGPOS
1578 {
1579   static const hb_tag_t Tag     = HB_OT_TAG_GPOS;
1580
1581   inline const PosLookup& get_lookup (unsigned int i) const
1582   { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
1583
1584   inline bool position_lookup (hb_ot_layout_context_t *layout,
1585                                hb_buffer_t  *buffer,
1586                                unsigned int  lookup_index,
1587                                hb_mask_t     mask) const
1588   { return get_lookup (lookup_index).apply_string (layout, buffer, mask); }
1589
1590   inline bool sanitize (hb_sanitize_context_t *context) {
1591     TRACE_SANITIZE ();
1592     if (unlikely (!GSUBGPOS::sanitize (context))) return false;
1593     OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
1594     return list.sanitize (context, this);
1595   }
1596   public:
1597   DEFINE_SIZE_STATIC (10);
1598 };
1599
1600
1601 /* Out-of-class implementation for methods recursing */
1602
1603 inline bool ExtensionPos::apply (hb_apply_context_t *context) const
1604 {
1605   TRACE_APPLY ();
1606   return get_subtable ().apply (context, get_type ());
1607 }
1608
1609 inline bool ExtensionPos::sanitize (hb_sanitize_context_t *context)
1610 {
1611   TRACE_SANITIZE ();
1612   if (unlikely (!Extension::sanitize (context))) return false;
1613   unsigned int offset = get_offset ();
1614   if (unlikely (!offset)) return true;
1615   return StructAtOffset<PosLookupSubTable> (this, offset).sanitize (context);
1616 }
1617
1618 static inline bool position_lookup (hb_apply_context_t *context, unsigned int lookup_index)
1619 {
1620   const GPOS &gpos = *(context->layout->face->ot_layout.gpos);
1621   const PosLookup &l = gpos.get_lookup (lookup_index);
1622
1623   if (unlikely (context->nesting_level_left == 0))
1624     return false;
1625
1626   if (unlikely (context->context_length < 1))
1627     return false;
1628
1629   return l.apply_once (context->layout, context->buffer, context->context_length, context->nesting_level_left - 1);
1630 }
1631
1632
1633 #endif /* HB_OT_LAYOUT_GPOS_PRIVATE_HH */