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