• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
3  * Copyright © 2010,2012  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_TABLE_HH
30 #define HB_OT_LAYOUT_GPOS_TABLE_HH
31 
32 #include "hb-ot-layout-gsubgpos-private.hh"
33 
34 
35 namespace OT {
36 
37 
38 /* buffer **position** var allocations */
39 #define attach_lookback() var.u16[0] /* number of glyphs to go back to attach this glyph to its base */
40 #define cursive_chain() var.i16[1] /* character to which this connects, may be positive or negative */
41 
42 
43 /* Shared Tables: ValueRecord, Anchor Table, and MarkArray */
44 
45 typedef USHORT Value;
46 
47 typedef Value ValueRecord[VAR];
48 
49 struct ValueFormat : USHORT
50 {
51   enum Flags {
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 
get_lenOT::ValueFormat92   inline unsigned int get_len (void) const
93   { return _hb_popcount32 ((unsigned int) *this); }
get_sizeOT::ValueFormat94   inline unsigned int get_size (void) const
95   { return get_len () * Value::static_size; }
96 
apply_valueOT::ValueFormat97   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:
sanitize_value_devicesOT::ValueFormat143   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 
get_deviceOT::ValueFormat159   static inline OffsetTo<Device>& get_device (Value* value)
160   { return *CastP<OffsetTo<Device> > (value); }
get_deviceOT::ValueFormat161   static inline const OffsetTo<Device>& get_device (const Value* value)
162   { return *CastP<OffsetTo<Device> > (value); }
163 
get_shortOT::ValueFormat164   static inline const SHORT& get_short (const Value* value)
165   { return *CastP<SHORT> (value); }
166 
167   public:
168 
has_deviceOT::ValueFormat169   inline bool has_device (void) const {
170     unsigned int format = *this;
171     return (format & devices) != 0;
172   }
173 
sanitize_valueOT::ValueFormat174   inline bool sanitize_value (hb_sanitize_context_t *c, void *base, Value *values) {
175     TRACE_SANITIZE (this);
176     return TRACE_RETURN (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values)));
177   }
178 
sanitize_valuesOT::ValueFormat179   inline bool sanitize_values (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count) {
180     TRACE_SANITIZE (this);
181     unsigned int len = get_len ();
182 
183     if (!c->check_array (values, get_size (), count)) return TRACE_RETURN (false);
184 
185     if (!has_device ()) return TRACE_RETURN (true);
186 
187     for (unsigned int i = 0; i < count; i++) {
188       if (!sanitize_value_devices (c, base, values))
189         return TRACE_RETURN (false);
190       values += len;
191     }
192 
193     return TRACE_RETURN (true);
194   }
195 
196   /* Just sanitize referenced Device tables.  Doesn't check the values themselves. */
sanitize_values_stride_unsafeOT::ValueFormat197   inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count, unsigned int stride) {
198     TRACE_SANITIZE (this);
199 
200     if (!has_device ()) return TRACE_RETURN (true);
201 
202     for (unsigned int i = 0; i < count; i++) {
203       if (!sanitize_value_devices (c, base, values))
204         return TRACE_RETURN (false);
205       values += stride;
206     }
207 
208     return TRACE_RETURN (true);
209   }
210 };
211 
212 
213 struct AnchorFormat1
214 {
get_anchorOT::AnchorFormat1215   inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
216 			  hb_position_t *x, hb_position_t *y) const
217   {
218       *x = font->em_scale_x (xCoordinate);
219       *y = font->em_scale_y (yCoordinate);
220   }
221 
sanitizeOT::AnchorFormat1222   inline bool sanitize (hb_sanitize_context_t *c) {
223     TRACE_SANITIZE (this);
224     return TRACE_RETURN (c->check_struct (this));
225   }
226 
227   protected:
228   USHORT	format;			/* Format identifier--format = 1 */
229   SHORT		xCoordinate;		/* Horizontal value--in design units */
230   SHORT		yCoordinate;		/* Vertical value--in design units */
231   public:
232   DEFINE_SIZE_STATIC (6);
233 };
234 
235 struct AnchorFormat2
236 {
get_anchorOT::AnchorFormat2237   inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
238 			  hb_position_t *x, hb_position_t *y) const
239   {
240       unsigned int x_ppem = font->x_ppem;
241       unsigned int y_ppem = font->y_ppem;
242       hb_position_t cx, cy;
243       hb_bool_t ret = false;
244 
245       if (x_ppem || y_ppem)
246 	ret = font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
247       *x = x_ppem && ret ? cx : font->em_scale_x (xCoordinate);
248       *y = y_ppem && ret ? cy : font->em_scale_y (yCoordinate);
249   }
250 
sanitizeOT::AnchorFormat2251   inline bool sanitize (hb_sanitize_context_t *c) {
252     TRACE_SANITIZE (this);
253     return TRACE_RETURN (c->check_struct (this));
254   }
255 
256   protected:
257   USHORT	format;			/* Format identifier--format = 2 */
258   SHORT		xCoordinate;		/* Horizontal value--in design units */
259   SHORT		yCoordinate;		/* Vertical value--in design units */
260   USHORT	anchorPoint;		/* Index to glyph contour point */
261   public:
262   DEFINE_SIZE_STATIC (8);
263 };
264 
265 struct AnchorFormat3
266 {
get_anchorOT::AnchorFormat3267   inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
268 			  hb_position_t *x, hb_position_t *y) const
269   {
270       *x = font->em_scale_x (xCoordinate);
271       *y = font->em_scale_y (yCoordinate);
272 
273       if (font->x_ppem)
274 	*x += (this+xDeviceTable).get_x_delta (font);
275       if (font->y_ppem)
276 	*y += (this+yDeviceTable).get_x_delta (font);
277   }
278 
sanitizeOT::AnchorFormat3279   inline bool sanitize (hb_sanitize_context_t *c) {
280     TRACE_SANITIZE (this);
281     return TRACE_RETURN (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
282   }
283 
284   protected:
285   USHORT	format;			/* Format identifier--format = 3 */
286   SHORT		xCoordinate;		/* Horizontal value--in design units */
287   SHORT		yCoordinate;		/* Vertical value--in design units */
288   OffsetTo<Device>
289 		xDeviceTable;		/* Offset to Device table for X
290 					 * coordinate-- from beginning of
291 					 * Anchor table (may be NULL) */
292   OffsetTo<Device>
293 		yDeviceTable;		/* Offset to Device table for Y
294 					 * coordinate-- from beginning of
295 					 * Anchor table (may be NULL) */
296   public:
297   DEFINE_SIZE_STATIC (10);
298 };
299 
300 struct Anchor
301 {
get_anchorOT::Anchor302   inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
303 			  hb_position_t *x, hb_position_t *y) const
304   {
305     *x = *y = 0;
306     switch (u.format) {
307     case 1: u.format1.get_anchor (font, glyph_id, x, y); return;
308     case 2: u.format2.get_anchor (font, glyph_id, x, y); return;
309     case 3: u.format3.get_anchor (font, glyph_id, x, y); return;
310     default:						 return;
311     }
312   }
313 
sanitizeOT::Anchor314   inline bool sanitize (hb_sanitize_context_t *c) {
315     TRACE_SANITIZE (this);
316     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
317     switch (u.format) {
318     case 1: return TRACE_RETURN (u.format1.sanitize (c));
319     case 2: return TRACE_RETURN (u.format2.sanitize (c));
320     case 3: return TRACE_RETURN (u.format3.sanitize (c));
321     default:return TRACE_RETURN (true);
322     }
323   }
324 
325   protected:
326   union {
327   USHORT		format;		/* Format identifier */
328   AnchorFormat1		format1;
329   AnchorFormat2		format2;
330   AnchorFormat3		format3;
331   } u;
332   public:
333   DEFINE_SIZE_UNION (2, format);
334 };
335 
336 
337 struct AnchorMatrix
338 {
get_anchorOT::AnchorMatrix339   inline const Anchor& get_anchor (unsigned int row, unsigned int col, unsigned int cols, bool *found) const {
340     *found = false;
341     if (unlikely (row >= rows || col >= cols)) return Null(Anchor);
342     *found = !matrix[row * cols + col].is_null ();
343     return this+matrix[row * cols + col];
344   }
345 
sanitizeOT::AnchorMatrix346   inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) {
347     TRACE_SANITIZE (this);
348     if (!c->check_struct (this)) return TRACE_RETURN (false);
349     if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return TRACE_RETURN (false);
350     unsigned int count = rows * cols;
351     if (!c->check_array (matrix, matrix[0].static_size, count)) return TRACE_RETURN (false);
352     for (unsigned int i = 0; i < count; i++)
353       if (!matrix[i].sanitize (c, this)) return TRACE_RETURN (false);
354     return TRACE_RETURN (true);
355   }
356 
357   USHORT	rows;			/* Number of rows */
358   protected:
359   OffsetTo<Anchor>
360 		matrix[VAR];		/* Matrix of offsets to Anchor tables--
361 					 * from beginning of AnchorMatrix table */
362   public:
363   DEFINE_SIZE_ARRAY (2, matrix);
364 };
365 
366 
367 struct MarkRecord
368 {
369   friend struct MarkArray;
370 
sanitizeOT::MarkRecord371   inline bool sanitize (hb_sanitize_context_t *c, void *base) {
372     TRACE_SANITIZE (this);
373     return TRACE_RETURN (c->check_struct (this) && markAnchor.sanitize (c, base));
374   }
375 
376   protected:
377   USHORT	klass;			/* Class defined for this mark */
378   OffsetTo<Anchor>
379 		markAnchor;		/* Offset to Anchor table--from
380 					 * beginning of MarkArray table */
381   public:
382   DEFINE_SIZE_STATIC (4);
383 };
384 
385 struct MarkArray : ArrayOf<MarkRecord>	/* Array of MarkRecords--in Coverage order */
386 {
applyOT::MarkArray387   inline bool apply (hb_apply_context_t *c,
388 		     unsigned int mark_index, unsigned int glyph_index,
389 		     const AnchorMatrix &anchors, unsigned int class_count,
390 		     unsigned int glyph_pos) const
391   {
392     TRACE_APPLY (this);
393     const MarkRecord &record = ArrayOf<MarkRecord>::operator[](mark_index);
394     unsigned int mark_class = record.klass;
395 
396     const Anchor& mark_anchor = this + record.markAnchor;
397     bool found;
398     const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count, &found);
399     /* If this subtable doesn't have an anchor for this base and this class,
400      * return false such that the subsequent subtables have a chance at it. */
401     if (unlikely (!found)) return TRACE_RETURN (false);
402 
403     hb_position_t mark_x, mark_y, base_x, base_y;
404 
405     mark_anchor.get_anchor (c->font, c->buffer->cur().codepoint, &mark_x, &mark_y);
406     glyph_anchor.get_anchor (c->font, c->buffer->info[glyph_pos].codepoint, &base_x, &base_y);
407 
408     hb_glyph_position_t &o = c->buffer->cur_pos();
409     o.x_offset = base_x - mark_x;
410     o.y_offset = base_y - mark_y;
411     o.attach_lookback() = c->buffer->idx - glyph_pos;
412 
413     c->buffer->idx++;
414     return TRACE_RETURN (true);
415   }
416 
sanitizeOT::MarkArray417   inline bool sanitize (hb_sanitize_context_t *c) {
418     TRACE_SANITIZE (this);
419     return TRACE_RETURN (ArrayOf<MarkRecord>::sanitize (c, this));
420   }
421 };
422 
423 
424 /* Lookups */
425 
426 struct SinglePosFormat1
427 {
collect_glyphsOT::SinglePosFormat1428   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
429   {
430     TRACE_COLLECT_GLYPHS (this);
431     (this+coverage).add_coverage (c->input);
432   }
433 
get_coverageOT::SinglePosFormat1434   inline const Coverage &get_coverage (void) const
435   {
436     return this+coverage;
437   }
438 
applyOT::SinglePosFormat1439   inline bool apply (hb_apply_context_t *c) const
440   {
441     TRACE_APPLY (this);
442     unsigned int index = (this+coverage).get_coverage  (c->buffer->cur().codepoint);
443     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
444 
445     valueFormat.apply_value (c->font, c->direction, this,
446 			     values, c->buffer->cur_pos());
447 
448     c->buffer->idx++;
449     return TRACE_RETURN (true);
450   }
451 
sanitizeOT::SinglePosFormat1452   inline bool sanitize (hb_sanitize_context_t *c) {
453     TRACE_SANITIZE (this);
454     return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && valueFormat.sanitize_value (c, this, values));
455   }
456 
457   protected:
458   USHORT	format;			/* Format identifier--format = 1 */
459   OffsetTo<Coverage>
460 		coverage;		/* Offset to Coverage table--from
461 					 * beginning of subtable */
462   ValueFormat	valueFormat;		/* Defines the types of data in the
463 					 * ValueRecord */
464   ValueRecord	values;			/* Defines positioning
465 					 * value(s)--applied to all glyphs in
466 					 * the Coverage table */
467   public:
468   DEFINE_SIZE_ARRAY (6, values);
469 };
470 
471 struct SinglePosFormat2
472 {
collect_glyphsOT::SinglePosFormat2473   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
474   {
475     TRACE_COLLECT_GLYPHS (this);
476     (this+coverage).add_coverage (c->input);
477   }
478 
get_coverageOT::SinglePosFormat2479   inline const Coverage &get_coverage (void) const
480   {
481     return this+coverage;
482   }
483 
applyOT::SinglePosFormat2484   inline bool apply (hb_apply_context_t *c) const
485   {
486     TRACE_APPLY (this);
487     unsigned int index = (this+coverage).get_coverage  (c->buffer->cur().codepoint);
488     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
489 
490     if (likely (index >= valueCount)) return TRACE_RETURN (false);
491 
492     valueFormat.apply_value (c->font, c->direction, this,
493 			     &values[index * valueFormat.get_len ()],
494 			     c->buffer->cur_pos());
495 
496     c->buffer->idx++;
497     return TRACE_RETURN (true);
498   }
499 
sanitizeOT::SinglePosFormat2500   inline bool sanitize (hb_sanitize_context_t *c) {
501     TRACE_SANITIZE (this);
502     return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && valueFormat.sanitize_values (c, this, values, valueCount));
503   }
504 
505   protected:
506   USHORT	format;			/* Format identifier--format = 2 */
507   OffsetTo<Coverage>
508 		coverage;		/* Offset to Coverage table--from
509 					 * beginning of subtable */
510   ValueFormat	valueFormat;		/* Defines the types of data in the
511 					 * ValueRecord */
512   USHORT	valueCount;		/* Number of ValueRecords */
513   ValueRecord	values;			/* Array of ValueRecords--positioning
514 					 * values applied to glyphs */
515   public:
516   DEFINE_SIZE_ARRAY (8, values);
517 };
518 
519 struct SinglePos
520 {
521   template <typename context_t>
dispatchOT::SinglePos522   inline typename context_t::return_t dispatch (context_t *c) const
523   {
524     TRACE_DISPATCH (this);
525     switch (u.format) {
526     case 1: return TRACE_RETURN (c->dispatch (u.format1));
527     case 2: return TRACE_RETURN (c->dispatch (u.format2));
528     default:return TRACE_RETURN (c->default_return_value ());
529     }
530   }
531 
sanitizeOT::SinglePos532   inline bool sanitize (hb_sanitize_context_t *c) {
533     TRACE_SANITIZE (this);
534     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
535     switch (u.format) {
536     case 1: return TRACE_RETURN (u.format1.sanitize (c));
537     case 2: return TRACE_RETURN (u.format2.sanitize (c));
538     default:return TRACE_RETURN (true);
539     }
540   }
541 
542   protected:
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   protected:
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 
collect_glyphsOT::PairSet569   inline void collect_glyphs (hb_collect_glyphs_context_t *c,
570 			      const ValueFormat *valueFormats) const
571   {
572     TRACE_COLLECT_GLYPHS (this);
573     unsigned int len1 = valueFormats[0].get_len ();
574     unsigned int len2 = valueFormats[1].get_len ();
575     unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
576 
577     const PairValueRecord *record = CastP<PairValueRecord> (array);
578     unsigned int count = len;
579     for (unsigned int i = 0; i < count; i++)
580     {
581       c->input->add (record->secondGlyph);
582       record = &StructAtOffset<PairValueRecord> (record, record_size);
583     }
584   }
585 
applyOT::PairSet586   inline bool apply (hb_apply_context_t *c,
587 		     const ValueFormat *valueFormats,
588 		     unsigned int pos) const
589   {
590     TRACE_APPLY (this);
591     unsigned int len1 = valueFormats[0].get_len ();
592     unsigned int len2 = valueFormats[1].get_len ();
593     unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
594 
595     const PairValueRecord *record = CastP<PairValueRecord> (array);
596     unsigned int count = len;
597     for (unsigned int i = 0; i < count; i++)
598     {
599       /* TODO bsearch */
600       if (c->buffer->info[pos].codepoint == record->secondGlyph)
601       {
602 	valueFormats[0].apply_value (c->font, c->direction, this,
603 				     &record->values[0], c->buffer->cur_pos());
604 	valueFormats[1].apply_value (c->font, c->direction, this,
605 				     &record->values[len1], c->buffer->pos[pos]);
606 	if (len2)
607 	  pos++;
608 	c->buffer->idx = pos;
609 	return TRACE_RETURN (true);
610       }
611       record = &StructAtOffset<PairValueRecord> (record, record_size);
612     }
613 
614     return TRACE_RETURN (false);
615   }
616 
617   struct sanitize_closure_t {
618     void *base;
619     ValueFormat *valueFormats;
620     unsigned int len1; /* valueFormats[0].get_len() */
621     unsigned int stride; /* 1 + len1 + len2 */
622   };
623 
sanitizeOT::PairSet624   inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) {
625     TRACE_SANITIZE (this);
626     if (!(c->check_struct (this)
627        && c->check_array (array, USHORT::static_size * closure->stride, len))) return TRACE_RETURN (false);
628 
629     unsigned int count = len;
630     PairValueRecord *record = CastP<PairValueRecord> (array);
631     return TRACE_RETURN (closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride)
632 		      && closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride));
633   }
634 
635   protected:
636   USHORT	len;			/* Number of PairValueRecords */
637   USHORT	array[VAR];		/* Array of PairValueRecords--ordered
638 					 * by GlyphID of the second glyph */
639   public:
640   DEFINE_SIZE_ARRAY (2, array);
641 };
642 
643 struct PairPosFormat1
644 {
collect_glyphsOT::PairPosFormat1645   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
646   {
647     TRACE_COLLECT_GLYPHS (this);
648     (this+coverage).add_coverage (c->input);
649     unsigned int count = pairSet.len;
650     for (unsigned int i = 0; i < count; i++)
651       (this+pairSet[i]).collect_glyphs (c, &valueFormat1);
652   }
653 
get_coverageOT::PairPosFormat1654   inline const Coverage &get_coverage (void) const
655   {
656     return this+coverage;
657   }
658 
applyOT::PairPosFormat1659   inline bool apply (hb_apply_context_t *c) const
660   {
661     TRACE_APPLY (this);
662     hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1);
663     if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
664 
665     unsigned int index = (this+coverage).get_coverage  (c->buffer->cur().codepoint);
666     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
667 
668     if (!skippy_iter.next ()) return TRACE_RETURN (false);
669 
670     return TRACE_RETURN ((this+pairSet[index]).apply (c, &valueFormat1, skippy_iter.idx));
671   }
672 
sanitizeOT::PairPosFormat1673   inline bool sanitize (hb_sanitize_context_t *c) {
674     TRACE_SANITIZE (this);
675 
676     unsigned int len1 = valueFormat1.get_len ();
677     unsigned int len2 = valueFormat2.get_len ();
678     PairSet::sanitize_closure_t closure = {
679       this,
680       &valueFormat1,
681       len1,
682       1 + len1 + len2
683     };
684 
685     return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
686   }
687 
688   protected:
689   USHORT	format;			/* Format identifier--format = 1 */
690   OffsetTo<Coverage>
691 		coverage;		/* Offset to Coverage table--from
692 					 * beginning of subtable */
693   ValueFormat	valueFormat1;		/* Defines the types of data in
694 					 * ValueRecord1--for the first glyph
695 					 * in the pair--may be zero (0) */
696   ValueFormat	valueFormat2;		/* Defines the types of data in
697 					 * ValueRecord2--for the second glyph
698 					 * in the pair--may be zero (0) */
699   OffsetArrayOf<PairSet>
700 		pairSet;		/* Array of PairSet tables
701 					 * ordered by Coverage Index */
702   public:
703   DEFINE_SIZE_ARRAY (10, pairSet);
704 };
705 
706 struct PairPosFormat2
707 {
collect_glyphsOT::PairPosFormat2708   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
709   {
710     TRACE_COLLECT_GLYPHS (this);
711     /* (this+coverage).add_coverage (c->input); // Don't need this. */
712 
713     /* TODO only add values for pairs that have nonzero adjustments. */
714 
715     unsigned int count1 = class1Count;
716     const ClassDef &klass1 = this+classDef1;
717     for (unsigned int i = 0; i < count1; i++)
718       klass1.add_class (c->input, i);
719 
720     unsigned int count2 = class2Count;
721     const ClassDef &klass2 = this+classDef2;
722     for (unsigned int i = 0; i < count2; i++)
723       klass2.add_class (c->input, i);
724   }
725 
get_coverageOT::PairPosFormat2726   inline const Coverage &get_coverage (void) const
727   {
728     return this+coverage;
729   }
730 
applyOT::PairPosFormat2731   inline bool apply (hb_apply_context_t *c) const
732   {
733     TRACE_APPLY (this);
734     hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1);
735     if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
736 
737     unsigned int index = (this+coverage).get_coverage  (c->buffer->cur().codepoint);
738     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
739 
740     if (!skippy_iter.next ()) return TRACE_RETURN (false);
741 
742     unsigned int len1 = valueFormat1.get_len ();
743     unsigned int len2 = valueFormat2.get_len ();
744     unsigned int record_len = len1 + len2;
745 
746     unsigned int klass1 = (this+classDef1).get_class (c->buffer->cur().codepoint);
747     unsigned int klass2 = (this+classDef2).get_class (c->buffer->info[skippy_iter.idx].codepoint);
748     if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return TRACE_RETURN (false);
749 
750     const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
751     valueFormat1.apply_value (c->font, c->direction, this,
752 			      v, c->buffer->cur_pos());
753     valueFormat2.apply_value (c->font, c->direction, this,
754 			      v + len1, c->buffer->pos[skippy_iter.idx]);
755 
756     c->buffer->idx = skippy_iter.idx;
757     if (len2)
758       c->buffer->idx++;
759 
760     return TRACE_RETURN (true);
761   }
762 
sanitizeOT::PairPosFormat2763   inline bool sanitize (hb_sanitize_context_t *c) {
764     TRACE_SANITIZE (this);
765     if (!(c->check_struct (this)
766        && coverage.sanitize (c, this)
767        && classDef1.sanitize (c, this)
768        && classDef2.sanitize (c, this))) return TRACE_RETURN (false);
769 
770     unsigned int len1 = valueFormat1.get_len ();
771     unsigned int len2 = valueFormat2.get_len ();
772     unsigned int stride = len1 + len2;
773     unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
774     unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
775     return TRACE_RETURN (c->check_array (values, record_size, count) &&
776 			 valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
777 			 valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride));
778   }
779 
780   protected:
781   USHORT	format;			/* Format identifier--format = 2 */
782   OffsetTo<Coverage>
783 		coverage;		/* Offset to Coverage table--from
784 					 * beginning of subtable */
785   ValueFormat	valueFormat1;		/* ValueRecord definition--for the
786 					 * first glyph of the pair--may be zero
787 					 * (0) */
788   ValueFormat	valueFormat2;		/* ValueRecord definition--for the
789 					 * second glyph of the pair--may be
790 					 * zero (0) */
791   OffsetTo<ClassDef>
792 		classDef1;		/* Offset to ClassDef table--from
793 					 * beginning of PairPos subtable--for
794 					 * the first glyph of the pair */
795   OffsetTo<ClassDef>
796 		classDef2;		/* Offset to ClassDef table--from
797 					 * beginning of PairPos subtable--for
798 					 * the second glyph of the pair */
799   USHORT	class1Count;		/* Number of classes in ClassDef1
800 					 * table--includes Class0 */
801   USHORT	class2Count;		/* Number of classes in ClassDef2
802 					 * table--includes Class0 */
803   ValueRecord	values;			/* Matrix of value pairs:
804 					 * class1-major, class2-minor,
805 					 * Each entry has value1 and value2 */
806   public:
807   DEFINE_SIZE_ARRAY (16, values);
808 };
809 
810 struct PairPos
811 {
812   template <typename context_t>
dispatchOT::PairPos813   inline typename context_t::return_t dispatch (context_t *c) const
814   {
815     TRACE_DISPATCH (this);
816     switch (u.format) {
817     case 1: return TRACE_RETURN (c->dispatch (u.format1));
818     case 2: return TRACE_RETURN (c->dispatch (u.format2));
819     default:return TRACE_RETURN (c->default_return_value ());
820     }
821   }
822 
sanitizeOT::PairPos823   inline bool sanitize (hb_sanitize_context_t *c) {
824     TRACE_SANITIZE (this);
825     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
826     switch (u.format) {
827     case 1: return TRACE_RETURN (u.format1.sanitize (c));
828     case 2: return TRACE_RETURN (u.format2.sanitize (c));
829     default:return TRACE_RETURN (true);
830     }
831   }
832 
833   protected:
834   union {
835   USHORT		format;		/* Format identifier */
836   PairPosFormat1	format1;
837   PairPosFormat2	format2;
838   } u;
839 };
840 
841 
842 struct EntryExitRecord
843 {
844   friend struct CursivePosFormat1;
845 
sanitizeOT::EntryExitRecord846   inline bool sanitize (hb_sanitize_context_t *c, void *base) {
847     TRACE_SANITIZE (this);
848     return TRACE_RETURN (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
849   }
850 
851   protected:
852   OffsetTo<Anchor>
853 		entryAnchor;		/* Offset to EntryAnchor table--from
854 					 * beginning of CursivePos
855 					 * subtable--may be NULL */
856   OffsetTo<Anchor>
857 		exitAnchor;		/* Offset to ExitAnchor table--from
858 					 * beginning of CursivePos
859 					 * subtable--may be NULL */
860   public:
861   DEFINE_SIZE_STATIC (4);
862 };
863 
864 struct CursivePosFormat1
865 {
collect_glyphsOT::CursivePosFormat1866   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
867   {
868     TRACE_COLLECT_GLYPHS (this);
869     (this+coverage).add_coverage (c->input);
870   }
871 
get_coverageOT::CursivePosFormat1872   inline const Coverage &get_coverage (void) const
873   {
874     return this+coverage;
875   }
876 
applyOT::CursivePosFormat1877   inline bool apply (hb_apply_context_t *c) const
878   {
879     TRACE_APPLY (this);
880 
881     /* We don't handle mark glyphs here. */
882     if (c->buffer->cur().glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK) return TRACE_RETURN (false);
883 
884     hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1);
885     if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
886 
887     const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage  (c->buffer->cur().codepoint)];
888     if (!this_record.exitAnchor) return TRACE_RETURN (false);
889 
890     if (!skippy_iter.next ()) return TRACE_RETURN (false);
891 
892     const EntryExitRecord &next_record = entryExitRecord[(this+coverage).get_coverage  (c->buffer->info[skippy_iter.idx].codepoint)];
893     if (!next_record.entryAnchor) return TRACE_RETURN (false);
894 
895     unsigned int i = c->buffer->idx;
896     unsigned int j = skippy_iter.idx;
897 
898     hb_position_t entry_x, entry_y, exit_x, exit_y;
899     (this+this_record.exitAnchor).get_anchor (c->font, c->buffer->info[i].codepoint, &exit_x, &exit_y);
900     (this+next_record.entryAnchor).get_anchor (c->font, c->buffer->info[j].codepoint, &entry_x, &entry_y);
901 
902     hb_glyph_position_t *pos = c->buffer->pos;
903 
904     hb_position_t d;
905     /* Main-direction adjustment */
906     switch (c->direction) {
907       case HB_DIRECTION_LTR:
908 	pos[i].x_advance  =  exit_x + pos[i].x_offset;
909 
910 	d = entry_x + pos[j].x_offset;
911 	pos[j].x_advance -= d;
912 	pos[j].x_offset  -= d;
913 	break;
914       case HB_DIRECTION_RTL:
915 	d = exit_x + pos[i].x_offset;
916 	pos[i].x_advance -= d;
917 	pos[i].x_offset  -= d;
918 
919 	pos[j].x_advance  =  entry_x + pos[j].x_offset;
920 	break;
921       case HB_DIRECTION_TTB:
922 	pos[i].y_advance  =  exit_y + pos[i].y_offset;
923 
924 	d = entry_y + pos[j].y_offset;
925 	pos[j].y_advance -= d;
926 	pos[j].y_offset  -= d;
927 	break;
928       case HB_DIRECTION_BTT:
929 	d = exit_y + pos[i].y_offset;
930 	pos[i].y_advance -= d;
931 	pos[i].y_offset  -= d;
932 
933 	pos[j].y_advance  =  entry_y;
934 	break;
935       case HB_DIRECTION_INVALID:
936       default:
937 	break;
938     }
939 
940     /* Cross-direction adjustment */
941     if  (c->lookup_props & LookupFlag::RightToLeft) {
942       pos[i].cursive_chain() = j - i;
943       if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
944 	pos[i].y_offset = entry_y - exit_y;
945       else
946 	pos[i].x_offset = entry_x - exit_x;
947     } else {
948       pos[j].cursive_chain() = i - j;
949       if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
950 	pos[j].y_offset = exit_y - entry_y;
951       else
952 	pos[j].x_offset = exit_x - entry_x;
953     }
954 
955     c->buffer->idx = j;
956     return TRACE_RETURN (true);
957   }
958 
sanitizeOT::CursivePosFormat1959   inline bool sanitize (hb_sanitize_context_t *c) {
960     TRACE_SANITIZE (this);
961     return TRACE_RETURN (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
962   }
963 
964   protected:
965   USHORT	format;			/* Format identifier--format = 1 */
966   OffsetTo<Coverage>
967 		coverage;		/* Offset to Coverage table--from
968 					 * beginning of subtable */
969   ArrayOf<EntryExitRecord>
970 		entryExitRecord;	/* Array of EntryExit records--in
971 					 * Coverage Index order */
972   public:
973   DEFINE_SIZE_ARRAY (6, entryExitRecord);
974 };
975 
976 struct CursivePos
977 {
978   template <typename context_t>
dispatchOT::CursivePos979   inline typename context_t::return_t dispatch (context_t *c) const
980   {
981     TRACE_DISPATCH (this);
982     switch (u.format) {
983     case 1: return TRACE_RETURN (c->dispatch (u.format1));
984     default:return TRACE_RETURN (c->default_return_value ());
985     }
986   }
987 
sanitizeOT::CursivePos988   inline bool sanitize (hb_sanitize_context_t *c) {
989     TRACE_SANITIZE (this);
990     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
991     switch (u.format) {
992     case 1: return TRACE_RETURN (u.format1.sanitize (c));
993     default:return TRACE_RETURN (true);
994     }
995   }
996 
997   protected:
998   union {
999   USHORT		format;		/* Format identifier */
1000   CursivePosFormat1	format1;
1001   } u;
1002 };
1003 
1004 
1005 typedef AnchorMatrix BaseArray;		/* base-major--
1006 					 * in order of BaseCoverage Index--,
1007 					 * mark-minor--
1008 					 * ordered by class--zero-based. */
1009 
1010 struct MarkBasePosFormat1
1011 {
collect_glyphsOT::MarkBasePosFormat11012   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1013   {
1014     TRACE_COLLECT_GLYPHS (this);
1015     (this+markCoverage).add_coverage (c->input);
1016     (this+baseCoverage).add_coverage (c->input);
1017     /* TODO only add combinations that have nonzero adjustment. */
1018   }
1019 
get_coverageOT::MarkBasePosFormat11020   inline const Coverage &get_coverage (void) const
1021   {
1022     return this+markCoverage;
1023   }
1024 
applyOT::MarkBasePosFormat11025   inline bool apply (hb_apply_context_t *c) const
1026   {
1027     TRACE_APPLY (this);
1028     unsigned int mark_index = (this+markCoverage).get_coverage  (c->buffer->cur().codepoint);
1029     if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
1030 
1031     /* now we search backwards for a non-mark glyph */
1032     hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1);
1033     skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
1034     do {
1035       if (!skippy_iter.prev ()) return TRACE_RETURN (false);
1036       /* We only want to attach to the first of a MultipleSubst sequence.  Reject others. */
1037       if (0 == get_lig_comp (c->buffer->info[skippy_iter.idx])) break;
1038       skippy_iter.reject ();
1039     } while (1);
1040 
1041     /* The following assertion is too strong, so we've disabled it. */
1042     if (!(c->buffer->info[skippy_iter.idx].glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH)) {/*return TRACE_RETURN (false);*/}
1043 
1044     unsigned int base_index = (this+baseCoverage).get_coverage  (c->buffer->info[skippy_iter.idx].codepoint);
1045     if (base_index == NOT_COVERED) return TRACE_RETURN (false);
1046 
1047     return TRACE_RETURN ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx));
1048   }
1049 
sanitizeOT::MarkBasePosFormat11050   inline bool sanitize (hb_sanitize_context_t *c) {
1051     TRACE_SANITIZE (this);
1052     return TRACE_RETURN (c->check_struct (this) && markCoverage.sanitize (c, this) && baseCoverage.sanitize (c, this) &&
1053 			 markArray.sanitize (c, this) && baseArray.sanitize (c, this, (unsigned int) classCount));
1054   }
1055 
1056   protected:
1057   USHORT	format;			/* Format identifier--format = 1 */
1058   OffsetTo<Coverage>
1059 		markCoverage;		/* Offset to MarkCoverage table--from
1060 					 * beginning of MarkBasePos subtable */
1061   OffsetTo<Coverage>
1062 		baseCoverage;		/* Offset to BaseCoverage table--from
1063 					 * beginning of MarkBasePos subtable */
1064   USHORT	classCount;		/* Number of classes defined for marks */
1065   OffsetTo<MarkArray>
1066 		markArray;		/* Offset to MarkArray table--from
1067 					 * beginning of MarkBasePos subtable */
1068   OffsetTo<BaseArray>
1069 		baseArray;		/* Offset to BaseArray table--from
1070 					 * beginning of MarkBasePos subtable */
1071   public:
1072   DEFINE_SIZE_STATIC (12);
1073 };
1074 
1075 struct MarkBasePos
1076 {
1077   template <typename context_t>
dispatchOT::MarkBasePos1078   inline typename context_t::return_t dispatch (context_t *c) const
1079   {
1080     TRACE_DISPATCH (this);
1081     switch (u.format) {
1082     case 1: return TRACE_RETURN (c->dispatch (u.format1));
1083     default:return TRACE_RETURN (c->default_return_value ());
1084     }
1085   }
1086 
sanitizeOT::MarkBasePos1087   inline bool sanitize (hb_sanitize_context_t *c) {
1088     TRACE_SANITIZE (this);
1089     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
1090     switch (u.format) {
1091     case 1: return TRACE_RETURN (u.format1.sanitize (c));
1092     default:return TRACE_RETURN (true);
1093     }
1094   }
1095 
1096   protected:
1097   union {
1098   USHORT		format;		/* Format identifier */
1099   MarkBasePosFormat1	format1;
1100   } u;
1101 };
1102 
1103 
1104 typedef AnchorMatrix LigatureAttach;	/* component-major--
1105 					 * in order of writing direction--,
1106 					 * mark-minor--
1107 					 * ordered by class--zero-based. */
1108 
1109 typedef OffsetListOf<LigatureAttach> LigatureArray;
1110 					/* Array of LigatureAttach
1111 					 * tables ordered by
1112 					 * LigatureCoverage Index */
1113 
1114 struct MarkLigPosFormat1
1115 {
collect_glyphsOT::MarkLigPosFormat11116   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1117   {
1118     TRACE_COLLECT_GLYPHS (this);
1119     (this+markCoverage).add_coverage (c->input);
1120     (this+ligatureCoverage).add_coverage (c->input);
1121     /* TODO only add combinations that have nonzero adjustment. */
1122   }
1123 
get_coverageOT::MarkLigPosFormat11124   inline const Coverage &get_coverage (void) const
1125   {
1126     return this+markCoverage;
1127   }
1128 
applyOT::MarkLigPosFormat11129   inline bool apply (hb_apply_context_t *c) const
1130   {
1131     TRACE_APPLY (this);
1132     unsigned int mark_index = (this+markCoverage).get_coverage  (c->buffer->cur().codepoint);
1133     if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
1134 
1135     /* now we search backwards for a non-mark glyph */
1136     hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1);
1137     skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
1138     if (!skippy_iter.prev ()) return TRACE_RETURN (false);
1139 
1140     /* The following assertion is too strong, so we've disabled it. */
1141     if (!(c->buffer->info[skippy_iter.idx].glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE)) {/*return TRACE_RETURN (false);*/}
1142 
1143     unsigned int j = skippy_iter.idx;
1144     unsigned int lig_index = (this+ligatureCoverage).get_coverage  (c->buffer->info[j].codepoint);
1145     if (lig_index == NOT_COVERED) return TRACE_RETURN (false);
1146 
1147     const LigatureArray& lig_array = this+ligatureArray;
1148     const LigatureAttach& lig_attach = lig_array[lig_index];
1149 
1150     /* Find component to attach to */
1151     unsigned int comp_count = lig_attach.rows;
1152     if (unlikely (!comp_count)) return TRACE_RETURN (false);
1153 
1154     /* We must now check whether the ligature ID of the current mark glyph
1155      * is identical to the ligature ID of the found ligature.  If yes, we
1156      * can directly use the component index.  If not, we attach the mark
1157      * glyph to the last component of the ligature. */
1158     unsigned int comp_index;
1159     unsigned int lig_id = get_lig_id (c->buffer->info[j]);
1160     unsigned int mark_id = get_lig_id (c->buffer->cur());
1161     unsigned int mark_comp = get_lig_comp (c->buffer->cur());
1162     if (lig_id && lig_id == mark_id && mark_comp > 0)
1163       comp_index = MIN (comp_count, get_lig_comp (c->buffer->cur())) - 1;
1164     else
1165       comp_index = comp_count - 1;
1166 
1167     return TRACE_RETURN ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
1168   }
1169 
sanitizeOT::MarkLigPosFormat11170   inline bool sanitize (hb_sanitize_context_t *c) {
1171     TRACE_SANITIZE (this);
1172     return TRACE_RETURN (c->check_struct (this) && markCoverage.sanitize (c, this) && ligatureCoverage.sanitize (c, this) &&
1173 			 markArray.sanitize (c, this) && ligatureArray.sanitize (c, this, (unsigned int) classCount));
1174   }
1175 
1176   protected:
1177   USHORT	format;			/* Format identifier--format = 1 */
1178   OffsetTo<Coverage>
1179 		markCoverage;		/* Offset to Mark Coverage table--from
1180 					 * beginning of MarkLigPos subtable */
1181   OffsetTo<Coverage>
1182 		ligatureCoverage;	/* Offset to Ligature Coverage
1183 					 * table--from beginning of MarkLigPos
1184 					 * subtable */
1185   USHORT	classCount;		/* Number of defined mark classes */
1186   OffsetTo<MarkArray>
1187 		markArray;		/* Offset to MarkArray table--from
1188 					 * beginning of MarkLigPos subtable */
1189   OffsetTo<LigatureArray>
1190 		ligatureArray;		/* Offset to LigatureArray table--from
1191 					 * beginning of MarkLigPos subtable */
1192   public:
1193   DEFINE_SIZE_STATIC (12);
1194 };
1195 
1196 struct MarkLigPos
1197 {
1198   template <typename context_t>
dispatchOT::MarkLigPos1199   inline typename context_t::return_t dispatch (context_t *c) const
1200   {
1201     TRACE_DISPATCH (this);
1202     switch (u.format) {
1203     case 1: return TRACE_RETURN (c->dispatch (u.format1));
1204     default:return TRACE_RETURN (c->default_return_value ());
1205     }
1206   }
1207 
sanitizeOT::MarkLigPos1208   inline bool sanitize (hb_sanitize_context_t *c) {
1209     TRACE_SANITIZE (this);
1210     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
1211     switch (u.format) {
1212     case 1: return TRACE_RETURN (u.format1.sanitize (c));
1213     default:return TRACE_RETURN (true);
1214     }
1215   }
1216 
1217   protected:
1218   union {
1219   USHORT		format;		/* Format identifier */
1220   MarkLigPosFormat1	format1;
1221   } u;
1222 };
1223 
1224 
1225 typedef AnchorMatrix Mark2Array;	/* mark2-major--
1226 					 * in order of Mark2Coverage Index--,
1227 					 * mark1-minor--
1228 					 * ordered by class--zero-based. */
1229 
1230 struct MarkMarkPosFormat1
1231 {
collect_glyphsOT::MarkMarkPosFormat11232   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1233   {
1234     TRACE_COLLECT_GLYPHS (this);
1235     (this+mark1Coverage).add_coverage (c->input);
1236     (this+mark2Coverage).add_coverage (c->input);
1237     /* TODO only add combinations that have nonzero adjustment. */
1238   }
1239 
get_coverageOT::MarkMarkPosFormat11240   inline const Coverage &get_coverage (void) const
1241   {
1242     return this+mark1Coverage;
1243   }
1244 
applyOT::MarkMarkPosFormat11245   inline bool apply (hb_apply_context_t *c) const
1246   {
1247     TRACE_APPLY (this);
1248     unsigned int mark1_index = (this+mark1Coverage).get_coverage  (c->buffer->cur().codepoint);
1249     if (likely (mark1_index == NOT_COVERED)) return TRACE_RETURN (false);
1250 
1251     /* now we search backwards for a suitable mark glyph until a non-mark glyph */
1252     hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1);
1253     skippy_iter.set_lookup_props (c->lookup_props & ~LookupFlag::IgnoreFlags);
1254     if (!skippy_iter.prev ()) return TRACE_RETURN (false);
1255 
1256     if (!(c->buffer->info[skippy_iter.idx].glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK)) { return TRACE_RETURN (false); }
1257 
1258     unsigned int j = skippy_iter.idx;
1259 
1260     unsigned int id1 = get_lig_id (c->buffer->cur());
1261     unsigned int id2 = get_lig_id (c->buffer->info[j]);
1262     unsigned int comp1 = get_lig_comp (c->buffer->cur());
1263     unsigned int comp2 = get_lig_comp (c->buffer->info[j]);
1264 
1265     if (likely (id1 == id2)) {
1266       if (id1 == 0) /* Marks belonging to the same base. */
1267 	goto good;
1268       else if (comp1 == comp2) /* Marks belonging to the same ligature component. */
1269         goto good;
1270     } else {
1271       /* If ligature ids don't match, it may be the case that one of the marks
1272        * itself is a ligature.  In which case match. */
1273       if ((id1 > 0 && !comp1) || (id2 > 0 && !comp2))
1274 	goto good;
1275     }
1276 
1277     /* Didn't match. */
1278     return TRACE_RETURN (false);
1279 
1280     good:
1281     unsigned int mark2_index = (this+mark2Coverage).get_coverage  (c->buffer->info[j].codepoint);
1282     if (mark2_index == NOT_COVERED) return TRACE_RETURN (false);
1283 
1284     return TRACE_RETURN ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j));
1285   }
1286 
sanitizeOT::MarkMarkPosFormat11287   inline bool sanitize (hb_sanitize_context_t *c) {
1288     TRACE_SANITIZE (this);
1289     return TRACE_RETURN (c->check_struct (this) && mark1Coverage.sanitize (c, this) &&
1290 			 mark2Coverage.sanitize (c, this) && mark1Array.sanitize (c, this)
1291 			 && mark2Array.sanitize (c, this, (unsigned int) classCount));
1292   }
1293 
1294   protected:
1295   USHORT	format;			/* Format identifier--format = 1 */
1296   OffsetTo<Coverage>
1297 		mark1Coverage;		/* Offset to Combining Mark1 Coverage
1298 					 * table--from beginning of MarkMarkPos
1299 					 * subtable */
1300   OffsetTo<Coverage>
1301 		mark2Coverage;		/* Offset to Combining Mark2 Coverage
1302 					 * table--from beginning of MarkMarkPos
1303 					 * subtable */
1304   USHORT	classCount;		/* Number of defined mark classes */
1305   OffsetTo<MarkArray>
1306 		mark1Array;		/* Offset to Mark1Array table--from
1307 					 * beginning of MarkMarkPos subtable */
1308   OffsetTo<Mark2Array>
1309 		mark2Array;		/* Offset to Mark2Array table--from
1310 					 * beginning of MarkMarkPos subtable */
1311   public:
1312   DEFINE_SIZE_STATIC (12);
1313 };
1314 
1315 struct MarkMarkPos
1316 {
1317   template <typename context_t>
dispatchOT::MarkMarkPos1318   inline typename context_t::return_t dispatch (context_t *c) const
1319   {
1320     TRACE_DISPATCH (this);
1321     switch (u.format) {
1322     case 1: return TRACE_RETURN (c->dispatch (u.format1));
1323     default:return TRACE_RETURN (c->default_return_value ());
1324     }
1325   }
1326 
sanitizeOT::MarkMarkPos1327   inline bool sanitize (hb_sanitize_context_t *c) {
1328     TRACE_SANITIZE (this);
1329     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
1330     switch (u.format) {
1331     case 1: return TRACE_RETURN (u.format1.sanitize (c));
1332     default:return TRACE_RETURN (true);
1333     }
1334   }
1335 
1336   protected:
1337   union {
1338   USHORT		format;		/* Format identifier */
1339   MarkMarkPosFormat1	format1;
1340   } u;
1341 };
1342 
1343 
1344 struct ContextPos : Context {};
1345 
1346 struct ChainContextPos : ChainContext {};
1347 
1348 struct ExtensionPos : Extension<ExtensionPos>
1349 {
1350   typedef struct PosLookupSubTable LookupSubTable;
1351 };
1352 
1353 
1354 
1355 /*
1356  * PosLookup
1357  */
1358 
1359 
1360 struct PosLookupSubTable
1361 {
1362   friend struct PosLookup;
1363 
1364   enum Type {
1365     Single		= 1,
1366     Pair		= 2,
1367     Cursive		= 3,
1368     MarkBase		= 4,
1369     MarkLig		= 5,
1370     MarkMark		= 6,
1371     Context		= 7,
1372     ChainContext	= 8,
1373     Extension		= 9
1374   };
1375 
1376   template <typename context_t>
dispatchOT::PosLookupSubTable1377   inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
1378   {
1379     TRACE_DISPATCH (this);
1380     switch (lookup_type) {
1381     case Single:		return TRACE_RETURN (u.single.dispatch (c));
1382     case Pair:			return TRACE_RETURN (u.pair.dispatch (c));
1383     case Cursive:		return TRACE_RETURN (u.cursive.dispatch (c));
1384     case MarkBase:		return TRACE_RETURN (u.markBase.dispatch (c));
1385     case MarkLig:		return TRACE_RETURN (u.markLig.dispatch (c));
1386     case MarkMark:		return TRACE_RETURN (u.markMark.dispatch (c));
1387     case Context:		return TRACE_RETURN (u.context.dispatch (c));
1388     case ChainContext:		return TRACE_RETURN (u.chainContext.dispatch (c));
1389     case Extension:		return TRACE_RETURN (u.extension.dispatch (c));
1390     default:			return TRACE_RETURN (c->default_return_value ());
1391     }
1392   }
1393 
sanitizeOT::PosLookupSubTable1394   inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
1395     TRACE_SANITIZE (this);
1396     if (!u.header.sub_format.sanitize (c))
1397       return TRACE_RETURN (false);
1398     switch (lookup_type) {
1399     case Single:		return TRACE_RETURN (u.single.sanitize (c));
1400     case Pair:			return TRACE_RETURN (u.pair.sanitize (c));
1401     case Cursive:		return TRACE_RETURN (u.cursive.sanitize (c));
1402     case MarkBase:		return TRACE_RETURN (u.markBase.sanitize (c));
1403     case MarkLig:		return TRACE_RETURN (u.markLig.sanitize (c));
1404     case MarkMark:		return TRACE_RETURN (u.markMark.sanitize (c));
1405     case Context:		return TRACE_RETURN (u.context.sanitize (c));
1406     case ChainContext:		return TRACE_RETURN (u.chainContext.sanitize (c));
1407     case Extension:		return TRACE_RETURN (u.extension.sanitize (c));
1408     default:			return TRACE_RETURN (true);
1409     }
1410   }
1411 
1412   protected:
1413   union {
1414   struct {
1415     USHORT		sub_format;
1416   } header;
1417   SinglePos		single;
1418   PairPos		pair;
1419   CursivePos		cursive;
1420   MarkBasePos		markBase;
1421   MarkLigPos		markLig;
1422   MarkMarkPos		markMark;
1423   ContextPos		context;
1424   ChainContextPos	chainContext;
1425   ExtensionPos		extension;
1426   } u;
1427   public:
1428   DEFINE_SIZE_UNION (2, header.sub_format);
1429 };
1430 
1431 
1432 struct PosLookup : Lookup
1433 {
get_subtableOT::PosLookup1434   inline const PosLookupSubTable& get_subtable (unsigned int i) const
1435   { return this+CastR<OffsetArrayOf<PosLookupSubTable> > (subTable)[i]; }
1436 
collect_glyphs_lookupOT::PosLookup1437   inline hb_collect_glyphs_context_t::return_t collect_glyphs_lookup (hb_collect_glyphs_context_t *c) const
1438   {
1439     TRACE_COLLECT_GLYPHS (this);
1440     c->set_recurse_func (NULL);
1441     return TRACE_RETURN (dispatch (c));
1442   }
1443 
1444   template <typename set_t>
add_coverageOT::PosLookup1445   inline void add_coverage (set_t *glyphs) const
1446   {
1447     hb_get_coverage_context_t c;
1448     const Coverage *last = NULL;
1449     unsigned int count = get_subtable_count ();
1450     for (unsigned int i = 0; i < count; i++) {
1451       const Coverage *coverage = &get_subtable (i).dispatch (&c, get_type ());
1452       if (coverage != last) {
1453         coverage->add_coverage (glyphs);
1454         last = coverage;
1455       }
1456     }
1457   }
1458 
apply_onceOT::PosLookup1459   inline bool apply_once (hb_apply_context_t *c) const
1460   {
1461     TRACE_APPLY (this);
1462     if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props))
1463       return TRACE_RETURN (false);
1464     return TRACE_RETURN (dispatch (c));
1465   }
1466 
1467   static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
1468 
apply_stringOT::PosLookup1469   inline bool apply_string (hb_apply_context_t *c, const hb_set_digest_t *digest) const
1470   {
1471     bool ret = false;
1472 
1473     if (unlikely (!c->buffer->len || !c->lookup_mask))
1474       return false;
1475 
1476     c->set_recurse_func (apply_recurse_func);
1477     c->set_lookup (*this);
1478 
1479     c->buffer->idx = 0;
1480 
1481     while (c->buffer->idx < c->buffer->len)
1482     {
1483       if ((c->buffer->cur().mask & c->lookup_mask) &&
1484 	  digest->may_have (c->buffer->cur().codepoint) &&
1485 	  apply_once (c))
1486 	ret = true;
1487       else
1488 	c->buffer->idx++;
1489     }
1490 
1491     return ret;
1492   }
1493 
1494   template <typename context_t>
1495   static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
1496 
1497   template <typename context_t>
dispatchOT::PosLookup1498   inline typename context_t::return_t dispatch (context_t *c) const
1499   {
1500     TRACE_DISPATCH (this);
1501     unsigned int lookup_type = get_type ();
1502     unsigned int count = get_subtable_count ();
1503     for (unsigned int i = 0; i < count; i++) {
1504       typename context_t::return_t r = get_subtable (i).dispatch (c, lookup_type);
1505       if (c->stop_sublookup_iteration (r))
1506         return TRACE_RETURN (r);
1507     }
1508     return TRACE_RETURN (c->default_return_value ());
1509   }
1510 
sanitizeOT::PosLookup1511   inline bool sanitize (hb_sanitize_context_t *c) {
1512     TRACE_SANITIZE (this);
1513     if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
1514     OffsetArrayOf<PosLookupSubTable> &list = CastR<OffsetArrayOf<PosLookupSubTable> > (subTable);
1515     return TRACE_RETURN (list.sanitize (c, this, get_type ()));
1516   }
1517 };
1518 
1519 typedef OffsetListOf<PosLookup> PosLookupList;
1520 
1521 /*
1522  * GPOS -- The Glyph Positioning Table
1523  */
1524 
1525 struct GPOS : GSUBGPOS
1526 {
1527   static const hb_tag_t Tag	= HB_OT_TAG_GPOS;
1528 
get_lookupOT::GPOS1529   inline const PosLookup& get_lookup (unsigned int i) const
1530   { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
1531 
1532   static inline void position_start (hb_font_t *font, hb_buffer_t *buffer);
1533   static inline void position_finish (hb_font_t *font, hb_buffer_t *buffer);
1534 
sanitizeOT::GPOS1535   inline bool sanitize (hb_sanitize_context_t *c) {
1536     TRACE_SANITIZE (this);
1537     if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
1538     OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
1539     return TRACE_RETURN (list.sanitize (c, this));
1540   }
1541   public:
1542   DEFINE_SIZE_STATIC (10);
1543 };
1544 
1545 
1546 static void
fix_cursive_minor_offset(hb_glyph_position_t * pos,unsigned int i,hb_direction_t direction)1547 fix_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
1548 {
1549   unsigned int j = pos[i].cursive_chain();
1550   if (likely (!j))
1551     return;
1552 
1553   j += i;
1554 
1555   pos[i].cursive_chain() = 0;
1556 
1557   fix_cursive_minor_offset (pos, j, direction);
1558 
1559   if (HB_DIRECTION_IS_HORIZONTAL (direction))
1560     pos[i].y_offset += pos[j].y_offset;
1561   else
1562     pos[i].x_offset += pos[j].x_offset;
1563 }
1564 
1565 static void
fix_mark_attachment(hb_glyph_position_t * pos,unsigned int i,hb_direction_t direction)1566 fix_mark_attachment (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
1567 {
1568   if (likely (!(pos[i].attach_lookback())))
1569     return;
1570 
1571   unsigned int j = i - pos[i].attach_lookback();
1572 
1573   pos[i].x_offset += pos[j].x_offset;
1574   pos[i].y_offset += pos[j].y_offset;
1575 
1576   if (HB_DIRECTION_IS_FORWARD (direction))
1577     for (unsigned int k = j; k < i; k++) {
1578       pos[i].x_offset -= pos[k].x_advance;
1579       pos[i].y_offset -= pos[k].y_advance;
1580     }
1581   else
1582     for (unsigned int k = j + 1; k < i + 1; k++) {
1583       pos[i].x_offset += pos[k].x_advance;
1584       pos[i].y_offset += pos[k].y_advance;
1585     }
1586 }
1587 
1588 void
position_start(hb_font_t * font HB_UNUSED,hb_buffer_t * buffer)1589 GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
1590 {
1591   buffer->clear_positions ();
1592 
1593   unsigned int count = buffer->len;
1594   for (unsigned int i = 0; i < count; i++)
1595     buffer->pos[i].attach_lookback() = buffer->pos[i].cursive_chain() = 0;
1596 }
1597 
1598 void
position_finish(hb_font_t * font HB_UNUSED,hb_buffer_t * buffer)1599 GPOS::position_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
1600 {
1601   unsigned int len;
1602   hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
1603   hb_direction_t direction = buffer->props.direction;
1604 
1605   /* Handle cursive connections */
1606   for (unsigned int i = 0; i < len; i++)
1607     fix_cursive_minor_offset (pos, i, direction);
1608 
1609   /* Handle attachments */
1610   for (unsigned int i = 0; i < len; i++)
1611     fix_mark_attachment (pos, i, direction);
1612 
1613   HB_BUFFER_DEALLOCATE_VAR (buffer, syllable);
1614   HB_BUFFER_DEALLOCATE_VAR (buffer, lig_props);
1615   HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_props);
1616 }
1617 
1618 
1619 /* Out-of-class implementation for methods recursing */
1620 
1621 template <typename context_t>
dispatch_recurse_func(context_t * c,unsigned int lookup_index)1622 inline typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
1623 {
1624   const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
1625   const PosLookup &l = gpos.get_lookup (lookup_index);
1626   return l.dispatch (c);
1627 }
1628 
apply_recurse_func(hb_apply_context_t * c,unsigned int lookup_index)1629 inline bool PosLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
1630 {
1631   const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
1632   const PosLookup &l = gpos.get_lookup (lookup_index);
1633   unsigned int saved_lookup_props = c->lookup_props;
1634   c->set_lookup (l);
1635   bool ret = l.apply_once (c);
1636   c->lookup_props = saved_lookup_props;
1637   return ret;
1638 }
1639 
1640 
1641 #undef attach_lookback
1642 #undef cursive_chain
1643 
1644 
1645 } /* namespace OT */
1646 
1647 
1648 #endif /* HB_OT_LAYOUT_GPOS_TABLE_HH */
1649