1 /*
2  * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
3  * Copyright © 2010,2012,2013  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	= 0x0001u,	/* Includes horizontal adjustment for placement */
53     yPlacement	= 0x0002u,	/* Includes vertical adjustment for placement */
54     xAdvance	= 0x0004u,	/* Includes horizontal adjustment for advance */
55     yAdvance	= 0x0008u,	/* Includes vertical adjustment for advance */
56     xPlaDevice	= 0x0010u,	/* Includes horizontal Device table for placement */
57     yPlaDevice	= 0x0020u,	/* Includes vertical Device table for placement */
58     xAdvDevice	= 0x0040u,	/* Includes horizontal Device table for advance */
59     yAdvDevice	= 0x0080u,	/* Includes vertical Device table for advance */
60     ignored	= 0x0F00u,	/* Was used in TrueType Open for MM fonts */
61     reserved	= 0xF000u,	/* For future use */
62 
63     devices	= 0x00F0u	/* 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));
113       values++;
114     }
115     /* y_advance values grow downward but font-space grows upward, hence negation */
116     if (format & yAdvance) {
117       if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values));
118       values++;
119     }
120 
121     if (!has_device ()) return;
122 
123     x_ppem = font->x_ppem;
124     y_ppem = font->y_ppem;
125 
126     if (!x_ppem && !y_ppem) return;
127 
128     /* pixel -> fractional pixel */
129     if (format & xPlaDevice) {
130       if (x_ppem) glyph_pos.x_offset  += (base + get_device (values)).get_x_delta (font);
131       values++;
132     }
133     if (format & yPlaDevice) {
134       if (y_ppem) glyph_pos.y_offset  += (base + get_device (values)).get_y_delta (font);
135       values++;
136     }
137     if (format & xAdvDevice) {
138       if (horizontal && x_ppem) glyph_pos.x_advance += (base + get_device (values)).get_x_delta (font);
139       values++;
140     }
141     if (format & yAdvDevice) {
142       /* y_advance values grow downward but font-space grows upward, hence negation */
143       if (!horizontal && y_ppem) glyph_pos.y_advance -= (base + get_device (values)).get_y_delta (font);
144       values++;
145     }
146   }
147 
148   private:
sanitize_value_devicesOT::ValueFormat149   inline bool sanitize_value_devices (hb_sanitize_context_t *c, void *base, Value *values) {
150     unsigned int format = *this;
151 
152     if (format & xPlacement) values++;
153     if (format & yPlacement) values++;
154     if (format & xAdvance)   values++;
155     if (format & yAdvance)   values++;
156 
157     if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
158     if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
159     if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
160     if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
161 
162     return true;
163   }
164 
get_deviceOT::ValueFormat165   static inline OffsetTo<Device>& get_device (Value* value)
166   { return *CastP<OffsetTo<Device> > (value); }
get_deviceOT::ValueFormat167   static inline const OffsetTo<Device>& get_device (const Value* value)
168   { return *CastP<OffsetTo<Device> > (value); }
169 
get_shortOT::ValueFormat170   static inline const SHORT& get_short (const Value* value)
171   { return *CastP<SHORT> (value); }
172 
173   public:
174 
has_deviceOT::ValueFormat175   inline bool has_device (void) const {
176     unsigned int format = *this;
177     return (format & devices) != 0;
178   }
179 
sanitize_valueOT::ValueFormat180   inline bool sanitize_value (hb_sanitize_context_t *c, void *base, Value *values) {
181     TRACE_SANITIZE (this);
182     return TRACE_RETURN (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values)));
183   }
184 
sanitize_valuesOT::ValueFormat185   inline bool sanitize_values (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count) {
186     TRACE_SANITIZE (this);
187     unsigned int len = get_len ();
188 
189     if (!c->check_array (values, get_size (), count)) return TRACE_RETURN (false);
190 
191     if (!has_device ()) return TRACE_RETURN (true);
192 
193     for (unsigned int i = 0; i < count; i++) {
194       if (!sanitize_value_devices (c, base, values))
195         return TRACE_RETURN (false);
196       values += len;
197     }
198 
199     return TRACE_RETURN (true);
200   }
201 
202   /* Just sanitize referenced Device tables.  Doesn't check the values themselves. */
sanitize_values_stride_unsafeOT::ValueFormat203   inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count, unsigned int stride) {
204     TRACE_SANITIZE (this);
205 
206     if (!has_device ()) return TRACE_RETURN (true);
207 
208     for (unsigned int i = 0; i < count; i++) {
209       if (!sanitize_value_devices (c, base, values))
210         return TRACE_RETURN (false);
211       values += stride;
212     }
213 
214     return TRACE_RETURN (true);
215   }
216 };
217 
218 
219 struct AnchorFormat1
220 {
get_anchorOT::AnchorFormat1221   inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
222 			  hb_position_t *x, hb_position_t *y) const
223   {
224       *x = font->em_scale_x (xCoordinate);
225       *y = font->em_scale_y (yCoordinate);
226   }
227 
sanitizeOT::AnchorFormat1228   inline bool sanitize (hb_sanitize_context_t *c) {
229     TRACE_SANITIZE (this);
230     return TRACE_RETURN (c->check_struct (this));
231   }
232 
233   protected:
234   USHORT	format;			/* Format identifier--format = 1 */
235   SHORT		xCoordinate;		/* Horizontal value--in design units */
236   SHORT		yCoordinate;		/* Vertical value--in design units */
237   public:
238   DEFINE_SIZE_STATIC (6);
239 };
240 
241 struct AnchorFormat2
242 {
get_anchorOT::AnchorFormat2243   inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
244 			  hb_position_t *x, hb_position_t *y) const
245   {
246       unsigned int x_ppem = font->x_ppem;
247       unsigned int y_ppem = font->y_ppem;
248       hb_position_t cx, cy;
249       hb_bool_t ret;
250 
251       ret = (x_ppem || y_ppem) &&
252              font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
253       *x = ret && x_ppem ? cx : font->em_scale_x (xCoordinate);
254       *y = ret && y_ppem ? cy : font->em_scale_y (yCoordinate);
255   }
256 
sanitizeOT::AnchorFormat2257   inline bool sanitize (hb_sanitize_context_t *c) {
258     TRACE_SANITIZE (this);
259     return TRACE_RETURN (c->check_struct (this));
260   }
261 
262   protected:
263   USHORT	format;			/* Format identifier--format = 2 */
264   SHORT		xCoordinate;		/* Horizontal value--in design units */
265   SHORT		yCoordinate;		/* Vertical value--in design units */
266   USHORT	anchorPoint;		/* Index to glyph contour point */
267   public:
268   DEFINE_SIZE_STATIC (8);
269 };
270 
271 struct AnchorFormat3
272 {
get_anchorOT::AnchorFormat3273   inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
274 			  hb_position_t *x, hb_position_t *y) const
275   {
276       *x = font->em_scale_x (xCoordinate);
277       *y = font->em_scale_y (yCoordinate);
278 
279       if (font->x_ppem)
280 	*x += (this+xDeviceTable).get_x_delta (font);
281       if (font->y_ppem)
282 	*y += (this+yDeviceTable).get_x_delta (font);
283   }
284 
sanitizeOT::AnchorFormat3285   inline bool sanitize (hb_sanitize_context_t *c) {
286     TRACE_SANITIZE (this);
287     return TRACE_RETURN (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
288   }
289 
290   protected:
291   USHORT	format;			/* Format identifier--format = 3 */
292   SHORT		xCoordinate;		/* Horizontal value--in design units */
293   SHORT		yCoordinate;		/* Vertical value--in design units */
294   OffsetTo<Device>
295 		xDeviceTable;		/* Offset to Device table for X
296 					 * coordinate-- from beginning of
297 					 * Anchor table (may be NULL) */
298   OffsetTo<Device>
299 		yDeviceTable;		/* Offset to Device table for Y
300 					 * coordinate-- from beginning of
301 					 * Anchor table (may be NULL) */
302   public:
303   DEFINE_SIZE_STATIC (10);
304 };
305 
306 struct Anchor
307 {
get_anchorOT::Anchor308   inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
309 			  hb_position_t *x, hb_position_t *y) const
310   {
311     *x = *y = 0;
312     switch (u.format) {
313     case 1: u.format1.get_anchor (font, glyph_id, x, y); return;
314     case 2: u.format2.get_anchor (font, glyph_id, x, y); return;
315     case 3: u.format3.get_anchor (font, glyph_id, x, y); return;
316     default:						 return;
317     }
318   }
319 
sanitizeOT::Anchor320   inline bool sanitize (hb_sanitize_context_t *c) {
321     TRACE_SANITIZE (this);
322     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
323     switch (u.format) {
324     case 1: return TRACE_RETURN (u.format1.sanitize (c));
325     case 2: return TRACE_RETURN (u.format2.sanitize (c));
326     case 3: return TRACE_RETURN (u.format3.sanitize (c));
327     default:return TRACE_RETURN (true);
328     }
329   }
330 
331   protected:
332   union {
333   USHORT		format;		/* Format identifier */
334   AnchorFormat1		format1;
335   AnchorFormat2		format2;
336   AnchorFormat3		format3;
337   } u;
338   public:
339   DEFINE_SIZE_UNION (2, format);
340 };
341 
342 
343 struct AnchorMatrix
344 {
get_anchorOT::AnchorMatrix345   inline const Anchor& get_anchor (unsigned int row, unsigned int col, unsigned int cols, bool *found) const {
346     *found = false;
347     if (unlikely (row >= rows || col >= cols)) return Null(Anchor);
348     *found = !matrixZ[row * cols + col].is_null ();
349     return this+matrixZ[row * cols + col];
350   }
351 
sanitizeOT::AnchorMatrix352   inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) {
353     TRACE_SANITIZE (this);
354     if (!c->check_struct (this)) return TRACE_RETURN (false);
355     if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return TRACE_RETURN (false);
356     unsigned int count = rows * cols;
357     if (!c->check_array (matrixZ, matrixZ[0].static_size, count)) return TRACE_RETURN (false);
358     for (unsigned int i = 0; i < count; i++)
359       if (!matrixZ[i].sanitize (c, this)) return TRACE_RETURN (false);
360     return TRACE_RETURN (true);
361   }
362 
363   USHORT	rows;			/* Number of rows */
364   protected:
365   OffsetTo<Anchor>
366 		matrixZ[VAR];		/* Matrix of offsets to Anchor tables--
367 					 * from beginning of AnchorMatrix table */
368   public:
369   DEFINE_SIZE_ARRAY (2, matrixZ);
370 };
371 
372 
373 struct MarkRecord
374 {
375   friend struct MarkArray;
376 
sanitizeOT::MarkRecord377   inline bool sanitize (hb_sanitize_context_t *c, void *base) {
378     TRACE_SANITIZE (this);
379     return TRACE_RETURN (c->check_struct (this) && markAnchor.sanitize (c, base));
380   }
381 
382   protected:
383   USHORT	klass;			/* Class defined for this mark */
384   OffsetTo<Anchor>
385 		markAnchor;		/* Offset to Anchor table--from
386 					 * beginning of MarkArray table */
387   public:
388   DEFINE_SIZE_STATIC (4);
389 };
390 
391 struct MarkArray : ArrayOf<MarkRecord>	/* Array of MarkRecords--in Coverage order */
392 {
applyOT::MarkArray393   inline bool apply (hb_apply_context_t *c,
394 		     unsigned int mark_index, unsigned int glyph_index,
395 		     const AnchorMatrix &anchors, unsigned int class_count,
396 		     unsigned int glyph_pos) const
397   {
398     TRACE_APPLY (this);
399     hb_buffer_t *buffer = c->buffer;
400     const MarkRecord &record = ArrayOf<MarkRecord>::operator[](mark_index);
401     unsigned int mark_class = record.klass;
402 
403     const Anchor& mark_anchor = this + record.markAnchor;
404     bool found;
405     const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count, &found);
406     /* If this subtable doesn't have an anchor for this base and this class,
407      * return false such that the subsequent subtables have a chance at it. */
408     if (unlikely (!found)) return TRACE_RETURN (false);
409 
410     hb_position_t mark_x, mark_y, base_x, base_y;
411 
412     mark_anchor.get_anchor (c->font, buffer->cur().codepoint, &mark_x, &mark_y);
413     glyph_anchor.get_anchor (c->font, buffer->info[glyph_pos].codepoint, &base_x, &base_y);
414 
415     hb_glyph_position_t &o = buffer->cur_pos();
416     o.x_offset = base_x - mark_x;
417     o.y_offset = base_y - mark_y;
418     o.attach_lookback() = buffer->idx - glyph_pos;
419 
420     buffer->idx++;
421     return TRACE_RETURN (true);
422   }
423 
sanitizeOT::MarkArray424   inline bool sanitize (hb_sanitize_context_t *c) {
425     TRACE_SANITIZE (this);
426     return TRACE_RETURN (ArrayOf<MarkRecord>::sanitize (c, this));
427   }
428 };
429 
430 
431 /* Lookups */
432 
433 struct SinglePosFormat1
434 {
collect_glyphsOT::SinglePosFormat1435   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
436   {
437     TRACE_COLLECT_GLYPHS (this);
438     (this+coverage).add_coverage (c->input);
439   }
440 
get_coverageOT::SinglePosFormat1441   inline const Coverage &get_coverage (void) const
442   {
443     return this+coverage;
444   }
445 
applyOT::SinglePosFormat1446   inline bool apply (hb_apply_context_t *c) const
447   {
448     TRACE_APPLY (this);
449     hb_buffer_t *buffer = c->buffer;
450     unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
451     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
452 
453     valueFormat.apply_value (c->font, c->direction, this,
454 			     values, buffer->cur_pos());
455 
456     buffer->idx++;
457     return TRACE_RETURN (true);
458   }
459 
sanitizeOT::SinglePosFormat1460   inline bool sanitize (hb_sanitize_context_t *c) {
461     TRACE_SANITIZE (this);
462     return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && valueFormat.sanitize_value (c, this, values));
463   }
464 
465   protected:
466   USHORT	format;			/* Format identifier--format = 1 */
467   OffsetTo<Coverage>
468 		coverage;		/* Offset to Coverage table--from
469 					 * beginning of subtable */
470   ValueFormat	valueFormat;		/* Defines the types of data in the
471 					 * ValueRecord */
472   ValueRecord	values;			/* Defines positioning
473 					 * value(s)--applied to all glyphs in
474 					 * the Coverage table */
475   public:
476   DEFINE_SIZE_ARRAY (6, values);
477 };
478 
479 struct SinglePosFormat2
480 {
collect_glyphsOT::SinglePosFormat2481   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
482   {
483     TRACE_COLLECT_GLYPHS (this);
484     (this+coverage).add_coverage (c->input);
485   }
486 
get_coverageOT::SinglePosFormat2487   inline const Coverage &get_coverage (void) const
488   {
489     return this+coverage;
490   }
491 
applyOT::SinglePosFormat2492   inline bool apply (hb_apply_context_t *c) const
493   {
494     TRACE_APPLY (this);
495     hb_buffer_t *buffer = c->buffer;
496     unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
497     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
498 
499     if (likely (index >= valueCount)) return TRACE_RETURN (false);
500 
501     valueFormat.apply_value (c->font, c->direction, this,
502 			     &values[index * valueFormat.get_len ()],
503 			     buffer->cur_pos());
504 
505     buffer->idx++;
506     return TRACE_RETURN (true);
507   }
508 
sanitizeOT::SinglePosFormat2509   inline bool sanitize (hb_sanitize_context_t *c) {
510     TRACE_SANITIZE (this);
511     return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && valueFormat.sanitize_values (c, this, values, valueCount));
512   }
513 
514   protected:
515   USHORT	format;			/* Format identifier--format = 2 */
516   OffsetTo<Coverage>
517 		coverage;		/* Offset to Coverage table--from
518 					 * beginning of subtable */
519   ValueFormat	valueFormat;		/* Defines the types of data in the
520 					 * ValueRecord */
521   USHORT	valueCount;		/* Number of ValueRecords */
522   ValueRecord	values;			/* Array of ValueRecords--positioning
523 					 * values applied to glyphs */
524   public:
525   DEFINE_SIZE_ARRAY (8, values);
526 };
527 
528 struct SinglePos
529 {
530   template <typename context_t>
dispatchOT::SinglePos531   inline typename context_t::return_t dispatch (context_t *c) const
532   {
533     TRACE_DISPATCH (this, u.format);
534     switch (u.format) {
535     case 1: return TRACE_RETURN (c->dispatch (u.format1));
536     case 2: return TRACE_RETURN (c->dispatch (u.format2));
537     default:return TRACE_RETURN (c->default_return_value ());
538     }
539   }
540 
sanitizeOT::SinglePos541   inline bool sanitize (hb_sanitize_context_t *c) {
542     TRACE_SANITIZE (this);
543     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
544     switch (u.format) {
545     case 1: return TRACE_RETURN (u.format1.sanitize (c));
546     case 2: return TRACE_RETURN (u.format2.sanitize (c));
547     default:return TRACE_RETURN (true);
548     }
549   }
550 
551   protected:
552   union {
553   USHORT		format;		/* Format identifier */
554   SinglePosFormat1	format1;
555   SinglePosFormat2	format2;
556   } u;
557 };
558 
559 
560 struct PairValueRecord
561 {
562   friend struct PairSet;
563 
564   protected:
565   GlyphID	secondGlyph;		/* GlyphID of second glyph in the
566 					 * pair--first glyph is listed in the
567 					 * Coverage table */
568   ValueRecord	values;			/* Positioning data for the first glyph
569 					 * followed by for second glyph */
570   public:
571   DEFINE_SIZE_ARRAY (2, values);
572 };
573 
574 struct PairSet
575 {
576   friend struct PairPosFormat1;
577 
collect_glyphsOT::PairSet578   inline void collect_glyphs (hb_collect_glyphs_context_t *c,
579 			      const ValueFormat *valueFormats) const
580   {
581     TRACE_COLLECT_GLYPHS (this);
582     unsigned int len1 = valueFormats[0].get_len ();
583     unsigned int len2 = valueFormats[1].get_len ();
584     unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
585 
586     const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
587     unsigned int count = len;
588     for (unsigned int i = 0; i < count; i++)
589     {
590       c->input->add (record->secondGlyph);
591       record = &StructAtOffset<PairValueRecord> (record, record_size);
592     }
593   }
594 
applyOT::PairSet595   inline bool apply (hb_apply_context_t *c,
596 		     const ValueFormat *valueFormats,
597 		     unsigned int pos) const
598   {
599     TRACE_APPLY (this);
600     hb_buffer_t *buffer = c->buffer;
601     unsigned int len1 = valueFormats[0].get_len ();
602     unsigned int len2 = valueFormats[1].get_len ();
603     unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
604 
605     const PairValueRecord *record_array = CastP<PairValueRecord> (arrayZ);
606     unsigned int count = len;
607 
608     /* Hand-coded bsearch. */
609     if (unlikely (!count))
610       return TRACE_RETURN (false);
611     hb_codepoint_t x = buffer->info[pos].codepoint;
612     int min = 0, max = (int) count - 1;
613     while (min <= max)
614     {
615       int mid = (min + max) / 2;
616       const PairValueRecord *record = &StructAtOffset<PairValueRecord> (record_array, record_size * mid);
617       hb_codepoint_t mid_x = record->secondGlyph;
618       if (x < mid_x)
619         max = mid - 1;
620       else if (x > mid_x)
621         min = mid + 1;
622       else
623       {
624 	valueFormats[0].apply_value (c->font, c->direction, this,
625 				     &record->values[0], buffer->cur_pos());
626 	valueFormats[1].apply_value (c->font, c->direction, this,
627 				     &record->values[len1], buffer->pos[pos]);
628 	if (len2)
629 	  pos++;
630 	buffer->idx = pos;
631 	return TRACE_RETURN (true);
632       }
633     }
634 
635     return TRACE_RETURN (false);
636   }
637 
638   struct sanitize_closure_t {
639     void *base;
640     ValueFormat *valueFormats;
641     unsigned int len1; /* valueFormats[0].get_len() */
642     unsigned int stride; /* 1 + len1 + len2 */
643   };
644 
sanitizeOT::PairSet645   inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) {
646     TRACE_SANITIZE (this);
647     if (!(c->check_struct (this)
648        && c->check_array (arrayZ, USHORT::static_size * closure->stride, len))) return TRACE_RETURN (false);
649 
650     unsigned int count = len;
651     PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
652     return TRACE_RETURN (closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride)
653 		      && closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride));
654   }
655 
656   protected:
657   USHORT	len;			/* Number of PairValueRecords */
658   USHORT	arrayZ[VAR];		/* Array of PairValueRecords--ordered
659 					 * by GlyphID of the second glyph */
660   public:
661   DEFINE_SIZE_ARRAY (2, arrayZ);
662 };
663 
664 struct PairPosFormat1
665 {
collect_glyphsOT::PairPosFormat1666   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
667   {
668     TRACE_COLLECT_GLYPHS (this);
669     (this+coverage).add_coverage (c->input);
670     unsigned int count = pairSet.len;
671     for (unsigned int i = 0; i < count; i++)
672       (this+pairSet[i]).collect_glyphs (c, &valueFormat1);
673   }
674 
get_coverageOT::PairPosFormat1675   inline const Coverage &get_coverage (void) const
676   {
677     return this+coverage;
678   }
679 
applyOT::PairPosFormat1680   inline bool apply (hb_apply_context_t *c) const
681   {
682     TRACE_APPLY (this);
683     hb_buffer_t *buffer = c->buffer;
684     hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, 1);
685     if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
686 
687     unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
688     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
689 
690     if (!skippy_iter.next ()) return TRACE_RETURN (false);
691 
692     return TRACE_RETURN ((this+pairSet[index]).apply (c, &valueFormat1, skippy_iter.idx));
693   }
694 
sanitizeOT::PairPosFormat1695   inline bool sanitize (hb_sanitize_context_t *c) {
696     TRACE_SANITIZE (this);
697 
698     unsigned int len1 = valueFormat1.get_len ();
699     unsigned int len2 = valueFormat2.get_len ();
700     PairSet::sanitize_closure_t closure = {
701       this,
702       &valueFormat1,
703       len1,
704       1 + len1 + len2
705     };
706 
707     return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
708   }
709 
710   protected:
711   USHORT	format;			/* Format identifier--format = 1 */
712   OffsetTo<Coverage>
713 		coverage;		/* Offset to Coverage table--from
714 					 * beginning of subtable */
715   ValueFormat	valueFormat1;		/* Defines the types of data in
716 					 * ValueRecord1--for the first glyph
717 					 * in the pair--may be zero (0) */
718   ValueFormat	valueFormat2;		/* Defines the types of data in
719 					 * ValueRecord2--for the second glyph
720 					 * in the pair--may be zero (0) */
721   OffsetArrayOf<PairSet>
722 		pairSet;		/* Array of PairSet tables
723 					 * ordered by Coverage Index */
724   public:
725   DEFINE_SIZE_ARRAY (10, pairSet);
726 };
727 
728 struct PairPosFormat2
729 {
collect_glyphsOT::PairPosFormat2730   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
731   {
732     TRACE_COLLECT_GLYPHS (this);
733     /* (this+coverage).add_coverage (c->input); // Don't need this. */
734 
735     unsigned int count1 = class1Count;
736     const ClassDef &klass1 = this+classDef1;
737     for (unsigned int i = 0; i < count1; i++)
738       klass1.add_class (c->input, i);
739 
740     unsigned int count2 = class2Count;
741     const ClassDef &klass2 = this+classDef2;
742     for (unsigned int i = 0; i < count2; i++)
743       klass2.add_class (c->input, i);
744   }
745 
get_coverageOT::PairPosFormat2746   inline const Coverage &get_coverage (void) const
747   {
748     return this+coverage;
749   }
750 
applyOT::PairPosFormat2751   inline bool apply (hb_apply_context_t *c) const
752   {
753     TRACE_APPLY (this);
754     hb_buffer_t *buffer = c->buffer;
755     hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, 1);
756     if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
757 
758     unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
759     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
760 
761     if (!skippy_iter.next ()) return TRACE_RETURN (false);
762 
763     unsigned int len1 = valueFormat1.get_len ();
764     unsigned int len2 = valueFormat2.get_len ();
765     unsigned int record_len = len1 + len2;
766 
767     unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint);
768     unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint);
769     if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return TRACE_RETURN (false);
770 
771     const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
772     valueFormat1.apply_value (c->font, c->direction, this,
773 			      v, buffer->cur_pos());
774     valueFormat2.apply_value (c->font, c->direction, this,
775 			      v + len1, buffer->pos[skippy_iter.idx]);
776 
777     buffer->idx = skippy_iter.idx;
778     if (len2)
779       buffer->idx++;
780 
781     return TRACE_RETURN (true);
782   }
783 
sanitizeOT::PairPosFormat2784   inline bool sanitize (hb_sanitize_context_t *c) {
785     TRACE_SANITIZE (this);
786     if (!(c->check_struct (this)
787        && coverage.sanitize (c, this)
788        && classDef1.sanitize (c, this)
789        && classDef2.sanitize (c, this))) return TRACE_RETURN (false);
790 
791     unsigned int len1 = valueFormat1.get_len ();
792     unsigned int len2 = valueFormat2.get_len ();
793     unsigned int stride = len1 + len2;
794     unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
795     unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
796     return TRACE_RETURN (c->check_array (values, record_size, count) &&
797 			 valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
798 			 valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride));
799   }
800 
801   protected:
802   USHORT	format;			/* Format identifier--format = 2 */
803   OffsetTo<Coverage>
804 		coverage;		/* Offset to Coverage table--from
805 					 * beginning of subtable */
806   ValueFormat	valueFormat1;		/* ValueRecord definition--for the
807 					 * first glyph of the pair--may be zero
808 					 * (0) */
809   ValueFormat	valueFormat2;		/* ValueRecord definition--for the
810 					 * second glyph of the pair--may be
811 					 * zero (0) */
812   OffsetTo<ClassDef>
813 		classDef1;		/* Offset to ClassDef table--from
814 					 * beginning of PairPos subtable--for
815 					 * the first glyph of the pair */
816   OffsetTo<ClassDef>
817 		classDef2;		/* Offset to ClassDef table--from
818 					 * beginning of PairPos subtable--for
819 					 * the second glyph of the pair */
820   USHORT	class1Count;		/* Number of classes in ClassDef1
821 					 * table--includes Class0 */
822   USHORT	class2Count;		/* Number of classes in ClassDef2
823 					 * table--includes Class0 */
824   ValueRecord	values;			/* Matrix of value pairs:
825 					 * class1-major, class2-minor,
826 					 * Each entry has value1 and value2 */
827   public:
828   DEFINE_SIZE_ARRAY (16, values);
829 };
830 
831 struct PairPos
832 {
833   template <typename context_t>
dispatchOT::PairPos834   inline typename context_t::return_t dispatch (context_t *c) const
835   {
836     TRACE_DISPATCH (this, u.format);
837     switch (u.format) {
838     case 1: return TRACE_RETURN (c->dispatch (u.format1));
839     case 2: return TRACE_RETURN (c->dispatch (u.format2));
840     default:return TRACE_RETURN (c->default_return_value ());
841     }
842   }
843 
sanitizeOT::PairPos844   inline bool sanitize (hb_sanitize_context_t *c) {
845     TRACE_SANITIZE (this);
846     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
847     switch (u.format) {
848     case 1: return TRACE_RETURN (u.format1.sanitize (c));
849     case 2: return TRACE_RETURN (u.format2.sanitize (c));
850     default:return TRACE_RETURN (true);
851     }
852   }
853 
854   protected:
855   union {
856   USHORT		format;		/* Format identifier */
857   PairPosFormat1	format1;
858   PairPosFormat2	format2;
859   } u;
860 };
861 
862 
863 struct EntryExitRecord
864 {
865   friend struct CursivePosFormat1;
866 
sanitizeOT::EntryExitRecord867   inline bool sanitize (hb_sanitize_context_t *c, void *base) {
868     TRACE_SANITIZE (this);
869     return TRACE_RETURN (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
870   }
871 
872   protected:
873   OffsetTo<Anchor>
874 		entryAnchor;		/* Offset to EntryAnchor table--from
875 					 * beginning of CursivePos
876 					 * subtable--may be NULL */
877   OffsetTo<Anchor>
878 		exitAnchor;		/* Offset to ExitAnchor table--from
879 					 * beginning of CursivePos
880 					 * subtable--may be NULL */
881   public:
882   DEFINE_SIZE_STATIC (4);
883 };
884 
885 struct CursivePosFormat1
886 {
collect_glyphsOT::CursivePosFormat1887   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
888   {
889     TRACE_COLLECT_GLYPHS (this);
890     (this+coverage).add_coverage (c->input);
891   }
892 
get_coverageOT::CursivePosFormat1893   inline const Coverage &get_coverage (void) const
894   {
895     return this+coverage;
896   }
897 
applyOT::CursivePosFormat1898   inline bool apply (hb_apply_context_t *c) const
899   {
900     TRACE_APPLY (this);
901     hb_buffer_t *buffer = c->buffer;
902 
903     /* We don't handle mark glyphs here. */
904     if (unlikely (_hb_glyph_info_is_mark (&buffer->cur()))) return TRACE_RETURN (false);
905 
906     hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, 1);
907     if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
908 
909     const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage  (buffer->cur().codepoint)];
910     if (!this_record.exitAnchor) return TRACE_RETURN (false);
911 
912     if (!skippy_iter.next ()) return TRACE_RETURN (false);
913 
914     const EntryExitRecord &next_record = entryExitRecord[(this+coverage).get_coverage  (buffer->info[skippy_iter.idx].codepoint)];
915     if (!next_record.entryAnchor) return TRACE_RETURN (false);
916 
917     unsigned int i = buffer->idx;
918     unsigned int j = skippy_iter.idx;
919 
920     hb_position_t entry_x, entry_y, exit_x, exit_y;
921     (this+this_record.exitAnchor).get_anchor (c->font, buffer->info[i].codepoint, &exit_x, &exit_y);
922     (this+next_record.entryAnchor).get_anchor (c->font, buffer->info[j].codepoint, &entry_x, &entry_y);
923 
924     hb_glyph_position_t *pos = buffer->pos;
925 
926     hb_position_t d;
927     /* Main-direction adjustment */
928     switch (c->direction) {
929       case HB_DIRECTION_LTR:
930 	pos[i].x_advance  =  exit_x + pos[i].x_offset;
931 
932 	d = entry_x + pos[j].x_offset;
933 	pos[j].x_advance -= d;
934 	pos[j].x_offset  -= d;
935 	break;
936       case HB_DIRECTION_RTL:
937 	d = exit_x + pos[i].x_offset;
938 	pos[i].x_advance -= d;
939 	pos[i].x_offset  -= d;
940 
941 	pos[j].x_advance  =  entry_x + pos[j].x_offset;
942 	break;
943       case HB_DIRECTION_TTB:
944 	pos[i].y_advance  =  exit_y + pos[i].y_offset;
945 
946 	d = entry_y + pos[j].y_offset;
947 	pos[j].y_advance -= d;
948 	pos[j].y_offset  -= d;
949 	break;
950       case HB_DIRECTION_BTT:
951 	d = exit_y + pos[i].y_offset;
952 	pos[i].y_advance -= d;
953 	pos[i].y_offset  -= d;
954 
955 	pos[j].y_advance  =  entry_y;
956 	break;
957       case HB_DIRECTION_INVALID:
958       default:
959 	break;
960     }
961 
962     /* Cross-direction adjustment */
963     if  (c->lookup_props & LookupFlag::RightToLeft) {
964       pos[i].cursive_chain() = j - i;
965       if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
966 	pos[i].y_offset = entry_y - exit_y;
967       else
968 	pos[i].x_offset = entry_x - exit_x;
969     } else {
970       pos[j].cursive_chain() = i - j;
971       if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
972 	pos[j].y_offset = exit_y - entry_y;
973       else
974 	pos[j].x_offset = exit_x - entry_x;
975     }
976 
977     buffer->idx = j;
978     return TRACE_RETURN (true);
979   }
980 
sanitizeOT::CursivePosFormat1981   inline bool sanitize (hb_sanitize_context_t *c) {
982     TRACE_SANITIZE (this);
983     return TRACE_RETURN (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
984   }
985 
986   protected:
987   USHORT	format;			/* Format identifier--format = 1 */
988   OffsetTo<Coverage>
989 		coverage;		/* Offset to Coverage table--from
990 					 * beginning of subtable */
991   ArrayOf<EntryExitRecord>
992 		entryExitRecord;	/* Array of EntryExit records--in
993 					 * Coverage Index order */
994   public:
995   DEFINE_SIZE_ARRAY (6, entryExitRecord);
996 };
997 
998 struct CursivePos
999 {
1000   template <typename context_t>
dispatchOT::CursivePos1001   inline typename context_t::return_t dispatch (context_t *c) const
1002   {
1003     TRACE_DISPATCH (this, u.format);
1004     switch (u.format) {
1005     case 1: return TRACE_RETURN (c->dispatch (u.format1));
1006     default:return TRACE_RETURN (c->default_return_value ());
1007     }
1008   }
1009 
sanitizeOT::CursivePos1010   inline bool sanitize (hb_sanitize_context_t *c) {
1011     TRACE_SANITIZE (this);
1012     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
1013     switch (u.format) {
1014     case 1: return TRACE_RETURN (u.format1.sanitize (c));
1015     default:return TRACE_RETURN (true);
1016     }
1017   }
1018 
1019   protected:
1020   union {
1021   USHORT		format;		/* Format identifier */
1022   CursivePosFormat1	format1;
1023   } u;
1024 };
1025 
1026 
1027 typedef AnchorMatrix BaseArray;		/* base-major--
1028 					 * in order of BaseCoverage Index--,
1029 					 * mark-minor--
1030 					 * ordered by class--zero-based. */
1031 
1032 struct MarkBasePosFormat1
1033 {
collect_glyphsOT::MarkBasePosFormat11034   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1035   {
1036     TRACE_COLLECT_GLYPHS (this);
1037     (this+markCoverage).add_coverage (c->input);
1038     (this+baseCoverage).add_coverage (c->input);
1039   }
1040 
get_coverageOT::MarkBasePosFormat11041   inline const Coverage &get_coverage (void) const
1042   {
1043     return this+markCoverage;
1044   }
1045 
applyOT::MarkBasePosFormat11046   inline bool apply (hb_apply_context_t *c) const
1047   {
1048     TRACE_APPLY (this);
1049     hb_buffer_t *buffer = c->buffer;
1050     unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
1051     if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
1052 
1053     /* now we search backwards for a non-mark glyph */
1054     hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, buffer->idx, 1);
1055     skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
1056     do {
1057       if (!skippy_iter.prev ()) return TRACE_RETURN (false);
1058       /* We only want to attach to the first of a MultipleSubst sequence.  Reject others. */
1059       if (0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx])) break;
1060       skippy_iter.reject ();
1061     } while (1);
1062 
1063     /* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */
1064     if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { /*return TRACE_RETURN (false);*/ }
1065 
1066     unsigned int base_index = (this+baseCoverage).get_coverage  (buffer->info[skippy_iter.idx].codepoint);
1067     if (base_index == NOT_COVERED) return TRACE_RETURN (false);
1068 
1069     return TRACE_RETURN ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx));
1070   }
1071 
sanitizeOT::MarkBasePosFormat11072   inline bool sanitize (hb_sanitize_context_t *c) {
1073     TRACE_SANITIZE (this);
1074     return TRACE_RETURN (c->check_struct (this) && markCoverage.sanitize (c, this) && baseCoverage.sanitize (c, this) &&
1075 			 markArray.sanitize (c, this) && baseArray.sanitize (c, this, (unsigned int) classCount));
1076   }
1077 
1078   protected:
1079   USHORT	format;			/* Format identifier--format = 1 */
1080   OffsetTo<Coverage>
1081 		markCoverage;		/* Offset to MarkCoverage table--from
1082 					 * beginning of MarkBasePos subtable */
1083   OffsetTo<Coverage>
1084 		baseCoverage;		/* Offset to BaseCoverage table--from
1085 					 * beginning of MarkBasePos subtable */
1086   USHORT	classCount;		/* Number of classes defined for marks */
1087   OffsetTo<MarkArray>
1088 		markArray;		/* Offset to MarkArray table--from
1089 					 * beginning of MarkBasePos subtable */
1090   OffsetTo<BaseArray>
1091 		baseArray;		/* Offset to BaseArray table--from
1092 					 * beginning of MarkBasePos subtable */
1093   public:
1094   DEFINE_SIZE_STATIC (12);
1095 };
1096 
1097 struct MarkBasePos
1098 {
1099   template <typename context_t>
dispatchOT::MarkBasePos1100   inline typename context_t::return_t dispatch (context_t *c) const
1101   {
1102     TRACE_DISPATCH (this, u.format);
1103     switch (u.format) {
1104     case 1: return TRACE_RETURN (c->dispatch (u.format1));
1105     default:return TRACE_RETURN (c->default_return_value ());
1106     }
1107   }
1108 
sanitizeOT::MarkBasePos1109   inline bool sanitize (hb_sanitize_context_t *c) {
1110     TRACE_SANITIZE (this);
1111     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
1112     switch (u.format) {
1113     case 1: return TRACE_RETURN (u.format1.sanitize (c));
1114     default:return TRACE_RETURN (true);
1115     }
1116   }
1117 
1118   protected:
1119   union {
1120   USHORT		format;		/* Format identifier */
1121   MarkBasePosFormat1	format1;
1122   } u;
1123 };
1124 
1125 
1126 typedef AnchorMatrix LigatureAttach;	/* component-major--
1127 					 * in order of writing direction--,
1128 					 * mark-minor--
1129 					 * ordered by class--zero-based. */
1130 
1131 typedef OffsetListOf<LigatureAttach> LigatureArray;
1132 					/* Array of LigatureAttach
1133 					 * tables ordered by
1134 					 * LigatureCoverage Index */
1135 
1136 struct MarkLigPosFormat1
1137 {
collect_glyphsOT::MarkLigPosFormat11138   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1139   {
1140     TRACE_COLLECT_GLYPHS (this);
1141     (this+markCoverage).add_coverage (c->input);
1142     (this+ligatureCoverage).add_coverage (c->input);
1143   }
1144 
get_coverageOT::MarkLigPosFormat11145   inline const Coverage &get_coverage (void) const
1146   {
1147     return this+markCoverage;
1148   }
1149 
applyOT::MarkLigPosFormat11150   inline bool apply (hb_apply_context_t *c) const
1151   {
1152     TRACE_APPLY (this);
1153     hb_buffer_t *buffer = c->buffer;
1154     unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
1155     if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
1156 
1157     /* now we search backwards for a non-mark glyph */
1158     hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, buffer->idx, 1);
1159     skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
1160     if (!skippy_iter.prev ()) return TRACE_RETURN (false);
1161 
1162     /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */
1163     if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { /*return TRACE_RETURN (false);*/ }
1164 
1165     unsigned int j = skippy_iter.idx;
1166     unsigned int lig_index = (this+ligatureCoverage).get_coverage  (buffer->info[j].codepoint);
1167     if (lig_index == NOT_COVERED) return TRACE_RETURN (false);
1168 
1169     const LigatureArray& lig_array = this+ligatureArray;
1170     const LigatureAttach& lig_attach = lig_array[lig_index];
1171 
1172     /* Find component to attach to */
1173     unsigned int comp_count = lig_attach.rows;
1174     if (unlikely (!comp_count)) return TRACE_RETURN (false);
1175 
1176     /* We must now check whether the ligature ID of the current mark glyph
1177      * is identical to the ligature ID of the found ligature.  If yes, we
1178      * can directly use the component index.  If not, we attach the mark
1179      * glyph to the last component of the ligature. */
1180     unsigned int comp_index;
1181     unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[j]);
1182     unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur());
1183     unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
1184     if (lig_id && lig_id == mark_id && mark_comp > 0)
1185       comp_index = MIN (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1;
1186     else
1187       comp_index = comp_count - 1;
1188 
1189     return TRACE_RETURN ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
1190   }
1191 
sanitizeOT::MarkLigPosFormat11192   inline bool sanitize (hb_sanitize_context_t *c) {
1193     TRACE_SANITIZE (this);
1194     return TRACE_RETURN (c->check_struct (this) && markCoverage.sanitize (c, this) && ligatureCoverage.sanitize (c, this) &&
1195 			 markArray.sanitize (c, this) && ligatureArray.sanitize (c, this, (unsigned int) classCount));
1196   }
1197 
1198   protected:
1199   USHORT	format;			/* Format identifier--format = 1 */
1200   OffsetTo<Coverage>
1201 		markCoverage;		/* Offset to Mark Coverage table--from
1202 					 * beginning of MarkLigPos subtable */
1203   OffsetTo<Coverage>
1204 		ligatureCoverage;	/* Offset to Ligature Coverage
1205 					 * table--from beginning of MarkLigPos
1206 					 * subtable */
1207   USHORT	classCount;		/* Number of defined mark classes */
1208   OffsetTo<MarkArray>
1209 		markArray;		/* Offset to MarkArray table--from
1210 					 * beginning of MarkLigPos subtable */
1211   OffsetTo<LigatureArray>
1212 		ligatureArray;		/* Offset to LigatureArray table--from
1213 					 * beginning of MarkLigPos subtable */
1214   public:
1215   DEFINE_SIZE_STATIC (12);
1216 };
1217 
1218 struct MarkLigPos
1219 {
1220   template <typename context_t>
dispatchOT::MarkLigPos1221   inline typename context_t::return_t dispatch (context_t *c) const
1222   {
1223     TRACE_DISPATCH (this, u.format);
1224     switch (u.format) {
1225     case 1: return TRACE_RETURN (c->dispatch (u.format1));
1226     default:return TRACE_RETURN (c->default_return_value ());
1227     }
1228   }
1229 
sanitizeOT::MarkLigPos1230   inline bool sanitize (hb_sanitize_context_t *c) {
1231     TRACE_SANITIZE (this);
1232     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
1233     switch (u.format) {
1234     case 1: return TRACE_RETURN (u.format1.sanitize (c));
1235     default:return TRACE_RETURN (true);
1236     }
1237   }
1238 
1239   protected:
1240   union {
1241   USHORT		format;		/* Format identifier */
1242   MarkLigPosFormat1	format1;
1243   } u;
1244 };
1245 
1246 
1247 typedef AnchorMatrix Mark2Array;	/* mark2-major--
1248 					 * in order of Mark2Coverage Index--,
1249 					 * mark1-minor--
1250 					 * ordered by class--zero-based. */
1251 
1252 struct MarkMarkPosFormat1
1253 {
collect_glyphsOT::MarkMarkPosFormat11254   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1255   {
1256     TRACE_COLLECT_GLYPHS (this);
1257     (this+mark1Coverage).add_coverage (c->input);
1258     (this+mark2Coverage).add_coverage (c->input);
1259   }
1260 
get_coverageOT::MarkMarkPosFormat11261   inline const Coverage &get_coverage (void) const
1262   {
1263     return this+mark1Coverage;
1264   }
1265 
applyOT::MarkMarkPosFormat11266   inline bool apply (hb_apply_context_t *c) const
1267   {
1268     TRACE_APPLY (this);
1269     hb_buffer_t *buffer = c->buffer;
1270     unsigned int mark1_index = (this+mark1Coverage).get_coverage  (buffer->cur().codepoint);
1271     if (likely (mark1_index == NOT_COVERED)) return TRACE_RETURN (false);
1272 
1273     /* now we search backwards for a suitable mark glyph until a non-mark glyph */
1274     hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, buffer->idx, 1);
1275     skippy_iter.set_lookup_props (c->lookup_props & ~LookupFlag::IgnoreFlags);
1276     if (!skippy_iter.prev ()) return TRACE_RETURN (false);
1277 
1278     if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])) { return TRACE_RETURN (false); }
1279 
1280     unsigned int j = skippy_iter.idx;
1281 
1282     unsigned int id1 = _hb_glyph_info_get_lig_id (&buffer->cur());
1283     unsigned int id2 = _hb_glyph_info_get_lig_id (&buffer->info[j]);
1284     unsigned int comp1 = _hb_glyph_info_get_lig_comp (&buffer->cur());
1285     unsigned int comp2 = _hb_glyph_info_get_lig_comp (&buffer->info[j]);
1286 
1287     if (likely (id1 == id2)) {
1288       if (id1 == 0) /* Marks belonging to the same base. */
1289 	goto good;
1290       else if (comp1 == comp2) /* Marks belonging to the same ligature component. */
1291         goto good;
1292     } else {
1293       /* If ligature ids don't match, it may be the case that one of the marks
1294        * itself is a ligature.  In which case match. */
1295       if ((id1 > 0 && !comp1) || (id2 > 0 && !comp2))
1296 	goto good;
1297     }
1298 
1299     /* Didn't match. */
1300     return TRACE_RETURN (false);
1301 
1302     good:
1303     unsigned int mark2_index = (this+mark2Coverage).get_coverage  (buffer->info[j].codepoint);
1304     if (mark2_index == NOT_COVERED) return TRACE_RETURN (false);
1305 
1306     return TRACE_RETURN ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j));
1307   }
1308 
sanitizeOT::MarkMarkPosFormat11309   inline bool sanitize (hb_sanitize_context_t *c) {
1310     TRACE_SANITIZE (this);
1311     return TRACE_RETURN (c->check_struct (this) && mark1Coverage.sanitize (c, this) &&
1312 			 mark2Coverage.sanitize (c, this) && mark1Array.sanitize (c, this)
1313 			 && mark2Array.sanitize (c, this, (unsigned int) classCount));
1314   }
1315 
1316   protected:
1317   USHORT	format;			/* Format identifier--format = 1 */
1318   OffsetTo<Coverage>
1319 		mark1Coverage;		/* Offset to Combining Mark1 Coverage
1320 					 * table--from beginning of MarkMarkPos
1321 					 * subtable */
1322   OffsetTo<Coverage>
1323 		mark2Coverage;		/* Offset to Combining Mark2 Coverage
1324 					 * table--from beginning of MarkMarkPos
1325 					 * subtable */
1326   USHORT	classCount;		/* Number of defined mark classes */
1327   OffsetTo<MarkArray>
1328 		mark1Array;		/* Offset to Mark1Array table--from
1329 					 * beginning of MarkMarkPos subtable */
1330   OffsetTo<Mark2Array>
1331 		mark2Array;		/* Offset to Mark2Array table--from
1332 					 * beginning of MarkMarkPos subtable */
1333   public:
1334   DEFINE_SIZE_STATIC (12);
1335 };
1336 
1337 struct MarkMarkPos
1338 {
1339   template <typename context_t>
dispatchOT::MarkMarkPos1340   inline typename context_t::return_t dispatch (context_t *c) const
1341   {
1342     TRACE_DISPATCH (this, u.format);
1343     switch (u.format) {
1344     case 1: return TRACE_RETURN (c->dispatch (u.format1));
1345     default:return TRACE_RETURN (c->default_return_value ());
1346     }
1347   }
1348 
sanitizeOT::MarkMarkPos1349   inline bool sanitize (hb_sanitize_context_t *c) {
1350     TRACE_SANITIZE (this);
1351     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
1352     switch (u.format) {
1353     case 1: return TRACE_RETURN (u.format1.sanitize (c));
1354     default:return TRACE_RETURN (true);
1355     }
1356   }
1357 
1358   protected:
1359   union {
1360   USHORT		format;		/* Format identifier */
1361   MarkMarkPosFormat1	format1;
1362   } u;
1363 };
1364 
1365 
1366 struct ContextPos : Context {};
1367 
1368 struct ChainContextPos : ChainContext {};
1369 
1370 struct ExtensionPos : Extension<ExtensionPos>
1371 {
1372   typedef struct PosLookupSubTable LookupSubTable;
1373 };
1374 
1375 
1376 
1377 /*
1378  * PosLookup
1379  */
1380 
1381 
1382 struct PosLookupSubTable
1383 {
1384   friend struct PosLookup;
1385 
1386   enum Type {
1387     Single		= 1,
1388     Pair		= 2,
1389     Cursive		= 3,
1390     MarkBase		= 4,
1391     MarkLig		= 5,
1392     MarkMark		= 6,
1393     Context		= 7,
1394     ChainContext	= 8,
1395     Extension		= 9
1396   };
1397 
1398   template <typename context_t>
dispatchOT::PosLookupSubTable1399   inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
1400   {
1401     TRACE_DISPATCH (this, lookup_type);
1402     switch (lookup_type) {
1403     case Single:		return TRACE_RETURN (u.single.dispatch (c));
1404     case Pair:			return TRACE_RETURN (u.pair.dispatch (c));
1405     case Cursive:		return TRACE_RETURN (u.cursive.dispatch (c));
1406     case MarkBase:		return TRACE_RETURN (u.markBase.dispatch (c));
1407     case MarkLig:		return TRACE_RETURN (u.markLig.dispatch (c));
1408     case MarkMark:		return TRACE_RETURN (u.markMark.dispatch (c));
1409     case Context:		return TRACE_RETURN (u.context.dispatch (c));
1410     case ChainContext:		return TRACE_RETURN (u.chainContext.dispatch (c));
1411     case Extension:		return TRACE_RETURN (u.extension.dispatch (c));
1412     default:			return TRACE_RETURN (c->default_return_value ());
1413     }
1414   }
1415 
sanitizeOT::PosLookupSubTable1416   inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
1417     TRACE_SANITIZE (this);
1418     if (!u.header.sub_format.sanitize (c))
1419       return TRACE_RETURN (false);
1420     switch (lookup_type) {
1421     case Single:		return TRACE_RETURN (u.single.sanitize (c));
1422     case Pair:			return TRACE_RETURN (u.pair.sanitize (c));
1423     case Cursive:		return TRACE_RETURN (u.cursive.sanitize (c));
1424     case MarkBase:		return TRACE_RETURN (u.markBase.sanitize (c));
1425     case MarkLig:		return TRACE_RETURN (u.markLig.sanitize (c));
1426     case MarkMark:		return TRACE_RETURN (u.markMark.sanitize (c));
1427     case Context:		return TRACE_RETURN (u.context.sanitize (c));
1428     case ChainContext:		return TRACE_RETURN (u.chainContext.sanitize (c));
1429     case Extension:		return TRACE_RETURN (u.extension.sanitize (c));
1430     default:			return TRACE_RETURN (true);
1431     }
1432   }
1433 
1434   protected:
1435   union {
1436   struct {
1437     USHORT		sub_format;
1438   } header;
1439   SinglePos		single;
1440   PairPos		pair;
1441   CursivePos		cursive;
1442   MarkBasePos		markBase;
1443   MarkLigPos		markLig;
1444   MarkMarkPos		markMark;
1445   ContextPos		context;
1446   ChainContextPos	chainContext;
1447   ExtensionPos		extension;
1448   } u;
1449   public:
1450   DEFINE_SIZE_UNION (2, header.sub_format);
1451 };
1452 
1453 
1454 struct PosLookup : Lookup
1455 {
get_subtableOT::PosLookup1456   inline const PosLookupSubTable& get_subtable (unsigned int i) const
1457   { return this+CastR<OffsetArrayOf<PosLookupSubTable> > (subTable)[i]; }
1458 
is_reverseOT::PosLookup1459   inline bool is_reverse (void) const
1460   {
1461     return false;
1462   }
1463 
collect_glyphsOT::PosLookup1464   inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
1465   {
1466     TRACE_COLLECT_GLYPHS (this);
1467     c->set_recurse_func (NULL);
1468     return TRACE_RETURN (dispatch (c));
1469   }
1470 
1471   template <typename set_t>
add_coverageOT::PosLookup1472   inline void add_coverage (set_t *glyphs) const
1473   {
1474     hb_get_coverage_context_t c;
1475     const Coverage *last = NULL;
1476     unsigned int count = get_subtable_count ();
1477     for (unsigned int i = 0; i < count; i++) {
1478       const Coverage *coverage = &get_subtable (i).dispatch (&c, get_type ());
1479       if (coverage != last) {
1480         coverage->add_coverage (glyphs);
1481         last = coverage;
1482       }
1483     }
1484   }
1485 
apply_onceOT::PosLookup1486   inline bool apply_once (hb_apply_context_t *c) const
1487   {
1488     TRACE_APPLY (this);
1489     if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props))
1490       return TRACE_RETURN (false);
1491     return TRACE_RETURN (dispatch (c));
1492   }
1493 
1494   static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
1495 
1496   template <typename context_t>
1497   static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
1498 
1499   template <typename context_t>
dispatchOT::PosLookup1500   inline typename context_t::return_t dispatch (context_t *c) const
1501   {
1502     unsigned int lookup_type = get_type ();
1503     TRACE_DISPATCH (this, lookup_type);
1504     unsigned int count = get_subtable_count ();
1505     for (unsigned int i = 0; i < count; i++) {
1506       typename context_t::return_t r = get_subtable (i).dispatch (c, lookup_type);
1507       if (c->stop_sublookup_iteration (r))
1508         return TRACE_RETURN (r);
1509     }
1510     return TRACE_RETURN (c->default_return_value ());
1511   }
1512 
sanitizeOT::PosLookup1513   inline bool sanitize (hb_sanitize_context_t *c) {
1514     TRACE_SANITIZE (this);
1515     if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
1516     OffsetArrayOf<PosLookupSubTable> &list = CastR<OffsetArrayOf<PosLookupSubTable> > (subTable);
1517     return TRACE_RETURN (list.sanitize (c, this, get_type ()));
1518   }
1519 };
1520 
1521 typedef OffsetListOf<PosLookup> PosLookupList;
1522 
1523 /*
1524  * GPOS -- The Glyph Positioning Table
1525  */
1526 
1527 struct GPOS : GSUBGPOS
1528 {
1529   static const hb_tag_t tableTag	= HB_OT_TAG_GPOS;
1530 
get_lookupOT::GPOS1531   inline const PosLookup& get_lookup (unsigned int i) const
1532   { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
1533 
1534   static inline void position_start (hb_font_t *font, hb_buffer_t *buffer);
1535   static inline void position_finish (hb_font_t *font, hb_buffer_t *buffer);
1536 
sanitizeOT::GPOS1537   inline bool sanitize (hb_sanitize_context_t *c) {
1538     TRACE_SANITIZE (this);
1539     if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
1540     OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
1541     return TRACE_RETURN (list.sanitize (c, this));
1542   }
1543   public:
1544   DEFINE_SIZE_STATIC (10);
1545 };
1546 
1547 
1548 static void
fix_cursive_minor_offset(hb_glyph_position_t * pos,unsigned int i,hb_direction_t direction)1549 fix_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
1550 {
1551   unsigned int j = pos[i].cursive_chain();
1552   if (likely (!j))
1553     return;
1554 
1555   j += i;
1556 
1557   pos[i].cursive_chain() = 0;
1558 
1559   fix_cursive_minor_offset (pos, j, direction);
1560 
1561   if (HB_DIRECTION_IS_HORIZONTAL (direction))
1562     pos[i].y_offset += pos[j].y_offset;
1563   else
1564     pos[i].x_offset += pos[j].x_offset;
1565 }
1566 
1567 static void
fix_mark_attachment(hb_glyph_position_t * pos,unsigned int i,hb_direction_t direction)1568 fix_mark_attachment (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
1569 {
1570   if (likely (!(pos[i].attach_lookback())))
1571     return;
1572 
1573   unsigned int j = i - pos[i].attach_lookback();
1574 
1575   pos[i].x_offset += pos[j].x_offset;
1576   pos[i].y_offset += pos[j].y_offset;
1577 
1578   if (HB_DIRECTION_IS_FORWARD (direction))
1579     for (unsigned int k = j; k < i; k++) {
1580       pos[i].x_offset -= pos[k].x_advance;
1581       pos[i].y_offset -= pos[k].y_advance;
1582     }
1583   else
1584     for (unsigned int k = j + 1; k < i + 1; k++) {
1585       pos[i].x_offset += pos[k].x_advance;
1586       pos[i].y_offset += pos[k].y_advance;
1587     }
1588 }
1589 
1590 void
position_start(hb_font_t * font HB_UNUSED,hb_buffer_t * buffer)1591 GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
1592 {
1593   buffer->clear_positions ();
1594 
1595   unsigned int count = buffer->len;
1596   for (unsigned int i = 0; i < count; i++)
1597     buffer->pos[i].attach_lookback() = buffer->pos[i].cursive_chain() = 0;
1598 }
1599 
1600 void
position_finish(hb_font_t * font HB_UNUSED,hb_buffer_t * buffer)1601 GPOS::position_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
1602 {
1603   _hb_buffer_assert_gsubgpos_vars (buffer);
1604 
1605   unsigned int len;
1606   hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
1607   hb_direction_t direction = buffer->props.direction;
1608 
1609   /* Handle cursive connections */
1610   for (unsigned int i = 0; i < len; i++)
1611     fix_cursive_minor_offset (pos, i, direction);
1612 
1613   /* Handle attachments */
1614   for (unsigned int i = 0; i < len; i++)
1615     fix_mark_attachment (pos, i, direction);
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 /*static*/ 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 /*static*/ 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