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