• 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.hh"
33 
34 
35 namespace OT {
36 
37 
38 /* buffer **position** var allocations */
39 #define attach_chain() var.i16[0] /* glyph to which this attaches to, relative to current glyphs; negative for going back, positive for forward. */
40 #define attach_type() var.u8[2] /* attachment type */
41 /* Note! if attach_chain() is zero, the value of attach_type() is irrelevant. */
42 
43 enum attach_type_t {
44   ATTACH_TYPE_NONE	= 0X00,
45 
46   /* Each attachment should be either a mark or a cursive; can't be both. */
47   ATTACH_TYPE_MARK	= 0X01,
48   ATTACH_TYPE_CURSIVE	= 0X02,
49 };
50 
51 
52 /* Shared Tables: ValueRecord, Anchor Table, and MarkArray */
53 
54 typedef HBUINT16 Value;
55 
56 typedef UnsizedArrayOf<Value> ValueRecord;
57 
58 struct ValueFormat : HBUINT16
59 {
60   enum Flags {
61     xPlacement	= 0x0001u,	/* Includes horizontal adjustment for placement */
62     yPlacement	= 0x0002u,	/* Includes vertical adjustment for placement */
63     xAdvance	= 0x0004u,	/* Includes horizontal adjustment for advance */
64     yAdvance	= 0x0008u,	/* Includes vertical adjustment for advance */
65     xPlaDevice	= 0x0010u,	/* Includes horizontal Device table for placement */
66     yPlaDevice	= 0x0020u,	/* Includes vertical Device table for placement */
67     xAdvDevice	= 0x0040u,	/* Includes horizontal Device table for advance */
68     yAdvDevice	= 0x0080u,	/* Includes vertical Device table for advance */
69     ignored	= 0x0F00u,	/* Was used in TrueType Open for MM fonts */
70     reserved	= 0xF000u,	/* For future use */
71 
72     devices	= 0x00F0u	/* Mask for having any Device table */
73   };
74 
75 /* All fields are options.  Only those available advance the value pointer. */
76 #if 0
77   HBINT16		xPlacement;		/* Horizontal adjustment for
78 					 * placement--in design units */
79   HBINT16		yPlacement;		/* Vertical adjustment for
80 					 * placement--in design units */
81   HBINT16		xAdvance;		/* Horizontal adjustment for
82 					 * advance--in design units (only used
83 					 * for horizontal writing) */
84   HBINT16		yAdvance;		/* Vertical adjustment for advance--in
85 					 * design units (only used for vertical
86 					 * writing) */
87   Offset	xPlaDevice;		/* Offset to Device table for
88 					 * horizontal placement--measured from
89 					 * beginning of PosTable (may be NULL) */
90   Offset	yPlaDevice;		/* Offset to Device table for vertical
91 					 * placement--measured from beginning
92 					 * of PosTable (may be NULL) */
93   Offset	xAdvDevice;		/* Offset to Device table for
94 					 * horizontal advance--measured from
95 					 * beginning of PosTable (may be NULL) */
96   Offset	yAdvDevice;		/* Offset to Device table for vertical
97 					 * advance--measured from beginning of
98 					 * PosTable (may be NULL) */
99 #endif
100 
get_lenOT::ValueFormat101   unsigned int get_len () const  { return hb_popcount ((unsigned int) *this); }
get_sizeOT::ValueFormat102   unsigned int get_size () const { return get_len () * Value::static_size; }
103 
apply_valueOT::ValueFormat104   bool apply_value (hb_ot_apply_context_t   *c,
105 		    const void           *base,
106 		    const Value          *values,
107 		    hb_glyph_position_t  &glyph_pos) const
108   {
109     bool ret = false;
110     unsigned int format = *this;
111     if (!format) return ret;
112 
113     hb_font_t *font = c->font;
114     bool horizontal = HB_DIRECTION_IS_HORIZONTAL (c->direction);
115 
116     if (format & xPlacement) glyph_pos.x_offset  += font->em_scale_x (get_short (values++, &ret));
117     if (format & yPlacement) glyph_pos.y_offset  += font->em_scale_y (get_short (values++, &ret));
118     if (format & xAdvance) {
119       if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values, &ret));
120       values++;
121     }
122     /* y_advance values grow downward but font-space grows upward, hence negation */
123     if (format & yAdvance) {
124       if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values, &ret));
125       values++;
126     }
127 
128     if (!has_device ()) return ret;
129 
130     bool use_x_device = font->x_ppem || font->num_coords;
131     bool use_y_device = font->y_ppem || font->num_coords;
132 
133     if (!use_x_device && !use_y_device) return ret;
134 
135     const VariationStore &store = c->var_store;
136 
137     /* pixel -> fractional pixel */
138     if (format & xPlaDevice) {
139       if (use_x_device) glyph_pos.x_offset  += (base + get_device (values, &ret)).get_x_delta (font, store);
140       values++;
141     }
142     if (format & yPlaDevice) {
143       if (use_y_device) glyph_pos.y_offset  += (base + get_device (values, &ret)).get_y_delta (font, store);
144       values++;
145     }
146     if (format & xAdvDevice) {
147       if (horizontal && use_x_device) glyph_pos.x_advance += (base + get_device (values, &ret)).get_x_delta (font, store);
148       values++;
149     }
150     if (format & yAdvDevice) {
151       /* y_advance values grow downward but font-space grows upward, hence negation */
152       if (!horizontal && use_y_device) glyph_pos.y_advance -= (base + get_device (values, &ret)).get_y_delta (font, store);
153       values++;
154     }
155     return ret;
156   }
157 
158   private:
sanitize_value_devicesOT::ValueFormat159   bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const
160   {
161     unsigned int format = *this;
162 
163     if (format & xPlacement) values++;
164     if (format & yPlacement) values++;
165     if (format & xAdvance)   values++;
166     if (format & yAdvance)   values++;
167 
168     if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
169     if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
170     if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
171     if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
172 
173     return true;
174   }
175 
get_deviceOT::ValueFormat176   static OffsetTo<Device>& get_device (Value* value)
177   { return *CastP<OffsetTo<Device> > (value); }
get_deviceOT::ValueFormat178   static const OffsetTo<Device>& get_device (const Value* value, bool *worked=nullptr)
179   {
180     if (worked) *worked |= *value;
181     return *CastP<OffsetTo<Device> > (value);
182   }
183 
get_shortOT::ValueFormat184   static const HBINT16& get_short (const Value* value, bool *worked=nullptr)
185   {
186     if (worked) *worked |= *value;
187     return *CastP<HBINT16> (value);
188   }
189 
190   public:
191 
has_deviceOT::ValueFormat192   bool has_device () const
193   {
194     unsigned int format = *this;
195     return (format & devices) != 0;
196   }
197 
sanitize_valueOT::ValueFormat198   bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const
199   {
200     TRACE_SANITIZE (this);
201     return_trace (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values)));
202   }
203 
sanitize_valuesOT::ValueFormat204   bool sanitize_values (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count) const
205   {
206     TRACE_SANITIZE (this);
207     unsigned int len = get_len ();
208 
209     if (!c->check_range (values, count, get_size ())) return_trace (false);
210 
211     if (!has_device ()) return_trace (true);
212 
213     for (unsigned int i = 0; i < count; i++) {
214       if (!sanitize_value_devices (c, base, values))
215 	return_trace (false);
216       values += len;
217     }
218 
219     return_trace (true);
220   }
221 
222   /* Just sanitize referenced Device tables.  Doesn't check the values themselves. */
sanitize_values_stride_unsafeOT::ValueFormat223   bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count, unsigned int stride) const
224   {
225     TRACE_SANITIZE (this);
226 
227     if (!has_device ()) return_trace (true);
228 
229     for (unsigned int i = 0; i < count; i++) {
230       if (!sanitize_value_devices (c, base, values))
231 	return_trace (false);
232       values += stride;
233     }
234 
235     return_trace (true);
236   }
237 };
238 
239 
240 struct AnchorFormat1
241 {
get_anchorOT::AnchorFormat1242   void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED,
243 		   float *x, float *y) const
244   {
245     hb_font_t *font = c->font;
246     *x = font->em_fscale_x (xCoordinate);
247     *y = font->em_fscale_y (yCoordinate);
248   }
249 
sanitizeOT::AnchorFormat1250   bool sanitize (hb_sanitize_context_t *c) const
251   {
252     TRACE_SANITIZE (this);
253     return_trace (c->check_struct (this));
254   }
255 
256   protected:
257   HBUINT16	format;			/* Format identifier--format = 1 */
258   FWORD		xCoordinate;		/* Horizontal value--in design units */
259   FWORD		yCoordinate;		/* Vertical value--in design units */
260   public:
261   DEFINE_SIZE_STATIC (6);
262 };
263 
264 struct AnchorFormat2
265 {
get_anchorOT::AnchorFormat2266   void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id,
267 		   float *x, float *y) const
268   {
269     hb_font_t *font = c->font;
270     unsigned int x_ppem = font->x_ppem;
271     unsigned int y_ppem = font->y_ppem;
272     hb_position_t cx = 0, cy = 0;
273     bool ret;
274 
275     ret = (x_ppem || y_ppem) &&
276 	  font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
277     *x = ret && x_ppem ? cx : font->em_fscale_x (xCoordinate);
278     *y = ret && y_ppem ? cy : font->em_fscale_y (yCoordinate);
279   }
280 
sanitizeOT::AnchorFormat2281   bool sanitize (hb_sanitize_context_t *c) const
282   {
283     TRACE_SANITIZE (this);
284     return_trace (c->check_struct (this));
285   }
286 
287   protected:
288   HBUINT16	format;			/* Format identifier--format = 2 */
289   FWORD		xCoordinate;		/* Horizontal value--in design units */
290   FWORD		yCoordinate;		/* Vertical value--in design units */
291   HBUINT16	anchorPoint;		/* Index to glyph contour point */
292   public:
293   DEFINE_SIZE_STATIC (8);
294 };
295 
296 struct AnchorFormat3
297 {
get_anchorOT::AnchorFormat3298   void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED,
299 		   float *x, float *y) const
300   {
301     hb_font_t *font = c->font;
302     *x = font->em_fscale_x (xCoordinate);
303     *y = font->em_fscale_y (yCoordinate);
304 
305     if (font->x_ppem || font->num_coords)
306       *x += (this+xDeviceTable).get_x_delta (font, c->var_store);
307     if (font->y_ppem || font->num_coords)
308       *y += (this+yDeviceTable).get_y_delta (font, c->var_store);
309   }
310 
sanitizeOT::AnchorFormat3311   bool sanitize (hb_sanitize_context_t *c) const
312   {
313     TRACE_SANITIZE (this);
314     return_trace (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
315   }
316 
317   protected:
318   HBUINT16	format;			/* Format identifier--format = 3 */
319   FWORD		xCoordinate;		/* Horizontal value--in design units */
320   FWORD		yCoordinate;		/* Vertical value--in design units */
321   OffsetTo<Device>
322 		xDeviceTable;		/* Offset to Device table for X
323 					 * coordinate-- from beginning of
324 					 * Anchor table (may be NULL) */
325   OffsetTo<Device>
326 		yDeviceTable;		/* Offset to Device table for Y
327 					 * coordinate-- from beginning of
328 					 * Anchor table (may be NULL) */
329   public:
330   DEFINE_SIZE_STATIC (10);
331 };
332 
333 struct Anchor
334 {
get_anchorOT::Anchor335   void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id,
336 		   float *x, float *y) const
337   {
338     *x = *y = 0;
339     switch (u.format) {
340     case 1: u.format1.get_anchor (c, glyph_id, x, y); return;
341     case 2: u.format2.get_anchor (c, glyph_id, x, y); return;
342     case 3: u.format3.get_anchor (c, glyph_id, x, y); return;
343     default:					      return;
344     }
345   }
346 
sanitizeOT::Anchor347   bool sanitize (hb_sanitize_context_t *c) const
348   {
349     TRACE_SANITIZE (this);
350     if (!u.format.sanitize (c)) return_trace (false);
351     switch (u.format) {
352     case 1: return_trace (u.format1.sanitize (c));
353     case 2: return_trace (u.format2.sanitize (c));
354     case 3: return_trace (u.format3.sanitize (c));
355     default:return_trace (true);
356     }
357   }
358 
359   protected:
360   union {
361   HBUINT16		format;		/* Format identifier */
362   AnchorFormat1		format1;
363   AnchorFormat2		format2;
364   AnchorFormat3		format3;
365   } u;
366   public:
367   DEFINE_SIZE_UNION (2, format);
368 };
369 
370 
371 struct AnchorMatrix
372 {
get_anchorOT::AnchorMatrix373   const Anchor& get_anchor (unsigned int row, unsigned int col,
374 			    unsigned int cols, bool *found) const
375   {
376     *found = false;
377     if (unlikely (row >= rows || col >= cols)) return Null(Anchor);
378     *found = !matrixZ[row * cols + col].is_null ();
379     return this+matrixZ[row * cols + col];
380   }
381 
sanitizeOT::AnchorMatrix382   bool sanitize (hb_sanitize_context_t *c, unsigned int cols) const
383   {
384     TRACE_SANITIZE (this);
385     if (!c->check_struct (this)) return_trace (false);
386     if (unlikely (hb_unsigned_mul_overflows (rows, cols))) return_trace (false);
387     unsigned int count = rows * cols;
388     if (!c->check_array (matrixZ.arrayZ, count)) return_trace (false);
389     for (unsigned int i = 0; i < count; i++)
390       if (!matrixZ[i].sanitize (c, this)) return_trace (false);
391     return_trace (true);
392   }
393 
394   HBUINT16	rows;			/* Number of rows */
395   protected:
396   UnsizedArrayOf<OffsetTo<Anchor> >
397 		matrixZ;		/* Matrix of offsets to Anchor tables--
398 					 * from beginning of AnchorMatrix table */
399   public:
400   DEFINE_SIZE_ARRAY (2, matrixZ);
401 };
402 
403 
404 struct MarkRecord
405 {
406   friend struct MarkArray;
407 
sanitizeOT::MarkRecord408   bool sanitize (hb_sanitize_context_t *c, const void *base) const
409   {
410     TRACE_SANITIZE (this);
411     return_trace (c->check_struct (this) && markAnchor.sanitize (c, base));
412   }
413 
414   protected:
415   HBUINT16	klass;			/* Class defined for this mark */
416   OffsetTo<Anchor>
417 		markAnchor;		/* Offset to Anchor table--from
418 					 * beginning of MarkArray table */
419   public:
420   DEFINE_SIZE_STATIC (4);
421 };
422 
423 struct MarkArray : ArrayOf<MarkRecord>	/* Array of MarkRecords--in Coverage order */
424 {
applyOT::MarkArray425   bool apply (hb_ot_apply_context_t *c,
426 	      unsigned int mark_index, unsigned int glyph_index,
427 	      const AnchorMatrix &anchors, unsigned int class_count,
428 	      unsigned int glyph_pos) const
429   {
430     TRACE_APPLY (this);
431     hb_buffer_t *buffer = c->buffer;
432     const MarkRecord &record = ArrayOf<MarkRecord>::operator[](mark_index);
433     unsigned int mark_class = record.klass;
434 
435     const Anchor& mark_anchor = this + record.markAnchor;
436     bool found;
437     const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count, &found);
438     /* If this subtable doesn't have an anchor for this base and this class,
439      * return false such that the subsequent subtables have a chance at it. */
440     if (unlikely (!found)) return_trace (false);
441 
442     float mark_x, mark_y, base_x, base_y;
443 
444     buffer->unsafe_to_break (glyph_pos, buffer->idx);
445     mark_anchor.get_anchor (c, buffer->cur().codepoint, &mark_x, &mark_y);
446     glyph_anchor.get_anchor (c, buffer->info[glyph_pos].codepoint, &base_x, &base_y);
447 
448     hb_glyph_position_t &o = buffer->cur_pos();
449     o.x_offset = round (base_x - mark_x);
450     o.y_offset = round (base_y - mark_y);
451     o.attach_type() = ATTACH_TYPE_MARK;
452     o.attach_chain() = (int) glyph_pos - (int) buffer->idx;
453     buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
454 
455     buffer->idx++;
456     return_trace (true);
457   }
458 
sanitizeOT::MarkArray459   bool sanitize (hb_sanitize_context_t *c) const
460   {
461     TRACE_SANITIZE (this);
462     return_trace (ArrayOf<MarkRecord>::sanitize (c, this));
463   }
464 };
465 
466 
467 /* Lookups */
468 
469 struct SinglePosFormat1
470 {
intersectsOT::SinglePosFormat1471   bool intersects (const hb_set_t *glyphs) const
472   { return (this+coverage).intersects (glyphs); }
473 
collect_glyphsOT::SinglePosFormat1474   void collect_glyphs (hb_collect_glyphs_context_t *c) const
475   {
476     TRACE_COLLECT_GLYPHS (this);
477     if (unlikely (!(this+coverage).add_coverage (c->input))) return;
478   }
479 
get_coverageOT::SinglePosFormat1480   const Coverage &get_coverage () const { return this+coverage; }
481 
applyOT::SinglePosFormat1482   bool apply (hb_ot_apply_context_t *c) const
483   {
484     TRACE_APPLY (this);
485     hb_buffer_t *buffer = c->buffer;
486     unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
487     if (likely (index == NOT_COVERED)) return_trace (false);
488 
489     valueFormat.apply_value (c, this, values, buffer->cur_pos());
490 
491     buffer->idx++;
492     return_trace (true);
493   }
494 
subsetOT::SinglePosFormat1495   bool subset (hb_subset_context_t *c) const
496   {
497     TRACE_SUBSET (this);
498     // TODO(subset)
499     return_trace (false);
500   }
501 
sanitizeOT::SinglePosFormat1502   bool sanitize (hb_sanitize_context_t *c) const
503   {
504     TRACE_SANITIZE (this);
505     return_trace (c->check_struct (this) &&
506 		  coverage.sanitize (c, this) &&
507 		  valueFormat.sanitize_value (c, this, values));
508   }
509 
510   protected:
511   HBUINT16	format;			/* Format identifier--format = 1 */
512   OffsetTo<Coverage>
513 		coverage;		/* Offset to Coverage table--from
514 					 * beginning of subtable */
515   ValueFormat	valueFormat;		/* Defines the types of data in the
516 					 * ValueRecord */
517   ValueRecord	values;			/* Defines positioning
518 					 * value(s)--applied to all glyphs in
519 					 * the Coverage table */
520   public:
521   DEFINE_SIZE_ARRAY (6, values);
522 };
523 
524 struct SinglePosFormat2
525 {
intersectsOT::SinglePosFormat2526   bool intersects (const hb_set_t *glyphs) const
527   { return (this+coverage).intersects (glyphs); }
528 
collect_glyphsOT::SinglePosFormat2529   void collect_glyphs (hb_collect_glyphs_context_t *c) const
530   {
531     TRACE_COLLECT_GLYPHS (this);
532     if (unlikely (!(this+coverage).add_coverage (c->input))) return;
533   }
534 
get_coverageOT::SinglePosFormat2535   const Coverage &get_coverage () const { return this+coverage; }
536 
applyOT::SinglePosFormat2537   bool apply (hb_ot_apply_context_t *c) const
538   {
539     TRACE_APPLY (this);
540     hb_buffer_t *buffer = c->buffer;
541     unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
542     if (likely (index == NOT_COVERED)) return_trace (false);
543 
544     if (likely (index >= valueCount)) return_trace (false);
545 
546     valueFormat.apply_value (c, this,
547 			     &values[index * valueFormat.get_len ()],
548 			     buffer->cur_pos());
549 
550     buffer->idx++;
551     return_trace (true);
552   }
553 
subsetOT::SinglePosFormat2554   bool subset (hb_subset_context_t *c) const
555   {
556     TRACE_SUBSET (this);
557     // TODO(subset)
558     return_trace (false);
559   }
560 
sanitizeOT::SinglePosFormat2561   bool sanitize (hb_sanitize_context_t *c) const
562   {
563     TRACE_SANITIZE (this);
564     return_trace (c->check_struct (this) &&
565 		  coverage.sanitize (c, this) &&
566 		  valueFormat.sanitize_values (c, this, values, valueCount));
567   }
568 
569   protected:
570   HBUINT16	format;			/* Format identifier--format = 2 */
571   OffsetTo<Coverage>
572 		coverage;		/* Offset to Coverage table--from
573 					 * beginning of subtable */
574   ValueFormat	valueFormat;		/* Defines the types of data in the
575 					 * ValueRecord */
576   HBUINT16	valueCount;		/* Number of ValueRecords */
577   ValueRecord	values;			/* Array of ValueRecords--positioning
578 					 * values applied to glyphs */
579   public:
580   DEFINE_SIZE_ARRAY (8, values);
581 };
582 
583 struct SinglePos
584 {
585   template <typename context_t>
dispatchOT::SinglePos586   typename context_t::return_t dispatch (context_t *c) const
587   {
588     TRACE_DISPATCH (this, u.format);
589     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
590     switch (u.format) {
591     case 1: return_trace (c->dispatch (u.format1));
592     case 2: return_trace (c->dispatch (u.format2));
593     default:return_trace (c->default_return_value ());
594     }
595   }
596 
597   protected:
598   union {
599   HBUINT16		format;		/* Format identifier */
600   SinglePosFormat1	format1;
601   SinglePosFormat2	format2;
602   } u;
603 };
604 
605 
606 struct PairValueRecord
607 {
608   friend struct PairSet;
609 
610   protected:
611   GlyphID	secondGlyph;		/* GlyphID of second glyph in the
612 					 * pair--first glyph is listed in the
613 					 * Coverage table */
614   ValueRecord	values;			/* Positioning data for the first glyph
615 					 * followed by for second glyph */
616   public:
617   DEFINE_SIZE_ARRAY (2, values);
618 };
619 
620 struct PairSet
621 {
622   friend struct PairPosFormat1;
623 
intersectsOT::PairSet624   bool intersects (const hb_set_t *glyphs,
625 			  const ValueFormat *valueFormats) const
626   {
627     unsigned int len1 = valueFormats[0].get_len ();
628     unsigned int len2 = valueFormats[1].get_len ();
629     unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
630 
631     const PairValueRecord *record = &firstPairValueRecord;
632     unsigned int count = len;
633     for (unsigned int i = 0; i < count; i++)
634     {
635       if (glyphs->has (record->secondGlyph))
636 	return true;
637       record = &StructAtOffset<const PairValueRecord> (record, record_size);
638     }
639     return false;
640   }
641 
collect_glyphsOT::PairSet642   void collect_glyphs (hb_collect_glyphs_context_t *c,
643 			      const ValueFormat *valueFormats) const
644   {
645     TRACE_COLLECT_GLYPHS (this);
646     unsigned int len1 = valueFormats[0].get_len ();
647     unsigned int len2 = valueFormats[1].get_len ();
648     unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
649 
650     const PairValueRecord *record = &firstPairValueRecord;
651     c->input->add_array (&record->secondGlyph, len, record_size);
652   }
653 
applyOT::PairSet654   bool apply (hb_ot_apply_context_t *c,
655 		     const ValueFormat *valueFormats,
656 		     unsigned int pos) const
657   {
658     TRACE_APPLY (this);
659     hb_buffer_t *buffer = c->buffer;
660     unsigned int len1 = valueFormats[0].get_len ();
661     unsigned int len2 = valueFormats[1].get_len ();
662     unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
663 
664     unsigned int count = len;
665 
666     /* Hand-coded bsearch. */
667     if (unlikely (!count))
668       return_trace (false);
669     hb_codepoint_t x = buffer->info[pos].codepoint;
670     int min = 0, max = (int) count - 1;
671     while (min <= max)
672     {
673       int mid = ((unsigned int) min + (unsigned int) max) / 2;
674       const PairValueRecord *record = &StructAtOffset<PairValueRecord> (&firstPairValueRecord, record_size * mid);
675       hb_codepoint_t mid_x = record->secondGlyph;
676       if (x < mid_x)
677 	max = mid - 1;
678       else if (x > mid_x)
679 	min = mid + 1;
680       else
681       {
682 	/* Note the intentional use of "|" instead of short-circuit "||". */
683 	if (valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos()) |
684 	    valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]))
685 	  buffer->unsafe_to_break (buffer->idx, pos + 1);
686 	if (len2)
687 	  pos++;
688 	buffer->idx = pos;
689 	return_trace (true);
690       }
691     }
692 
693     return_trace (false);
694   }
695 
696   struct sanitize_closure_t
697   {
698     const void *base;
699     const ValueFormat *valueFormats;
700     unsigned int len1; /* valueFormats[0].get_len() */
701     unsigned int stride; /* 1 + len1 + len2 */
702   };
703 
sanitizeOT::PairSet704   bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const
705   {
706     TRACE_SANITIZE (this);
707     if (!(c->check_struct (this)
708        && c->check_range (&firstPairValueRecord,
709 			  len,
710 			  HBUINT16::static_size,
711 			  closure->stride))) return_trace (false);
712 
713     unsigned int count = len;
714     const PairValueRecord *record = &firstPairValueRecord;
715     return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride) &&
716 		  closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride));
717   }
718 
719   protected:
720   HBUINT16		len;	/* Number of PairValueRecords */
721   PairValueRecord	firstPairValueRecord;
722 				/* Array of PairValueRecords--ordered
723 				 * by GlyphID of the second glyph */
724   public:
725   DEFINE_SIZE_MIN (2);
726 };
727 
728 struct PairPosFormat1
729 {
intersectsOT::PairPosFormat1730   bool intersects (const hb_set_t *glyphs) const
731   {
732     unsigned int count = pairSet.len;
733     for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
734     {
735       if (unlikely (iter.get_coverage () >= count))
736 	break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
737       if (glyphs->has (iter.get_glyph ()) &&
738 	  (this+pairSet[iter.get_coverage ()]).intersects (glyphs, valueFormat))
739 	return true;
740     }
741     return false;
742   }
743 
collect_glyphsOT::PairPosFormat1744   void collect_glyphs (hb_collect_glyphs_context_t *c) const
745   {
746     TRACE_COLLECT_GLYPHS (this);
747     if (unlikely (!(this+coverage).add_coverage (c->input))) return;
748     unsigned int count = pairSet.len;
749     for (unsigned int i = 0; i < count; i++)
750       (this+pairSet[i]).collect_glyphs (c, valueFormat);
751   }
752 
get_coverageOT::PairPosFormat1753   const Coverage &get_coverage () const { return this+coverage; }
754 
applyOT::PairPosFormat1755   bool apply (hb_ot_apply_context_t *c) const
756   {
757     TRACE_APPLY (this);
758     hb_buffer_t *buffer = c->buffer;
759     unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
760     if (likely (index == NOT_COVERED)) return_trace (false);
761 
762     hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
763     skippy_iter.reset (buffer->idx, 1);
764     if (!skippy_iter.next ()) return_trace (false);
765 
766     return_trace ((this+pairSet[index]).apply (c, valueFormat, skippy_iter.idx));
767   }
768 
subsetOT::PairPosFormat1769   bool subset (hb_subset_context_t *c) const
770   {
771     TRACE_SUBSET (this);
772     // TODO(subset)
773     return_trace (false);
774   }
775 
sanitizeOT::PairPosFormat1776   bool sanitize (hb_sanitize_context_t *c) const
777   {
778     TRACE_SANITIZE (this);
779 
780     if (!c->check_struct (this)) return_trace (false);
781 
782     unsigned int len1 = valueFormat[0].get_len ();
783     unsigned int len2 = valueFormat[1].get_len ();
784     PairSet::sanitize_closure_t closure =
785     {
786       this,
787       valueFormat,
788       len1,
789       1 + len1 + len2
790     };
791 
792     return_trace (coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
793   }
794 
795   protected:
796   HBUINT16	format;			/* Format identifier--format = 1 */
797   OffsetTo<Coverage>
798 		coverage;		/* Offset to Coverage table--from
799 					 * beginning of subtable */
800   ValueFormat	valueFormat[2];		/* [0] Defines the types of data in
801 					 * ValueRecord1--for the first glyph
802 					 * in the pair--may be zero (0) */
803 					/* [1] Defines the types of data in
804 					 * ValueRecord2--for the second glyph
805 					 * in the pair--may be zero (0) */
806   OffsetArrayOf<PairSet>
807 		pairSet;		/* Array of PairSet tables
808 					 * ordered by Coverage Index */
809   public:
810   DEFINE_SIZE_ARRAY (10, pairSet);
811 };
812 
813 struct PairPosFormat2
814 {
intersectsOT::PairPosFormat2815   bool intersects (const hb_set_t *glyphs) const
816   {
817     return (this+coverage).intersects (glyphs) &&
818 	   (this+classDef2).intersects (glyphs);
819   }
820 
collect_glyphsOT::PairPosFormat2821   void collect_glyphs (hb_collect_glyphs_context_t *c) const
822   {
823     TRACE_COLLECT_GLYPHS (this);
824     if (unlikely (!(this+coverage).add_coverage (c->input))) return;
825     if (unlikely (!(this+classDef2).add_coverage (c->input))) return;
826   }
827 
get_coverageOT::PairPosFormat2828   const Coverage &get_coverage () const { return this+coverage; }
829 
applyOT::PairPosFormat2830   bool apply (hb_ot_apply_context_t *c) const
831   {
832     TRACE_APPLY (this);
833     hb_buffer_t *buffer = c->buffer;
834     unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
835     if (likely (index == NOT_COVERED)) return_trace (false);
836 
837     hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
838     skippy_iter.reset (buffer->idx, 1);
839     if (!skippy_iter.next ()) return_trace (false);
840 
841     unsigned int len1 = valueFormat1.get_len ();
842     unsigned int len2 = valueFormat2.get_len ();
843     unsigned int record_len = len1 + len2;
844 
845     unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint);
846     unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint);
847     if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return_trace (false);
848 
849     const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
850     /* Note the intentional use of "|" instead of short-circuit "||". */
851     if (valueFormat1.apply_value (c, this, v, buffer->cur_pos()) |
852 	valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]))
853       buffer->unsafe_to_break (buffer->idx, skippy_iter.idx + 1);
854 
855     buffer->idx = skippy_iter.idx;
856     if (len2)
857       buffer->idx++;
858 
859     return_trace (true);
860   }
861 
subsetOT::PairPosFormat2862   bool subset (hb_subset_context_t *c) const
863   {
864     TRACE_SUBSET (this);
865     // TODO(subset)
866     return_trace (false);
867   }
868 
sanitizeOT::PairPosFormat2869   bool sanitize (hb_sanitize_context_t *c) const
870   {
871     TRACE_SANITIZE (this);
872     if (!(c->check_struct (this)
873        && coverage.sanitize (c, this)
874        && classDef1.sanitize (c, this)
875        && classDef2.sanitize (c, this))) return_trace (false);
876 
877     unsigned int len1 = valueFormat1.get_len ();
878     unsigned int len2 = valueFormat2.get_len ();
879     unsigned int stride = len1 + len2;
880     unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
881     unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
882     return_trace (c->check_range ((const void *) values,
883 				  count,
884 				  record_size) &&
885 		  valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
886 		  valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride));
887   }
888 
889   protected:
890   HBUINT16	format;			/* Format identifier--format = 2 */
891   OffsetTo<Coverage>
892 		coverage;		/* Offset to Coverage table--from
893 					 * beginning of subtable */
894   ValueFormat	valueFormat1;		/* ValueRecord definition--for the
895 					 * first glyph of the pair--may be zero
896 					 * (0) */
897   ValueFormat	valueFormat2;		/* ValueRecord definition--for the
898 					 * second glyph of the pair--may be
899 					 * zero (0) */
900   OffsetTo<ClassDef>
901 		classDef1;		/* Offset to ClassDef table--from
902 					 * beginning of PairPos subtable--for
903 					 * the first glyph of the pair */
904   OffsetTo<ClassDef>
905 		classDef2;		/* Offset to ClassDef table--from
906 					 * beginning of PairPos subtable--for
907 					 * the second glyph of the pair */
908   HBUINT16	class1Count;		/* Number of classes in ClassDef1
909 					 * table--includes Class0 */
910   HBUINT16	class2Count;		/* Number of classes in ClassDef2
911 					 * table--includes Class0 */
912   ValueRecord	values;			/* Matrix of value pairs:
913 					 * class1-major, class2-minor,
914 					 * Each entry has value1 and value2 */
915   public:
916   DEFINE_SIZE_ARRAY (16, values);
917 };
918 
919 struct PairPos
920 {
921   template <typename context_t>
dispatchOT::PairPos922   typename context_t::return_t dispatch (context_t *c) const
923   {
924     TRACE_DISPATCH (this, u.format);
925     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
926     switch (u.format) {
927     case 1: return_trace (c->dispatch (u.format1));
928     case 2: return_trace (c->dispatch (u.format2));
929     default:return_trace (c->default_return_value ());
930     }
931   }
932 
933   protected:
934   union {
935   HBUINT16		format;		/* Format identifier */
936   PairPosFormat1	format1;
937   PairPosFormat2	format2;
938   } u;
939 };
940 
941 
942 struct EntryExitRecord
943 {
944   friend struct CursivePosFormat1;
945 
sanitizeOT::EntryExitRecord946   bool sanitize (hb_sanitize_context_t *c, const void *base) const
947   {
948     TRACE_SANITIZE (this);
949     return_trace (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
950   }
951 
952   protected:
953   OffsetTo<Anchor>
954 		entryAnchor;		/* Offset to EntryAnchor table--from
955 					 * beginning of CursivePos
956 					 * subtable--may be NULL */
957   OffsetTo<Anchor>
958 		exitAnchor;		/* Offset to ExitAnchor table--from
959 					 * beginning of CursivePos
960 					 * subtable--may be NULL */
961   public:
962   DEFINE_SIZE_STATIC (4);
963 };
964 
965 static void
966 reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent);
967 
968 struct CursivePosFormat1
969 {
intersectsOT::CursivePosFormat1970   bool intersects (const hb_set_t *glyphs) const
971   { return (this+coverage).intersects (glyphs); }
972 
collect_glyphsOT::CursivePosFormat1973   void collect_glyphs (hb_collect_glyphs_context_t *c) const
974   {
975     TRACE_COLLECT_GLYPHS (this);
976     if (unlikely (!(this+coverage).add_coverage (c->input))) return;
977   }
978 
get_coverageOT::CursivePosFormat1979   const Coverage &get_coverage () const { return this+coverage; }
980 
applyOT::CursivePosFormat1981   bool apply (hb_ot_apply_context_t *c) const
982   {
983     TRACE_APPLY (this);
984     hb_buffer_t *buffer = c->buffer;
985 
986     const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage  (buffer->cur().codepoint)];
987     if (!this_record.entryAnchor) return_trace (false);
988 
989     hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
990     skippy_iter.reset (buffer->idx, 1);
991     if (!skippy_iter.prev ()) return_trace (false);
992 
993     const EntryExitRecord &prev_record = entryExitRecord[(this+coverage).get_coverage  (buffer->info[skippy_iter.idx].codepoint)];
994     if (!prev_record.exitAnchor) return_trace (false);
995 
996     unsigned int i = skippy_iter.idx;
997     unsigned int j = buffer->idx;
998 
999     buffer->unsafe_to_break (i, j);
1000     float entry_x, entry_y, exit_x, exit_y;
1001     (this+prev_record.exitAnchor).get_anchor (c, buffer->info[i].codepoint, &exit_x, &exit_y);
1002     (this+this_record.entryAnchor).get_anchor (c, buffer->info[j].codepoint, &entry_x, &entry_y);
1003 
1004     hb_glyph_position_t *pos = buffer->pos;
1005 
1006     hb_position_t d;
1007     /* Main-direction adjustment */
1008     switch (c->direction) {
1009       case HB_DIRECTION_LTR:
1010 	pos[i].x_advance  = round (exit_x) + pos[i].x_offset;
1011 
1012 	d = round (entry_x) + pos[j].x_offset;
1013 	pos[j].x_advance -= d;
1014 	pos[j].x_offset  -= d;
1015 	break;
1016       case HB_DIRECTION_RTL:
1017 	d = round (exit_x) + pos[i].x_offset;
1018 	pos[i].x_advance -= d;
1019 	pos[i].x_offset  -= d;
1020 
1021 	pos[j].x_advance  = round (entry_x) + pos[j].x_offset;
1022 	break;
1023       case HB_DIRECTION_TTB:
1024 	pos[i].y_advance  = round (exit_y) + pos[i].y_offset;
1025 
1026 	d = round (entry_y) + pos[j].y_offset;
1027 	pos[j].y_advance -= d;
1028 	pos[j].y_offset  -= d;
1029 	break;
1030       case HB_DIRECTION_BTT:
1031 	d = round (exit_y) + pos[i].y_offset;
1032 	pos[i].y_advance -= d;
1033 	pos[i].y_offset  -= d;
1034 
1035 	pos[j].y_advance  = round (entry_y);
1036 	break;
1037       case HB_DIRECTION_INVALID:
1038       default:
1039 	break;
1040     }
1041 
1042     /* Cross-direction adjustment */
1043 
1044     /* We attach child to parent (think graph theory and rooted trees whereas
1045      * the root stays on baseline and each node aligns itself against its
1046      * parent.
1047      *
1048      * Optimize things for the case of RightToLeft, as that's most common in
1049      * Arabic. */
1050     unsigned int child  = i;
1051     unsigned int parent = j;
1052     hb_position_t x_offset = entry_x - exit_x;
1053     hb_position_t y_offset = entry_y - exit_y;
1054     if  (!(c->lookup_props & LookupFlag::RightToLeft))
1055     {
1056       unsigned int k = child;
1057       child = parent;
1058       parent = k;
1059       x_offset = -x_offset;
1060       y_offset = -y_offset;
1061     }
1062 
1063     /* If child was already connected to someone else, walk through its old
1064      * chain and reverse the link direction, such that the whole tree of its
1065      * previous connection now attaches to new parent.  Watch out for case
1066      * where new parent is on the path from old chain...
1067      */
1068     reverse_cursive_minor_offset (pos, child, c->direction, parent);
1069 
1070     pos[child].attach_type() = ATTACH_TYPE_CURSIVE;
1071     pos[child].attach_chain() = (int) parent - (int) child;
1072     buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
1073     if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
1074       pos[child].y_offset = y_offset;
1075     else
1076       pos[child].x_offset = x_offset;
1077 
1078     buffer->idx++;
1079     return_trace (true);
1080   }
1081 
subsetOT::CursivePosFormat11082   bool subset (hb_subset_context_t *c) const
1083   {
1084     TRACE_SUBSET (this);
1085     // TODO(subset)
1086     return_trace (false);
1087   }
1088 
sanitizeOT::CursivePosFormat11089   bool sanitize (hb_sanitize_context_t *c) const
1090   {
1091     TRACE_SANITIZE (this);
1092     return_trace (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
1093   }
1094 
1095   protected:
1096   HBUINT16	format;			/* Format identifier--format = 1 */
1097   OffsetTo<Coverage>
1098 		coverage;		/* Offset to Coverage table--from
1099 					 * beginning of subtable */
1100   ArrayOf<EntryExitRecord>
1101 		entryExitRecord;	/* Array of EntryExit records--in
1102 					 * Coverage Index order */
1103   public:
1104   DEFINE_SIZE_ARRAY (6, entryExitRecord);
1105 };
1106 
1107 struct CursivePos
1108 {
1109   template <typename context_t>
dispatchOT::CursivePos1110   typename context_t::return_t dispatch (context_t *c) const
1111   {
1112     TRACE_DISPATCH (this, u.format);
1113     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1114     switch (u.format) {
1115     case 1: return_trace (c->dispatch (u.format1));
1116     default:return_trace (c->default_return_value ());
1117     }
1118   }
1119 
1120   protected:
1121   union {
1122   HBUINT16		format;		/* Format identifier */
1123   CursivePosFormat1	format1;
1124   } u;
1125 };
1126 
1127 
1128 typedef AnchorMatrix BaseArray;		/* base-major--
1129 					 * in order of BaseCoverage Index--,
1130 					 * mark-minor--
1131 					 * ordered by class--zero-based. */
1132 
1133 struct MarkBasePosFormat1
1134 {
intersectsOT::MarkBasePosFormat11135   bool intersects (const hb_set_t *glyphs) const
1136   { return (this+markCoverage).intersects (glyphs) &&
1137 	   (this+baseCoverage).intersects (glyphs); }
1138 
collect_glyphsOT::MarkBasePosFormat11139   void collect_glyphs (hb_collect_glyphs_context_t *c) const
1140   {
1141     TRACE_COLLECT_GLYPHS (this);
1142     if (unlikely (!(this+markCoverage).add_coverage (c->input))) return;
1143     if (unlikely (!(this+baseCoverage).add_coverage (c->input))) return;
1144   }
1145 
get_coverageOT::MarkBasePosFormat11146   const Coverage &get_coverage () const { return this+markCoverage; }
1147 
applyOT::MarkBasePosFormat11148   bool apply (hb_ot_apply_context_t *c) const
1149   {
1150     TRACE_APPLY (this);
1151     hb_buffer_t *buffer = c->buffer;
1152     unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
1153     if (likely (mark_index == NOT_COVERED)) return_trace (false);
1154 
1155     /* Now we search backwards for a non-mark glyph */
1156     hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
1157     skippy_iter.reset (buffer->idx, 1);
1158     skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
1159     do {
1160       if (!skippy_iter.prev ()) return_trace (false);
1161       /* We only want to attach to the first of a MultipleSubst sequence.
1162        * https://github.com/harfbuzz/harfbuzz/issues/740
1163        * Reject others...
1164        * ...but stop if we find a mark in the MultipleSubst sequence:
1165        * https://github.com/harfbuzz/harfbuzz/issues/1020 */
1166       if (!_hb_glyph_info_multiplied (&buffer->info[skippy_iter.idx]) ||
1167 	  0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) ||
1168 	  (skippy_iter.idx == 0 ||
1169 	   _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx - 1]) ||
1170 	   _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]) !=
1171 	   _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx - 1]) ||
1172 	   _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) !=
1173 	   _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx - 1]) + 1
1174 	   ))
1175 	break;
1176       skippy_iter.reject ();
1177     } while (true);
1178 
1179     /* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */
1180     //if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { return_trace (false); }
1181 
1182     unsigned int base_index = (this+baseCoverage).get_coverage  (buffer->info[skippy_iter.idx].codepoint);
1183     if (base_index == NOT_COVERED) return_trace (false);
1184 
1185     return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx));
1186   }
1187 
subsetOT::MarkBasePosFormat11188   bool subset (hb_subset_context_t *c) const
1189   {
1190     TRACE_SUBSET (this);
1191     // TODO(subset)
1192     return_trace (false);
1193   }
1194 
sanitizeOT::MarkBasePosFormat11195   bool sanitize (hb_sanitize_context_t *c) const
1196   {
1197     TRACE_SANITIZE (this);
1198     return_trace (c->check_struct (this) &&
1199 		  markCoverage.sanitize (c, this) &&
1200 		  baseCoverage.sanitize (c, this) &&
1201 		  markArray.sanitize (c, this) &&
1202 		  baseArray.sanitize (c, this, (unsigned int) classCount));
1203   }
1204 
1205   protected:
1206   HBUINT16	format;			/* Format identifier--format = 1 */
1207   OffsetTo<Coverage>
1208 		markCoverage;		/* Offset to MarkCoverage table--from
1209 					 * beginning of MarkBasePos subtable */
1210   OffsetTo<Coverage>
1211 		baseCoverage;		/* Offset to BaseCoverage table--from
1212 					 * beginning of MarkBasePos subtable */
1213   HBUINT16	classCount;		/* Number of classes defined for marks */
1214   OffsetTo<MarkArray>
1215 		markArray;		/* Offset to MarkArray table--from
1216 					 * beginning of MarkBasePos subtable */
1217   OffsetTo<BaseArray>
1218 		baseArray;		/* Offset to BaseArray table--from
1219 					 * beginning of MarkBasePos subtable */
1220   public:
1221   DEFINE_SIZE_STATIC (12);
1222 };
1223 
1224 struct MarkBasePos
1225 {
1226   template <typename context_t>
dispatchOT::MarkBasePos1227   typename context_t::return_t dispatch (context_t *c) const
1228   {
1229     TRACE_DISPATCH (this, u.format);
1230     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1231     switch (u.format) {
1232     case 1: return_trace (c->dispatch (u.format1));
1233     default:return_trace (c->default_return_value ());
1234     }
1235   }
1236 
1237   protected:
1238   union {
1239   HBUINT16		format;		/* Format identifier */
1240   MarkBasePosFormat1	format1;
1241   } u;
1242 };
1243 
1244 
1245 typedef AnchorMatrix LigatureAttach;	/* component-major--
1246 					 * in order of writing direction--,
1247 					 * mark-minor--
1248 					 * ordered by class--zero-based. */
1249 
1250 typedef OffsetListOf<LigatureAttach> LigatureArray;
1251 					/* Array of LigatureAttach
1252 					 * tables ordered by
1253 					 * LigatureCoverage Index */
1254 
1255 struct MarkLigPosFormat1
1256 {
intersectsOT::MarkLigPosFormat11257   bool intersects (const hb_set_t *glyphs) const
1258   { return (this+markCoverage).intersects (glyphs) &&
1259 	   (this+ligatureCoverage).intersects (glyphs); }
1260 
collect_glyphsOT::MarkLigPosFormat11261   void collect_glyphs (hb_collect_glyphs_context_t *c) const
1262   {
1263     TRACE_COLLECT_GLYPHS (this);
1264     if (unlikely (!(this+markCoverage).add_coverage (c->input))) return;
1265     if (unlikely (!(this+ligatureCoverage).add_coverage (c->input))) return;
1266   }
1267 
get_coverageOT::MarkLigPosFormat11268   const Coverage &get_coverage () const { return this+markCoverage; }
1269 
applyOT::MarkLigPosFormat11270   bool apply (hb_ot_apply_context_t *c) const
1271   {
1272     TRACE_APPLY (this);
1273     hb_buffer_t *buffer = c->buffer;
1274     unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
1275     if (likely (mark_index == NOT_COVERED)) return_trace (false);
1276 
1277     /* Now we search backwards for a non-mark glyph */
1278     hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
1279     skippy_iter.reset (buffer->idx, 1);
1280     skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
1281     if (!skippy_iter.prev ()) return_trace (false);
1282 
1283     /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */
1284     //if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { return_trace (false); }
1285 
1286     unsigned int j = skippy_iter.idx;
1287     unsigned int lig_index = (this+ligatureCoverage).get_coverage  (buffer->info[j].codepoint);
1288     if (lig_index == NOT_COVERED) return_trace (false);
1289 
1290     const LigatureArray& lig_array = this+ligatureArray;
1291     const LigatureAttach& lig_attach = lig_array[lig_index];
1292 
1293     /* Find component to attach to */
1294     unsigned int comp_count = lig_attach.rows;
1295     if (unlikely (!comp_count)) return_trace (false);
1296 
1297     /* We must now check whether the ligature ID of the current mark glyph
1298      * is identical to the ligature ID of the found ligature.  If yes, we
1299      * can directly use the component index.  If not, we attach the mark
1300      * glyph to the last component of the ligature. */
1301     unsigned int comp_index;
1302     unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[j]);
1303     unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur());
1304     unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
1305     if (lig_id && lig_id == mark_id && mark_comp > 0)
1306       comp_index = MIN (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1;
1307     else
1308       comp_index = comp_count - 1;
1309 
1310     return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
1311   }
1312 
subsetOT::MarkLigPosFormat11313   bool subset (hb_subset_context_t *c) const
1314   {
1315     TRACE_SUBSET (this);
1316     // TODO(subset)
1317     return_trace (false);
1318   }
1319 
sanitizeOT::MarkLigPosFormat11320   bool sanitize (hb_sanitize_context_t *c) const
1321   {
1322     TRACE_SANITIZE (this);
1323     return_trace (c->check_struct (this) &&
1324 		  markCoverage.sanitize (c, this) &&
1325 		  ligatureCoverage.sanitize (c, this) &&
1326 		  markArray.sanitize (c, this) &&
1327 		  ligatureArray.sanitize (c, this, (unsigned int) classCount));
1328   }
1329 
1330   protected:
1331   HBUINT16	format;			/* Format identifier--format = 1 */
1332   OffsetTo<Coverage>
1333 		markCoverage;		/* Offset to Mark Coverage table--from
1334 					 * beginning of MarkLigPos subtable */
1335   OffsetTo<Coverage>
1336 		ligatureCoverage;	/* Offset to Ligature Coverage
1337 					 * table--from beginning of MarkLigPos
1338 					 * subtable */
1339   HBUINT16	classCount;		/* Number of defined mark classes */
1340   OffsetTo<MarkArray>
1341 		markArray;		/* Offset to MarkArray table--from
1342 					 * beginning of MarkLigPos subtable */
1343   OffsetTo<LigatureArray>
1344 		ligatureArray;		/* Offset to LigatureArray table--from
1345 					 * beginning of MarkLigPos subtable */
1346   public:
1347   DEFINE_SIZE_STATIC (12);
1348 };
1349 
1350 struct MarkLigPos
1351 {
1352   template <typename context_t>
dispatchOT::MarkLigPos1353   typename context_t::return_t dispatch (context_t *c) const
1354   {
1355     TRACE_DISPATCH (this, u.format);
1356     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1357     switch (u.format) {
1358     case 1: return_trace (c->dispatch (u.format1));
1359     default:return_trace (c->default_return_value ());
1360     }
1361   }
1362 
1363   protected:
1364   union {
1365   HBUINT16		format;		/* Format identifier */
1366   MarkLigPosFormat1	format1;
1367   } u;
1368 };
1369 
1370 
1371 typedef AnchorMatrix Mark2Array;	/* mark2-major--
1372 					 * in order of Mark2Coverage Index--,
1373 					 * mark1-minor--
1374 					 * ordered by class--zero-based. */
1375 
1376 struct MarkMarkPosFormat1
1377 {
intersectsOT::MarkMarkPosFormat11378   bool intersects (const hb_set_t *glyphs) const
1379   { return (this+mark1Coverage).intersects (glyphs) &&
1380 	   (this+mark2Coverage).intersects (glyphs); }
1381 
collect_glyphsOT::MarkMarkPosFormat11382   void collect_glyphs (hb_collect_glyphs_context_t *c) const
1383   {
1384     TRACE_COLLECT_GLYPHS (this);
1385     if (unlikely (!(this+mark1Coverage).add_coverage (c->input))) return;
1386     if (unlikely (!(this+mark2Coverage).add_coverage (c->input))) return;
1387   }
1388 
get_coverageOT::MarkMarkPosFormat11389   const Coverage &get_coverage () const { return this+mark1Coverage; }
1390 
applyOT::MarkMarkPosFormat11391   bool apply (hb_ot_apply_context_t *c) const
1392   {
1393     TRACE_APPLY (this);
1394     hb_buffer_t *buffer = c->buffer;
1395     unsigned int mark1_index = (this+mark1Coverage).get_coverage  (buffer->cur().codepoint);
1396     if (likely (mark1_index == NOT_COVERED)) return_trace (false);
1397 
1398     /* now we search backwards for a suitable mark glyph until a non-mark glyph */
1399     hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
1400     skippy_iter.reset (buffer->idx, 1);
1401     skippy_iter.set_lookup_props (c->lookup_props & ~LookupFlag::IgnoreFlags);
1402     if (!skippy_iter.prev ()) return_trace (false);
1403 
1404     if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])) { return_trace (false); }
1405 
1406     unsigned int j = skippy_iter.idx;
1407 
1408     unsigned int id1 = _hb_glyph_info_get_lig_id (&buffer->cur());
1409     unsigned int id2 = _hb_glyph_info_get_lig_id (&buffer->info[j]);
1410     unsigned int comp1 = _hb_glyph_info_get_lig_comp (&buffer->cur());
1411     unsigned int comp2 = _hb_glyph_info_get_lig_comp (&buffer->info[j]);
1412 
1413     if (likely (id1 == id2)) {
1414       if (id1 == 0) /* Marks belonging to the same base. */
1415 	goto good;
1416       else if (comp1 == comp2) /* Marks belonging to the same ligature component. */
1417 	goto good;
1418     } else {
1419       /* If ligature ids don't match, it may be the case that one of the marks
1420        * itself is a ligature.  In which case match. */
1421       if ((id1 > 0 && !comp1) || (id2 > 0 && !comp2))
1422 	goto good;
1423     }
1424 
1425     /* Didn't match. */
1426     return_trace (false);
1427 
1428     good:
1429     unsigned int mark2_index = (this+mark2Coverage).get_coverage  (buffer->info[j].codepoint);
1430     if (mark2_index == NOT_COVERED) return_trace (false);
1431 
1432     return_trace ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j));
1433   }
1434 
subsetOT::MarkMarkPosFormat11435   bool subset (hb_subset_context_t *c) const
1436   {
1437     TRACE_SUBSET (this);
1438     // TODO(subset)
1439     return_trace (false);
1440   }
1441 
sanitizeOT::MarkMarkPosFormat11442   bool sanitize (hb_sanitize_context_t *c) const
1443   {
1444     TRACE_SANITIZE (this);
1445     return_trace (c->check_struct (this) &&
1446 		  mark1Coverage.sanitize (c, this) &&
1447 		  mark2Coverage.sanitize (c, this) &&
1448 		  mark1Array.sanitize (c, this) &&
1449 		  mark2Array.sanitize (c, this, (unsigned int) classCount));
1450   }
1451 
1452   protected:
1453   HBUINT16	format;			/* Format identifier--format = 1 */
1454   OffsetTo<Coverage>
1455 		mark1Coverage;		/* Offset to Combining Mark1 Coverage
1456 					 * table--from beginning of MarkMarkPos
1457 					 * subtable */
1458   OffsetTo<Coverage>
1459 		mark2Coverage;		/* Offset to Combining Mark2 Coverage
1460 					 * table--from beginning of MarkMarkPos
1461 					 * subtable */
1462   HBUINT16	classCount;		/* Number of defined mark classes */
1463   OffsetTo<MarkArray>
1464 		mark1Array;		/* Offset to Mark1Array table--from
1465 					 * beginning of MarkMarkPos subtable */
1466   OffsetTo<Mark2Array>
1467 		mark2Array;		/* Offset to Mark2Array table--from
1468 					 * beginning of MarkMarkPos subtable */
1469   public:
1470   DEFINE_SIZE_STATIC (12);
1471 };
1472 
1473 struct MarkMarkPos
1474 {
1475   template <typename context_t>
dispatchOT::MarkMarkPos1476   typename context_t::return_t dispatch (context_t *c) const
1477   {
1478     TRACE_DISPATCH (this, u.format);
1479     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1480     switch (u.format) {
1481     case 1: return_trace (c->dispatch (u.format1));
1482     default:return_trace (c->default_return_value ());
1483     }
1484   }
1485 
1486   protected:
1487   union {
1488   HBUINT16		format;		/* Format identifier */
1489   MarkMarkPosFormat1	format1;
1490   } u;
1491 };
1492 
1493 
1494 struct ContextPos : Context {};
1495 
1496 struct ChainContextPos : ChainContext {};
1497 
1498 struct ExtensionPos : Extension<ExtensionPos>
1499 {
1500   typedef struct PosLookupSubTable SubTable;
1501 };
1502 
1503 
1504 
1505 /*
1506  * PosLookup
1507  */
1508 
1509 
1510 struct PosLookupSubTable
1511 {
1512   friend struct Lookup;
1513   friend struct PosLookup;
1514 
1515   enum Type {
1516     Single		= 1,
1517     Pair		= 2,
1518     Cursive		= 3,
1519     MarkBase		= 4,
1520     MarkLig		= 5,
1521     MarkMark		= 6,
1522     Context		= 7,
1523     ChainContext	= 8,
1524     Extension		= 9
1525   };
1526 
1527   template <typename context_t>
dispatchOT::PosLookupSubTable1528   typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
1529   {
1530     TRACE_DISPATCH (this, lookup_type);
1531     switch (lookup_type) {
1532     case Single:		return_trace (u.single.dispatch (c));
1533     case Pair:			return_trace (u.pair.dispatch (c));
1534     case Cursive:		return_trace (u.cursive.dispatch (c));
1535     case MarkBase:		return_trace (u.markBase.dispatch (c));
1536     case MarkLig:		return_trace (u.markLig.dispatch (c));
1537     case MarkMark:		return_trace (u.markMark.dispatch (c));
1538     case Context:		return_trace (u.context.dispatch (c));
1539     case ChainContext:		return_trace (u.chainContext.dispatch (c));
1540     case Extension:		return_trace (u.extension.dispatch (c));
1541     default:			return_trace (c->default_return_value ());
1542     }
1543   }
1544 
1545   protected:
1546   union {
1547   SinglePos		single;
1548   PairPos		pair;
1549   CursivePos		cursive;
1550   MarkBasePos		markBase;
1551   MarkLigPos		markLig;
1552   MarkMarkPos		markMark;
1553   ContextPos		context;
1554   ChainContextPos	chainContext;
1555   ExtensionPos		extension;
1556   } u;
1557   public:
1558   DEFINE_SIZE_MIN (0);
1559 };
1560 
1561 
1562 struct PosLookup : Lookup
1563 {
1564   typedef struct PosLookupSubTable SubTable;
1565 
get_subtableOT::PosLookup1566   const SubTable& get_subtable (unsigned int i) const
1567   { return Lookup::get_subtable<SubTable> (i); }
1568 
is_reverseOT::PosLookup1569   bool is_reverse () const
1570   {
1571     return false;
1572   }
1573 
applyOT::PosLookup1574   bool apply (hb_ot_apply_context_t *c) const
1575   {
1576     TRACE_APPLY (this);
1577     return_trace (dispatch (c));
1578   }
1579 
intersectsOT::PosLookup1580   bool intersects (const hb_set_t *glyphs) const
1581   {
1582     hb_intersects_context_t c (glyphs);
1583     return dispatch (&c);
1584   }
1585 
collect_glyphsOT::PosLookup1586   hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
1587   {
1588     TRACE_COLLECT_GLYPHS (this);
1589     return_trace (dispatch (c));
1590   }
1591 
1592   template <typename set_t>
add_coverageOT::PosLookup1593   void add_coverage (set_t *glyphs) const
1594   {
1595     hb_add_coverage_context_t<set_t> c (glyphs);
1596     dispatch (&c);
1597   }
1598 
1599   static bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index);
1600 
1601   template <typename context_t>
1602   static typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
1603 
1604   template <typename context_t>
dispatchOT::PosLookup1605   typename context_t::return_t dispatch (context_t *c) const
1606   { return Lookup::dispatch<SubTable> (c); }
1607 
subsetOT::PosLookup1608   bool subset (hb_subset_context_t *c) const
1609   { return Lookup::subset<SubTable> (c); }
1610 
sanitizeOT::PosLookup1611   bool sanitize (hb_sanitize_context_t *c) const
1612   { return Lookup::sanitize<SubTable> (c); }
1613 };
1614 
1615 /*
1616  * GPOS -- Glyph Positioning
1617  * https://docs.microsoft.com/en-us/typography/opentype/spec/gpos
1618  */
1619 
1620 struct GPOS : GSUBGPOS
1621 {
1622   enum { tableTag = HB_OT_TAG_GPOS };
1623 
get_lookupOT::GPOS1624   const PosLookup& get_lookup (unsigned int i) const
1625   { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
1626 
1627   static inline void position_start (hb_font_t *font, hb_buffer_t *buffer);
1628   static inline void position_finish_advances (hb_font_t *font, hb_buffer_t *buffer);
1629   static inline void position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer);
1630 
subsetOT::GPOS1631   bool subset (hb_subset_context_t *c) const
1632   { return GSUBGPOS::subset<PosLookup> (c); }
1633 
sanitizeOT::GPOS1634   bool sanitize (hb_sanitize_context_t *c) const
1635   { return GSUBGPOS::sanitize<PosLookup> (c); }
1636 
1637   HB_INTERNAL bool is_blacklisted (hb_blob_t *blob,
1638 				   hb_face_t *face) const;
1639 
1640   typedef GSUBGPOS::accelerator_t<GPOS> accelerator_t;
1641 };
1642 
1643 
1644 static void
reverse_cursive_minor_offset(hb_glyph_position_t * pos,unsigned int i,hb_direction_t direction,unsigned int new_parent)1645 reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent)
1646 {
1647   int chain = pos[i].attach_chain(), type = pos[i].attach_type();
1648   if (likely (!chain || 0 == (type & ATTACH_TYPE_CURSIVE)))
1649     return;
1650 
1651   pos[i].attach_chain() = 0;
1652 
1653   unsigned int j = (int) i + chain;
1654 
1655   /* Stop if we see new parent in the chain. */
1656   if (j == new_parent)
1657     return;
1658 
1659   reverse_cursive_minor_offset (pos, j, direction, new_parent);
1660 
1661   if (HB_DIRECTION_IS_HORIZONTAL (direction))
1662     pos[j].y_offset = -pos[i].y_offset;
1663   else
1664     pos[j].x_offset = -pos[i].x_offset;
1665 
1666   pos[j].attach_chain() = -chain;
1667   pos[j].attach_type() = type;
1668 }
1669 static void
propagate_attachment_offsets(hb_glyph_position_t * pos,unsigned int len,unsigned int i,hb_direction_t direction)1670 propagate_attachment_offsets (hb_glyph_position_t *pos,
1671 			      unsigned int len,
1672 			      unsigned int i,
1673 			      hb_direction_t direction)
1674 {
1675   /* Adjusts offsets of attached glyphs (both cursive and mark) to accumulate
1676    * offset of glyph they are attached to. */
1677   int chain = pos[i].attach_chain(), type = pos[i].attach_type();
1678   if (likely (!chain))
1679     return;
1680 
1681   pos[i].attach_chain() = 0;
1682 
1683   unsigned int j = (int) i + chain;
1684 
1685   if (unlikely (j >= len))
1686     return;
1687 
1688   propagate_attachment_offsets (pos, len, j, direction);
1689 
1690   assert (!!(type & ATTACH_TYPE_MARK) ^ !!(type & ATTACH_TYPE_CURSIVE));
1691 
1692   if (type & ATTACH_TYPE_CURSIVE)
1693   {
1694     if (HB_DIRECTION_IS_HORIZONTAL (direction))
1695       pos[i].y_offset += pos[j].y_offset;
1696     else
1697       pos[i].x_offset += pos[j].x_offset;
1698   }
1699   else /*if (type & ATTACH_TYPE_MARK)*/
1700   {
1701     pos[i].x_offset += pos[j].x_offset;
1702     pos[i].y_offset += pos[j].y_offset;
1703 
1704     assert (j < i);
1705     if (HB_DIRECTION_IS_FORWARD (direction))
1706       for (unsigned int k = j; k < i; k++) {
1707 	pos[i].x_offset -= pos[k].x_advance;
1708 	pos[i].y_offset -= pos[k].y_advance;
1709       }
1710     else
1711       for (unsigned int k = j + 1; k < i + 1; k++) {
1712 	pos[i].x_offset += pos[k].x_advance;
1713 	pos[i].y_offset += pos[k].y_advance;
1714       }
1715   }
1716 }
1717 
1718 void
position_start(hb_font_t * font HB_UNUSED,hb_buffer_t * buffer)1719 GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
1720 {
1721   unsigned int count = buffer->len;
1722   for (unsigned int i = 0; i < count; i++)
1723     buffer->pos[i].attach_chain() = buffer->pos[i].attach_type() = 0;
1724 }
1725 
1726 void
position_finish_advances(hb_font_t * font HB_UNUSED,hb_buffer_t * buffer HB_UNUSED)1727 GPOS::position_finish_advances (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSED)
1728 {
1729   //_hb_buffer_assert_gsubgpos_vars (buffer);
1730 }
1731 
1732 void
position_finish_offsets(hb_font_t * font HB_UNUSED,hb_buffer_t * buffer)1733 GPOS::position_finish_offsets (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
1734 {
1735   _hb_buffer_assert_gsubgpos_vars (buffer);
1736 
1737   unsigned int len;
1738   hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
1739   hb_direction_t direction = buffer->props.direction;
1740 
1741   /* Handle attachments */
1742   if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT)
1743     for (unsigned int i = 0; i < len; i++)
1744       propagate_attachment_offsets (pos, len, i, direction);
1745 }
1746 
1747 
1748 struct GPOS_accelerator_t : GPOS::accelerator_t {};
1749 
1750 
1751 /* Out-of-class implementation for methods recursing */
1752 
1753 template <typename context_t>
dispatch_recurse_func(context_t * c,unsigned int lookup_index)1754 /*static*/ inline typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
1755 {
1756   const PosLookup &l = c->face->table.GPOS.get_relaxed ()->table->get_lookup (lookup_index);
1757   return l.dispatch (c);
1758 }
1759 
apply_recurse_func(hb_ot_apply_context_t * c,unsigned int lookup_index)1760 /*static*/ inline bool PosLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
1761 {
1762   const PosLookup &l = c->face->table.GPOS.get_relaxed ()->table->get_lookup (lookup_index);
1763   unsigned int saved_lookup_props = c->lookup_props;
1764   unsigned int saved_lookup_index = c->lookup_index;
1765   c->set_lookup_index (lookup_index);
1766   c->set_lookup_props (l.get_props ());
1767   bool ret = l.dispatch (c);
1768   c->set_lookup_index (saved_lookup_index);
1769   c->set_lookup_props (saved_lookup_props);
1770   return ret;
1771 }
1772 
1773 
1774 } /* namespace OT */
1775 
1776 
1777 #endif /* HB_OT_LAYOUT_GPOS_TABLE_HH */
1778