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