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