• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 = !matrix[row * cols + col].is_null ();
349     return this+matrix[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 (matrix, matrix[0].static_size, count)) return TRACE_RETURN (false);
358     for (unsigned int i = 0; i < count; i++)
359       if (!matrix[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 		matrix[VAR];		/* Matrix of offsets to Anchor tables--
367 					 * from beginning of AnchorMatrix table */
368   public:
369   DEFINE_SIZE_ARRAY (2, matrix);
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);
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> (array);
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 = CastP<PairValueRecord> (array);
606     unsigned int count = len;
607     for (unsigned int i = 0; i < count; i++)
608     {
609       /* TODO bsearch */
610       if (buffer->info[pos].codepoint == record->secondGlyph)
611       {
612 	valueFormats[0].apply_value (c->font, c->direction, this,
613 				     &record->values[0], buffer->cur_pos());
614 	valueFormats[1].apply_value (c->font, c->direction, this,
615 				     &record->values[len1], buffer->pos[pos]);
616 	if (len2)
617 	  pos++;
618 	buffer->idx = pos;
619 	return TRACE_RETURN (true);
620       }
621       record = &StructAtOffset<PairValueRecord> (record, record_size);
622     }
623 
624     return TRACE_RETURN (false);
625   }
626 
627   struct sanitize_closure_t {
628     void *base;
629     ValueFormat *valueFormats;
630     unsigned int len1; /* valueFormats[0].get_len() */
631     unsigned int stride; /* 1 + len1 + len2 */
632   };
633 
sanitizeOT::PairSet634   inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) {
635     TRACE_SANITIZE (this);
636     if (!(c->check_struct (this)
637        && c->check_array (array, USHORT::static_size * closure->stride, len))) return TRACE_RETURN (false);
638 
639     unsigned int count = len;
640     PairValueRecord *record = CastP<PairValueRecord> (array);
641     return TRACE_RETURN (closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride)
642 		      && closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride));
643   }
644 
645   protected:
646   USHORT	len;			/* Number of PairValueRecords */
647   USHORT	array[VAR];		/* Array of PairValueRecords--ordered
648 					 * by GlyphID of the second glyph */
649   public:
650   DEFINE_SIZE_ARRAY (2, array);
651 };
652 
653 struct PairPosFormat1
654 {
collect_glyphsOT::PairPosFormat1655   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
656   {
657     TRACE_COLLECT_GLYPHS (this);
658     (this+coverage).add_coverage (c->input);
659     unsigned int count = pairSet.len;
660     for (unsigned int i = 0; i < count; i++)
661       (this+pairSet[i]).collect_glyphs (c, &valueFormat1);
662   }
663 
get_coverageOT::PairPosFormat1664   inline const Coverage &get_coverage (void) const
665   {
666     return this+coverage;
667   }
668 
applyOT::PairPosFormat1669   inline bool apply (hb_apply_context_t *c) const
670   {
671     TRACE_APPLY (this);
672     hb_buffer_t *buffer = c->buffer;
673     hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, 1);
674     if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
675 
676     unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
677     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
678 
679     if (!skippy_iter.next ()) return TRACE_RETURN (false);
680 
681     return TRACE_RETURN ((this+pairSet[index]).apply (c, &valueFormat1, skippy_iter.idx));
682   }
683 
sanitizeOT::PairPosFormat1684   inline bool sanitize (hb_sanitize_context_t *c) {
685     TRACE_SANITIZE (this);
686 
687     unsigned int len1 = valueFormat1.get_len ();
688     unsigned int len2 = valueFormat2.get_len ();
689     PairSet::sanitize_closure_t closure = {
690       this,
691       &valueFormat1,
692       len1,
693       1 + len1 + len2
694     };
695 
696     return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
697   }
698 
699   protected:
700   USHORT	format;			/* Format identifier--format = 1 */
701   OffsetTo<Coverage>
702 		coverage;		/* Offset to Coverage table--from
703 					 * beginning of subtable */
704   ValueFormat	valueFormat1;		/* Defines the types of data in
705 					 * ValueRecord1--for the first glyph
706 					 * in the pair--may be zero (0) */
707   ValueFormat	valueFormat2;		/* Defines the types of data in
708 					 * ValueRecord2--for the second glyph
709 					 * in the pair--may be zero (0) */
710   OffsetArrayOf<PairSet>
711 		pairSet;		/* Array of PairSet tables
712 					 * ordered by Coverage Index */
713   public:
714   DEFINE_SIZE_ARRAY (10, pairSet);
715 };
716 
717 struct PairPosFormat2
718 {
collect_glyphsOT::PairPosFormat2719   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
720   {
721     TRACE_COLLECT_GLYPHS (this);
722     /* (this+coverage).add_coverage (c->input); // Don't need this. */
723 
724     unsigned int count1 = class1Count;
725     const ClassDef &klass1 = this+classDef1;
726     for (unsigned int i = 0; i < count1; i++)
727       klass1.add_class (c->input, i);
728 
729     unsigned int count2 = class2Count;
730     const ClassDef &klass2 = this+classDef2;
731     for (unsigned int i = 0; i < count2; i++)
732       klass2.add_class (c->input, i);
733   }
734 
get_coverageOT::PairPosFormat2735   inline const Coverage &get_coverage (void) const
736   {
737     return this+coverage;
738   }
739 
applyOT::PairPosFormat2740   inline bool apply (hb_apply_context_t *c) const
741   {
742     TRACE_APPLY (this);
743     hb_buffer_t *buffer = c->buffer;
744     hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, 1);
745     if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
746 
747     unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
748     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
749 
750     if (!skippy_iter.next ()) return TRACE_RETURN (false);
751 
752     unsigned int len1 = valueFormat1.get_len ();
753     unsigned int len2 = valueFormat2.get_len ();
754     unsigned int record_len = len1 + len2;
755 
756     unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint);
757     unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint);
758     if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return TRACE_RETURN (false);
759 
760     const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
761     valueFormat1.apply_value (c->font, c->direction, this,
762 			      v, buffer->cur_pos());
763     valueFormat2.apply_value (c->font, c->direction, this,
764 			      v + len1, buffer->pos[skippy_iter.idx]);
765 
766     buffer->idx = skippy_iter.idx;
767     if (len2)
768       buffer->idx++;
769 
770     return TRACE_RETURN (true);
771   }
772 
sanitizeOT::PairPosFormat2773   inline bool sanitize (hb_sanitize_context_t *c) {
774     TRACE_SANITIZE (this);
775     if (!(c->check_struct (this)
776        && coverage.sanitize (c, this)
777        && classDef1.sanitize (c, this)
778        && classDef2.sanitize (c, this))) return TRACE_RETURN (false);
779 
780     unsigned int len1 = valueFormat1.get_len ();
781     unsigned int len2 = valueFormat2.get_len ();
782     unsigned int stride = len1 + len2;
783     unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
784     unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
785     return TRACE_RETURN (c->check_array (values, record_size, count) &&
786 			 valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
787 			 valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride));
788   }
789 
790   protected:
791   USHORT	format;			/* Format identifier--format = 2 */
792   OffsetTo<Coverage>
793 		coverage;		/* Offset to Coverage table--from
794 					 * beginning of subtable */
795   ValueFormat	valueFormat1;		/* ValueRecord definition--for the
796 					 * first glyph of the pair--may be zero
797 					 * (0) */
798   ValueFormat	valueFormat2;		/* ValueRecord definition--for the
799 					 * second glyph of the pair--may be
800 					 * zero (0) */
801   OffsetTo<ClassDef>
802 		classDef1;		/* Offset to ClassDef table--from
803 					 * beginning of PairPos subtable--for
804 					 * the first glyph of the pair */
805   OffsetTo<ClassDef>
806 		classDef2;		/* Offset to ClassDef table--from
807 					 * beginning of PairPos subtable--for
808 					 * the second glyph of the pair */
809   USHORT	class1Count;		/* Number of classes in ClassDef1
810 					 * table--includes Class0 */
811   USHORT	class2Count;		/* Number of classes in ClassDef2
812 					 * table--includes Class0 */
813   ValueRecord	values;			/* Matrix of value pairs:
814 					 * class1-major, class2-minor,
815 					 * Each entry has value1 and value2 */
816   public:
817   DEFINE_SIZE_ARRAY (16, values);
818 };
819 
820 struct PairPos
821 {
822   template <typename context_t>
dispatchOT::PairPos823   inline typename context_t::return_t dispatch (context_t *c) const
824   {
825     TRACE_DISPATCH (this);
826     switch (u.format) {
827     case 1: return TRACE_RETURN (c->dispatch (u.format1));
828     case 2: return TRACE_RETURN (c->dispatch (u.format2));
829     default:return TRACE_RETURN (c->default_return_value ());
830     }
831   }
832 
sanitizeOT::PairPos833   inline bool sanitize (hb_sanitize_context_t *c) {
834     TRACE_SANITIZE (this);
835     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
836     switch (u.format) {
837     case 1: return TRACE_RETURN (u.format1.sanitize (c));
838     case 2: return TRACE_RETURN (u.format2.sanitize (c));
839     default:return TRACE_RETURN (true);
840     }
841   }
842 
843   protected:
844   union {
845   USHORT		format;		/* Format identifier */
846   PairPosFormat1	format1;
847   PairPosFormat2	format2;
848   } u;
849 };
850 
851 
852 struct EntryExitRecord
853 {
854   friend struct CursivePosFormat1;
855 
sanitizeOT::EntryExitRecord856   inline bool sanitize (hb_sanitize_context_t *c, void *base) {
857     TRACE_SANITIZE (this);
858     return TRACE_RETURN (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
859   }
860 
861   protected:
862   OffsetTo<Anchor>
863 		entryAnchor;		/* Offset to EntryAnchor table--from
864 					 * beginning of CursivePos
865 					 * subtable--may be NULL */
866   OffsetTo<Anchor>
867 		exitAnchor;		/* Offset to ExitAnchor table--from
868 					 * beginning of CursivePos
869 					 * subtable--may be NULL */
870   public:
871   DEFINE_SIZE_STATIC (4);
872 };
873 
874 struct CursivePosFormat1
875 {
collect_glyphsOT::CursivePosFormat1876   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
877   {
878     TRACE_COLLECT_GLYPHS (this);
879     (this+coverage).add_coverage (c->input);
880   }
881 
get_coverageOT::CursivePosFormat1882   inline const Coverage &get_coverage (void) const
883   {
884     return this+coverage;
885   }
886 
applyOT::CursivePosFormat1887   inline bool apply (hb_apply_context_t *c) const
888   {
889     TRACE_APPLY (this);
890     hb_buffer_t *buffer = c->buffer;
891 
892     /* We don't handle mark glyphs here. */
893     if (unlikely (_hb_glyph_info_is_mark (&buffer->cur()))) return TRACE_RETURN (false);
894 
895     hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, 1);
896     if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
897 
898     const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage  (buffer->cur().codepoint)];
899     if (!this_record.exitAnchor) return TRACE_RETURN (false);
900 
901     if (!skippy_iter.next ()) return TRACE_RETURN (false);
902 
903     const EntryExitRecord &next_record = entryExitRecord[(this+coverage).get_coverage  (buffer->info[skippy_iter.idx].codepoint)];
904     if (!next_record.entryAnchor) return TRACE_RETURN (false);
905 
906     unsigned int i = buffer->idx;
907     unsigned int j = skippy_iter.idx;
908 
909     hb_position_t entry_x, entry_y, exit_x, exit_y;
910     (this+this_record.exitAnchor).get_anchor (c->font, buffer->info[i].codepoint, &exit_x, &exit_y);
911     (this+next_record.entryAnchor).get_anchor (c->font, buffer->info[j].codepoint, &entry_x, &entry_y);
912 
913     hb_glyph_position_t *pos = buffer->pos;
914 
915     hb_position_t d;
916     /* Main-direction adjustment */
917     switch (c->direction) {
918       case HB_DIRECTION_LTR:
919 	pos[i].x_advance  =  exit_x + pos[i].x_offset;
920 
921 	d = entry_x + pos[j].x_offset;
922 	pos[j].x_advance -= d;
923 	pos[j].x_offset  -= d;
924 	break;
925       case HB_DIRECTION_RTL:
926 	d = exit_x + pos[i].x_offset;
927 	pos[i].x_advance -= d;
928 	pos[i].x_offset  -= d;
929 
930 	pos[j].x_advance  =  entry_x + pos[j].x_offset;
931 	break;
932       case HB_DIRECTION_TTB:
933 	pos[i].y_advance  =  exit_y + pos[i].y_offset;
934 
935 	d = entry_y + pos[j].y_offset;
936 	pos[j].y_advance -= d;
937 	pos[j].y_offset  -= d;
938 	break;
939       case HB_DIRECTION_BTT:
940 	d = exit_y + pos[i].y_offset;
941 	pos[i].y_advance -= d;
942 	pos[i].y_offset  -= d;
943 
944 	pos[j].y_advance  =  entry_y;
945 	break;
946       case HB_DIRECTION_INVALID:
947       default:
948 	break;
949     }
950 
951     /* Cross-direction adjustment */
952     if  (c->lookup_props & LookupFlag::RightToLeft) {
953       pos[i].cursive_chain() = j - i;
954       if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
955 	pos[i].y_offset = entry_y - exit_y;
956       else
957 	pos[i].x_offset = entry_x - exit_x;
958     } else {
959       pos[j].cursive_chain() = i - j;
960       if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
961 	pos[j].y_offset = exit_y - entry_y;
962       else
963 	pos[j].x_offset = exit_x - entry_x;
964     }
965 
966     buffer->idx = j;
967     return TRACE_RETURN (true);
968   }
969 
sanitizeOT::CursivePosFormat1970   inline bool sanitize (hb_sanitize_context_t *c) {
971     TRACE_SANITIZE (this);
972     return TRACE_RETURN (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
973   }
974 
975   protected:
976   USHORT	format;			/* Format identifier--format = 1 */
977   OffsetTo<Coverage>
978 		coverage;		/* Offset to Coverage table--from
979 					 * beginning of subtable */
980   ArrayOf<EntryExitRecord>
981 		entryExitRecord;	/* Array of EntryExit records--in
982 					 * Coverage Index order */
983   public:
984   DEFINE_SIZE_ARRAY (6, entryExitRecord);
985 };
986 
987 struct CursivePos
988 {
989   template <typename context_t>
dispatchOT::CursivePos990   inline typename context_t::return_t dispatch (context_t *c) const
991   {
992     TRACE_DISPATCH (this);
993     switch (u.format) {
994     case 1: return TRACE_RETURN (c->dispatch (u.format1));
995     default:return TRACE_RETURN (c->default_return_value ());
996     }
997   }
998 
sanitizeOT::CursivePos999   inline bool sanitize (hb_sanitize_context_t *c) {
1000     TRACE_SANITIZE (this);
1001     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
1002     switch (u.format) {
1003     case 1: return TRACE_RETURN (u.format1.sanitize (c));
1004     default:return TRACE_RETURN (true);
1005     }
1006   }
1007 
1008   protected:
1009   union {
1010   USHORT		format;		/* Format identifier */
1011   CursivePosFormat1	format1;
1012   } u;
1013 };
1014 
1015 
1016 typedef AnchorMatrix BaseArray;		/* base-major--
1017 					 * in order of BaseCoverage Index--,
1018 					 * mark-minor--
1019 					 * ordered by class--zero-based. */
1020 
1021 struct MarkBasePosFormat1
1022 {
collect_glyphsOT::MarkBasePosFormat11023   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1024   {
1025     TRACE_COLLECT_GLYPHS (this);
1026     (this+markCoverage).add_coverage (c->input);
1027     (this+baseCoverage).add_coverage (c->input);
1028   }
1029 
get_coverageOT::MarkBasePosFormat11030   inline const Coverage &get_coverage (void) const
1031   {
1032     return this+markCoverage;
1033   }
1034 
applyOT::MarkBasePosFormat11035   inline bool apply (hb_apply_context_t *c) const
1036   {
1037     TRACE_APPLY (this);
1038     hb_buffer_t *buffer = c->buffer;
1039     unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
1040     if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
1041 
1042     /* now we search backwards for a non-mark glyph */
1043     hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, buffer->idx, 1);
1044     skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
1045     do {
1046       if (!skippy_iter.prev ()) return TRACE_RETURN (false);
1047       /* We only want to attach to the first of a MultipleSubst sequence.  Reject others. */
1048       if (0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx])) break;
1049       skippy_iter.reject ();
1050     } while (1);
1051 
1052     /* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */
1053     if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { /*return TRACE_RETURN (false);*/ }
1054 
1055     unsigned int base_index = (this+baseCoverage).get_coverage  (buffer->info[skippy_iter.idx].codepoint);
1056     if (base_index == NOT_COVERED) return TRACE_RETURN (false);
1057 
1058     return TRACE_RETURN ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx));
1059   }
1060 
sanitizeOT::MarkBasePosFormat11061   inline bool sanitize (hb_sanitize_context_t *c) {
1062     TRACE_SANITIZE (this);
1063     return TRACE_RETURN (c->check_struct (this) && markCoverage.sanitize (c, this) && baseCoverage.sanitize (c, this) &&
1064 			 markArray.sanitize (c, this) && baseArray.sanitize (c, this, (unsigned int) classCount));
1065   }
1066 
1067   protected:
1068   USHORT	format;			/* Format identifier--format = 1 */
1069   OffsetTo<Coverage>
1070 		markCoverage;		/* Offset to MarkCoverage table--from
1071 					 * beginning of MarkBasePos subtable */
1072   OffsetTo<Coverage>
1073 		baseCoverage;		/* Offset to BaseCoverage table--from
1074 					 * beginning of MarkBasePos subtable */
1075   USHORT	classCount;		/* Number of classes defined for marks */
1076   OffsetTo<MarkArray>
1077 		markArray;		/* Offset to MarkArray table--from
1078 					 * beginning of MarkBasePos subtable */
1079   OffsetTo<BaseArray>
1080 		baseArray;		/* Offset to BaseArray table--from
1081 					 * beginning of MarkBasePos subtable */
1082   public:
1083   DEFINE_SIZE_STATIC (12);
1084 };
1085 
1086 struct MarkBasePos
1087 {
1088   template <typename context_t>
dispatchOT::MarkBasePos1089   inline typename context_t::return_t dispatch (context_t *c) const
1090   {
1091     TRACE_DISPATCH (this);
1092     switch (u.format) {
1093     case 1: return TRACE_RETURN (c->dispatch (u.format1));
1094     default:return TRACE_RETURN (c->default_return_value ());
1095     }
1096   }
1097 
sanitizeOT::MarkBasePos1098   inline bool sanitize (hb_sanitize_context_t *c) {
1099     TRACE_SANITIZE (this);
1100     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
1101     switch (u.format) {
1102     case 1: return TRACE_RETURN (u.format1.sanitize (c));
1103     default:return TRACE_RETURN (true);
1104     }
1105   }
1106 
1107   protected:
1108   union {
1109   USHORT		format;		/* Format identifier */
1110   MarkBasePosFormat1	format1;
1111   } u;
1112 };
1113 
1114 
1115 typedef AnchorMatrix LigatureAttach;	/* component-major--
1116 					 * in order of writing direction--,
1117 					 * mark-minor--
1118 					 * ordered by class--zero-based. */
1119 
1120 typedef OffsetListOf<LigatureAttach> LigatureArray;
1121 					/* Array of LigatureAttach
1122 					 * tables ordered by
1123 					 * LigatureCoverage Index */
1124 
1125 struct MarkLigPosFormat1
1126 {
collect_glyphsOT::MarkLigPosFormat11127   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1128   {
1129     TRACE_COLLECT_GLYPHS (this);
1130     (this+markCoverage).add_coverage (c->input);
1131     (this+ligatureCoverage).add_coverage (c->input);
1132   }
1133 
get_coverageOT::MarkLigPosFormat11134   inline const Coverage &get_coverage (void) const
1135   {
1136     return this+markCoverage;
1137   }
1138 
applyOT::MarkLigPosFormat11139   inline bool apply (hb_apply_context_t *c) const
1140   {
1141     TRACE_APPLY (this);
1142     hb_buffer_t *buffer = c->buffer;
1143     unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
1144     if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
1145 
1146     /* now we search backwards for a non-mark glyph */
1147     hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, buffer->idx, 1);
1148     skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
1149     if (!skippy_iter.prev ()) return TRACE_RETURN (false);
1150 
1151     /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */
1152     if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { /*return TRACE_RETURN (false);*/ }
1153 
1154     unsigned int j = skippy_iter.idx;
1155     unsigned int lig_index = (this+ligatureCoverage).get_coverage  (buffer->info[j].codepoint);
1156     if (lig_index == NOT_COVERED) return TRACE_RETURN (false);
1157 
1158     const LigatureArray& lig_array = this+ligatureArray;
1159     const LigatureAttach& lig_attach = lig_array[lig_index];
1160 
1161     /* Find component to attach to */
1162     unsigned int comp_count = lig_attach.rows;
1163     if (unlikely (!comp_count)) return TRACE_RETURN (false);
1164 
1165     /* We must now check whether the ligature ID of the current mark glyph
1166      * is identical to the ligature ID of the found ligature.  If yes, we
1167      * can directly use the component index.  If not, we attach the mark
1168      * glyph to the last component of the ligature. */
1169     unsigned int comp_index;
1170     unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[j]);
1171     unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur());
1172     unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
1173     if (lig_id && lig_id == mark_id && mark_comp > 0)
1174       comp_index = MIN (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1;
1175     else
1176       comp_index = comp_count - 1;
1177 
1178     return TRACE_RETURN ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
1179   }
1180 
sanitizeOT::MarkLigPosFormat11181   inline bool sanitize (hb_sanitize_context_t *c) {
1182     TRACE_SANITIZE (this);
1183     return TRACE_RETURN (c->check_struct (this) && markCoverage.sanitize (c, this) && ligatureCoverage.sanitize (c, this) &&
1184 			 markArray.sanitize (c, this) && ligatureArray.sanitize (c, this, (unsigned int) classCount));
1185   }
1186 
1187   protected:
1188   USHORT	format;			/* Format identifier--format = 1 */
1189   OffsetTo<Coverage>
1190 		markCoverage;		/* Offset to Mark Coverage table--from
1191 					 * beginning of MarkLigPos subtable */
1192   OffsetTo<Coverage>
1193 		ligatureCoverage;	/* Offset to Ligature Coverage
1194 					 * table--from beginning of MarkLigPos
1195 					 * subtable */
1196   USHORT	classCount;		/* Number of defined mark classes */
1197   OffsetTo<MarkArray>
1198 		markArray;		/* Offset to MarkArray table--from
1199 					 * beginning of MarkLigPos subtable */
1200   OffsetTo<LigatureArray>
1201 		ligatureArray;		/* Offset to LigatureArray table--from
1202 					 * beginning of MarkLigPos subtable */
1203   public:
1204   DEFINE_SIZE_STATIC (12);
1205 };
1206 
1207 struct MarkLigPos
1208 {
1209   template <typename context_t>
dispatchOT::MarkLigPos1210   inline typename context_t::return_t dispatch (context_t *c) const
1211   {
1212     TRACE_DISPATCH (this);
1213     switch (u.format) {
1214     case 1: return TRACE_RETURN (c->dispatch (u.format1));
1215     default:return TRACE_RETURN (c->default_return_value ());
1216     }
1217   }
1218 
sanitizeOT::MarkLigPos1219   inline bool sanitize (hb_sanitize_context_t *c) {
1220     TRACE_SANITIZE (this);
1221     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
1222     switch (u.format) {
1223     case 1: return TRACE_RETURN (u.format1.sanitize (c));
1224     default:return TRACE_RETURN (true);
1225     }
1226   }
1227 
1228   protected:
1229   union {
1230   USHORT		format;		/* Format identifier */
1231   MarkLigPosFormat1	format1;
1232   } u;
1233 };
1234 
1235 
1236 typedef AnchorMatrix Mark2Array;	/* mark2-major--
1237 					 * in order of Mark2Coverage Index--,
1238 					 * mark1-minor--
1239 					 * ordered by class--zero-based. */
1240 
1241 struct MarkMarkPosFormat1
1242 {
collect_glyphsOT::MarkMarkPosFormat11243   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1244   {
1245     TRACE_COLLECT_GLYPHS (this);
1246     (this+mark1Coverage).add_coverage (c->input);
1247     (this+mark2Coverage).add_coverage (c->input);
1248   }
1249 
get_coverageOT::MarkMarkPosFormat11250   inline const Coverage &get_coverage (void) const
1251   {
1252     return this+mark1Coverage;
1253   }
1254 
applyOT::MarkMarkPosFormat11255   inline bool apply (hb_apply_context_t *c) const
1256   {
1257     TRACE_APPLY (this);
1258     hb_buffer_t *buffer = c->buffer;
1259     unsigned int mark1_index = (this+mark1Coverage).get_coverage  (buffer->cur().codepoint);
1260     if (likely (mark1_index == NOT_COVERED)) return TRACE_RETURN (false);
1261 
1262     /* now we search backwards for a suitable mark glyph until a non-mark glyph */
1263     hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, buffer->idx, 1);
1264     skippy_iter.set_lookup_props (c->lookup_props & ~LookupFlag::IgnoreFlags);
1265     if (!skippy_iter.prev ()) return TRACE_RETURN (false);
1266 
1267     if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])) { return TRACE_RETURN (false); }
1268 
1269     unsigned int j = skippy_iter.idx;
1270 
1271     unsigned int id1 = _hb_glyph_info_get_lig_id (&buffer->cur());
1272     unsigned int id2 = _hb_glyph_info_get_lig_id (&buffer->info[j]);
1273     unsigned int comp1 = _hb_glyph_info_get_lig_comp (&buffer->cur());
1274     unsigned int comp2 = _hb_glyph_info_get_lig_comp (&buffer->info[j]);
1275 
1276     if (likely (id1 == id2)) {
1277       if (id1 == 0) /* Marks belonging to the same base. */
1278 	goto good;
1279       else if (comp1 == comp2) /* Marks belonging to the same ligature component. */
1280         goto good;
1281     } else {
1282       /* If ligature ids don't match, it may be the case that one of the marks
1283        * itself is a ligature.  In which case match. */
1284       if ((id1 > 0 && !comp1) || (id2 > 0 && !comp2))
1285 	goto good;
1286     }
1287 
1288     /* Didn't match. */
1289     return TRACE_RETURN (false);
1290 
1291     good:
1292     unsigned int mark2_index = (this+mark2Coverage).get_coverage  (buffer->info[j].codepoint);
1293     if (mark2_index == NOT_COVERED) return TRACE_RETURN (false);
1294 
1295     return TRACE_RETURN ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j));
1296   }
1297 
sanitizeOT::MarkMarkPosFormat11298   inline bool sanitize (hb_sanitize_context_t *c) {
1299     TRACE_SANITIZE (this);
1300     return TRACE_RETURN (c->check_struct (this) && mark1Coverage.sanitize (c, this) &&
1301 			 mark2Coverage.sanitize (c, this) && mark1Array.sanitize (c, this)
1302 			 && mark2Array.sanitize (c, this, (unsigned int) classCount));
1303   }
1304 
1305   protected:
1306   USHORT	format;			/* Format identifier--format = 1 */
1307   OffsetTo<Coverage>
1308 		mark1Coverage;		/* Offset to Combining Mark1 Coverage
1309 					 * table--from beginning of MarkMarkPos
1310 					 * subtable */
1311   OffsetTo<Coverage>
1312 		mark2Coverage;		/* Offset to Combining Mark2 Coverage
1313 					 * table--from beginning of MarkMarkPos
1314 					 * subtable */
1315   USHORT	classCount;		/* Number of defined mark classes */
1316   OffsetTo<MarkArray>
1317 		mark1Array;		/* Offset to Mark1Array table--from
1318 					 * beginning of MarkMarkPos subtable */
1319   OffsetTo<Mark2Array>
1320 		mark2Array;		/* Offset to Mark2Array table--from
1321 					 * beginning of MarkMarkPos subtable */
1322   public:
1323   DEFINE_SIZE_STATIC (12);
1324 };
1325 
1326 struct MarkMarkPos
1327 {
1328   template <typename context_t>
dispatchOT::MarkMarkPos1329   inline typename context_t::return_t dispatch (context_t *c) const
1330   {
1331     TRACE_DISPATCH (this);
1332     switch (u.format) {
1333     case 1: return TRACE_RETURN (c->dispatch (u.format1));
1334     default:return TRACE_RETURN (c->default_return_value ());
1335     }
1336   }
1337 
sanitizeOT::MarkMarkPos1338   inline bool sanitize (hb_sanitize_context_t *c) {
1339     TRACE_SANITIZE (this);
1340     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
1341     switch (u.format) {
1342     case 1: return TRACE_RETURN (u.format1.sanitize (c));
1343     default:return TRACE_RETURN (true);
1344     }
1345   }
1346 
1347   protected:
1348   union {
1349   USHORT		format;		/* Format identifier */
1350   MarkMarkPosFormat1	format1;
1351   } u;
1352 };
1353 
1354 
1355 struct ContextPos : Context {};
1356 
1357 struct ChainContextPos : ChainContext {};
1358 
1359 struct ExtensionPos : Extension<ExtensionPos>
1360 {
1361   typedef struct PosLookupSubTable LookupSubTable;
1362 };
1363 
1364 
1365 
1366 /*
1367  * PosLookup
1368  */
1369 
1370 
1371 struct PosLookupSubTable
1372 {
1373   friend struct PosLookup;
1374 
1375   enum Type {
1376     Single		= 1,
1377     Pair		= 2,
1378     Cursive		= 3,
1379     MarkBase		= 4,
1380     MarkLig		= 5,
1381     MarkMark		= 6,
1382     Context		= 7,
1383     ChainContext	= 8,
1384     Extension		= 9
1385   };
1386 
1387   template <typename context_t>
dispatchOT::PosLookupSubTable1388   inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
1389   {
1390     TRACE_DISPATCH (this);
1391     switch (lookup_type) {
1392     case Single:		return TRACE_RETURN (u.single.dispatch (c));
1393     case Pair:			return TRACE_RETURN (u.pair.dispatch (c));
1394     case Cursive:		return TRACE_RETURN (u.cursive.dispatch (c));
1395     case MarkBase:		return TRACE_RETURN (u.markBase.dispatch (c));
1396     case MarkLig:		return TRACE_RETURN (u.markLig.dispatch (c));
1397     case MarkMark:		return TRACE_RETURN (u.markMark.dispatch (c));
1398     case Context:		return TRACE_RETURN (u.context.dispatch (c));
1399     case ChainContext:		return TRACE_RETURN (u.chainContext.dispatch (c));
1400     case Extension:		return TRACE_RETURN (u.extension.dispatch (c));
1401     default:			return TRACE_RETURN (c->default_return_value ());
1402     }
1403   }
1404 
sanitizeOT::PosLookupSubTable1405   inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
1406     TRACE_SANITIZE (this);
1407     if (!u.header.sub_format.sanitize (c))
1408       return TRACE_RETURN (false);
1409     switch (lookup_type) {
1410     case Single:		return TRACE_RETURN (u.single.sanitize (c));
1411     case Pair:			return TRACE_RETURN (u.pair.sanitize (c));
1412     case Cursive:		return TRACE_RETURN (u.cursive.sanitize (c));
1413     case MarkBase:		return TRACE_RETURN (u.markBase.sanitize (c));
1414     case MarkLig:		return TRACE_RETURN (u.markLig.sanitize (c));
1415     case MarkMark:		return TRACE_RETURN (u.markMark.sanitize (c));
1416     case Context:		return TRACE_RETURN (u.context.sanitize (c));
1417     case ChainContext:		return TRACE_RETURN (u.chainContext.sanitize (c));
1418     case Extension:		return TRACE_RETURN (u.extension.sanitize (c));
1419     default:			return TRACE_RETURN (true);
1420     }
1421   }
1422 
1423   protected:
1424   union {
1425   struct {
1426     USHORT		sub_format;
1427   } header;
1428   SinglePos		single;
1429   PairPos		pair;
1430   CursivePos		cursive;
1431   MarkBasePos		markBase;
1432   MarkLigPos		markLig;
1433   MarkMarkPos		markMark;
1434   ContextPos		context;
1435   ChainContextPos	chainContext;
1436   ExtensionPos		extension;
1437   } u;
1438   public:
1439   DEFINE_SIZE_UNION (2, header.sub_format);
1440 };
1441 
1442 
1443 struct PosLookup : Lookup
1444 {
get_subtableOT::PosLookup1445   inline const PosLookupSubTable& get_subtable (unsigned int i) const
1446   { return this+CastR<OffsetArrayOf<PosLookupSubTable> > (subTable)[i]; }
1447 
is_reverseOT::PosLookup1448   inline bool is_reverse (void) const
1449   {
1450     return false;
1451   }
1452 
collect_glyphsOT::PosLookup1453   inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
1454   {
1455     TRACE_COLLECT_GLYPHS (this);
1456     c->set_recurse_func (NULL);
1457     return TRACE_RETURN (dispatch (c));
1458   }
1459 
1460   template <typename set_t>
add_coverageOT::PosLookup1461   inline void add_coverage (set_t *glyphs) const
1462   {
1463     hb_get_coverage_context_t c;
1464     const Coverage *last = NULL;
1465     unsigned int count = get_subtable_count ();
1466     for (unsigned int i = 0; i < count; i++) {
1467       const Coverage *coverage = &get_subtable (i).dispatch (&c, get_type ());
1468       if (coverage != last) {
1469         coverage->add_coverage (glyphs);
1470         last = coverage;
1471       }
1472     }
1473   }
1474 
apply_onceOT::PosLookup1475   inline bool apply_once (hb_apply_context_t *c) const
1476   {
1477     TRACE_APPLY (this);
1478     if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props))
1479       return TRACE_RETURN (false);
1480     return TRACE_RETURN (dispatch (c));
1481   }
1482 
1483   static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
1484 
1485   template <typename context_t>
1486   static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
1487 
1488   template <typename context_t>
dispatchOT::PosLookup1489   inline typename context_t::return_t dispatch (context_t *c) const
1490   {
1491     TRACE_DISPATCH (this);
1492     unsigned int lookup_type = get_type ();
1493     unsigned int count = get_subtable_count ();
1494     for (unsigned int i = 0; i < count; i++) {
1495       typename context_t::return_t r = get_subtable (i).dispatch (c, lookup_type);
1496       if (c->stop_sublookup_iteration (r))
1497         return TRACE_RETURN (r);
1498     }
1499     return TRACE_RETURN (c->default_return_value ());
1500   }
1501 
sanitizeOT::PosLookup1502   inline bool sanitize (hb_sanitize_context_t *c) {
1503     TRACE_SANITIZE (this);
1504     if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
1505     OffsetArrayOf<PosLookupSubTable> &list = CastR<OffsetArrayOf<PosLookupSubTable> > (subTable);
1506     return TRACE_RETURN (list.sanitize (c, this, get_type ()));
1507   }
1508 };
1509 
1510 typedef OffsetListOf<PosLookup> PosLookupList;
1511 
1512 /*
1513  * GPOS -- The Glyph Positioning Table
1514  */
1515 
1516 struct GPOS : GSUBGPOS
1517 {
1518   static const hb_tag_t tableTag	= HB_OT_TAG_GPOS;
1519 
get_lookupOT::GPOS1520   inline const PosLookup& get_lookup (unsigned int i) const
1521   { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
1522 
1523   static inline void position_start (hb_font_t *font, hb_buffer_t *buffer);
1524   static inline void position_finish (hb_font_t *font, hb_buffer_t *buffer);
1525 
sanitizeOT::GPOS1526   inline bool sanitize (hb_sanitize_context_t *c) {
1527     TRACE_SANITIZE (this);
1528     if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
1529     OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
1530     return TRACE_RETURN (list.sanitize (c, this));
1531   }
1532   public:
1533   DEFINE_SIZE_STATIC (10);
1534 };
1535 
1536 
1537 static void
fix_cursive_minor_offset(hb_glyph_position_t * pos,unsigned int i,hb_direction_t direction)1538 fix_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
1539 {
1540   unsigned int j = pos[i].cursive_chain();
1541   if (likely (!j))
1542     return;
1543 
1544   j += i;
1545 
1546   pos[i].cursive_chain() = 0;
1547 
1548   fix_cursive_minor_offset (pos, j, direction);
1549 
1550   if (HB_DIRECTION_IS_HORIZONTAL (direction))
1551     pos[i].y_offset += pos[j].y_offset;
1552   else
1553     pos[i].x_offset += pos[j].x_offset;
1554 }
1555 
1556 static void
fix_mark_attachment(hb_glyph_position_t * pos,unsigned int i,hb_direction_t direction)1557 fix_mark_attachment (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
1558 {
1559   if (likely (!(pos[i].attach_lookback())))
1560     return;
1561 
1562   unsigned int j = i - pos[i].attach_lookback();
1563 
1564   pos[i].x_offset += pos[j].x_offset;
1565   pos[i].y_offset += pos[j].y_offset;
1566 
1567   if (HB_DIRECTION_IS_FORWARD (direction))
1568     for (unsigned int k = j; k < i; k++) {
1569       pos[i].x_offset -= pos[k].x_advance;
1570       pos[i].y_offset -= pos[k].y_advance;
1571     }
1572   else
1573     for (unsigned int k = j + 1; k < i + 1; k++) {
1574       pos[i].x_offset += pos[k].x_advance;
1575       pos[i].y_offset += pos[k].y_advance;
1576     }
1577 }
1578 
1579 void
position_start(hb_font_t * font HB_UNUSED,hb_buffer_t * buffer)1580 GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
1581 {
1582   buffer->clear_positions ();
1583 
1584   unsigned int count = buffer->len;
1585   for (unsigned int i = 0; i < count; i++)
1586     buffer->pos[i].attach_lookback() = buffer->pos[i].cursive_chain() = 0;
1587 }
1588 
1589 void
position_finish(hb_font_t * font HB_UNUSED,hb_buffer_t * buffer)1590 GPOS::position_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
1591 {
1592   unsigned int len;
1593   hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
1594   hb_direction_t direction = buffer->props.direction;
1595 
1596   /* Handle cursive connections */
1597   for (unsigned int i = 0; i < len; i++)
1598     fix_cursive_minor_offset (pos, i, direction);
1599 
1600   /* Handle attachments */
1601   for (unsigned int i = 0; i < len; i++)
1602     fix_mark_attachment (pos, i, direction);
1603 
1604   _hb_buffer_deallocate_gsubgpos_vars (buffer);
1605 }
1606 
1607 
1608 /* Out-of-class implementation for methods recursing */
1609 
1610 template <typename context_t>
dispatch_recurse_func(context_t * c,unsigned int lookup_index)1611 /*static*/ inline typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
1612 {
1613   const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
1614   const PosLookup &l = gpos.get_lookup (lookup_index);
1615   return l.dispatch (c);
1616 }
1617 
apply_recurse_func(hb_apply_context_t * c,unsigned int lookup_index)1618 /*static*/ inline bool PosLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
1619 {
1620   const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
1621   const PosLookup &l = gpos.get_lookup (lookup_index);
1622   unsigned int saved_lookup_props = c->lookup_props;
1623   c->set_lookup (l);
1624   bool ret = l.apply_once (c);
1625   c->lookup_props = saved_lookup_props;
1626   return ret;
1627 }
1628 
1629 
1630 #undef attach_lookback
1631 #undef cursive_chain
1632 
1633 
1634 } /* namespace OT */
1635 
1636 
1637 #endif /* HB_OT_LAYOUT_GPOS_TABLE_HH */
1638