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