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