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