Update mojo sdk to rev 1dc8a9a5db73d3718d99917fadf31f5fb2ebad4f
[chromium-blink-merge.git] / third_party / harfbuzz-ng / src / hb-ot-layout-gpos-table.hh
blobd88f7876e0a81169accb2a20c0c1d21a3db20327
1 /*
2 * Copyright © 2007,2008,2009,2010 Red Hat, Inc.
3 * Copyright © 2010,2012,2013 Google, Inc.
5 * This is part of HarfBuzz, a text shaping library.
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.
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.
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.
25 * Red Hat Author(s): Behdad Esfahbod
26 * Google Author(s): Behdad Esfahbod
29 #ifndef HB_OT_LAYOUT_GPOS_TABLE_HH
30 #define HB_OT_LAYOUT_GPOS_TABLE_HH
32 #include "hb-ot-layout-gsubgpos-private.hh"
35 namespace OT {
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 */
43 /* Shared Tables: ValueRecord, Anchor Table, and MarkArray */
45 typedef USHORT Value;
47 typedef Value ValueRecord[VAR];
49 struct ValueFormat : USHORT
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 */
63 devices = 0x00F0u /* Mask for having any Device table */
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
92 inline unsigned int get_len (void) const
93 { return _hb_popcount32 ((unsigned int) *this); }
94 inline unsigned int get_size (void) const
95 { return get_len () * Value::static_size; }
97 void apply_value (hb_font_t *font,
98 hb_direction_t direction,
99 const void *base,
100 const Value *values,
101 hb_glyph_position_t &glyph_pos) const
103 unsigned int x_ppem, y_ppem;
104 unsigned int format = *this;
105 hb_bool_t horizontal = HB_DIRECTION_IS_HORIZONTAL (direction);
107 if (!format) return;
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++;
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++;
121 if (!has_device ()) return;
123 x_ppem = font->x_ppem;
124 y_ppem = font->y_ppem;
126 if (!x_ppem && !y_ppem) return;
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++;
133 if (format & yPlaDevice) {
134 if (y_ppem) glyph_pos.y_offset += (base + get_device (values)).get_y_delta (font);
135 values++;
137 if (format & xAdvDevice) {
138 if (horizontal && x_ppem) glyph_pos.x_advance += (base + get_device (values)).get_x_delta (font);
139 values++;
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++;
148 private:
149 inline bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const
151 unsigned int format = *this;
153 if (format & xPlacement) values++;
154 if (format & yPlacement) values++;
155 if (format & xAdvance) values++;
156 if (format & yAdvance) values++;
158 if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
159 if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
160 if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
161 if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
163 return true;
166 static inline OffsetTo<Device>& get_device (Value* value)
167 { return *CastP<OffsetTo<Device> > (value); }
168 static inline const OffsetTo<Device>& get_device (const Value* value)
169 { return *CastP<OffsetTo<Device> > (value); }
171 static inline const SHORT& get_short (const Value* value)
172 { return *CastP<SHORT> (value); }
174 public:
176 inline bool has_device (void) const {
177 unsigned int format = *this;
178 return (format & devices) != 0;
181 inline bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const
183 TRACE_SANITIZE (this);
184 return TRACE_RETURN (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values)));
187 inline bool sanitize_values (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count) const
189 TRACE_SANITIZE (this);
190 unsigned int len = get_len ();
192 if (!c->check_array (values, get_size (), count)) return TRACE_RETURN (false);
194 if (!has_device ()) return TRACE_RETURN (true);
196 for (unsigned int i = 0; i < count; i++) {
197 if (!sanitize_value_devices (c, base, values))
198 return TRACE_RETURN (false);
199 values += len;
202 return TRACE_RETURN (true);
205 /* Just sanitize referenced Device tables. Doesn't check the values themselves. */
206 inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count, unsigned int stride) const
208 TRACE_SANITIZE (this);
210 if (!has_device ()) return TRACE_RETURN (true);
212 for (unsigned int i = 0; i < count; i++) {
213 if (!sanitize_value_devices (c, base, values))
214 return TRACE_RETURN (false);
215 values += stride;
218 return TRACE_RETURN (true);
223 struct AnchorFormat1
225 inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
226 hb_position_t *x, hb_position_t *y) const
228 *x = font->em_scale_x (xCoordinate);
229 *y = font->em_scale_y (yCoordinate);
232 inline bool sanitize (hb_sanitize_context_t *c) const
234 TRACE_SANITIZE (this);
235 return TRACE_RETURN (c->check_struct (this));
238 protected:
239 USHORT format; /* Format identifier--format = 1 */
240 SHORT xCoordinate; /* Horizontal value--in design units */
241 SHORT yCoordinate; /* Vertical value--in design units */
242 public:
243 DEFINE_SIZE_STATIC (6);
246 struct AnchorFormat2
248 inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
249 hb_position_t *x, hb_position_t *y) const
251 unsigned int x_ppem = font->x_ppem;
252 unsigned int y_ppem = font->y_ppem;
253 hb_position_t cx, cy;
254 hb_bool_t ret;
256 ret = (x_ppem || y_ppem) &&
257 font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
258 *x = ret && x_ppem ? cx : font->em_scale_x (xCoordinate);
259 *y = ret && y_ppem ? cy : font->em_scale_y (yCoordinate);
262 inline bool sanitize (hb_sanitize_context_t *c) const
264 TRACE_SANITIZE (this);
265 return TRACE_RETURN (c->check_struct (this));
268 protected:
269 USHORT format; /* Format identifier--format = 2 */
270 SHORT xCoordinate; /* Horizontal value--in design units */
271 SHORT yCoordinate; /* Vertical value--in design units */
272 USHORT anchorPoint; /* Index to glyph contour point */
273 public:
274 DEFINE_SIZE_STATIC (8);
277 struct AnchorFormat3
279 inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
280 hb_position_t *x, hb_position_t *y) const
282 *x = font->em_scale_x (xCoordinate);
283 *y = font->em_scale_y (yCoordinate);
285 if (font->x_ppem)
286 *x += (this+xDeviceTable).get_x_delta (font);
287 if (font->y_ppem)
288 *y += (this+yDeviceTable).get_x_delta (font);
291 inline bool sanitize (hb_sanitize_context_t *c) const
293 TRACE_SANITIZE (this);
294 return TRACE_RETURN (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
297 protected:
298 USHORT format; /* Format identifier--format = 3 */
299 SHORT xCoordinate; /* Horizontal value--in design units */
300 SHORT yCoordinate; /* Vertical value--in design units */
301 OffsetTo<Device>
302 xDeviceTable; /* Offset to Device table for X
303 * coordinate-- from beginning of
304 * Anchor table (may be NULL) */
305 OffsetTo<Device>
306 yDeviceTable; /* Offset to Device table for Y
307 * coordinate-- from beginning of
308 * Anchor table (may be NULL) */
309 public:
310 DEFINE_SIZE_STATIC (10);
313 struct Anchor
315 inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
316 hb_position_t *x, hb_position_t *y) const
318 *x = *y = 0;
319 switch (u.format) {
320 case 1: u.format1.get_anchor (font, glyph_id, x, y); return;
321 case 2: u.format2.get_anchor (font, glyph_id, x, y); return;
322 case 3: u.format3.get_anchor (font, glyph_id, x, y); return;
323 default: return;
327 inline bool sanitize (hb_sanitize_context_t *c) const
329 TRACE_SANITIZE (this);
330 if (!u.format.sanitize (c)) return TRACE_RETURN (false);
331 switch (u.format) {
332 case 1: return TRACE_RETURN (u.format1.sanitize (c));
333 case 2: return TRACE_RETURN (u.format2.sanitize (c));
334 case 3: return TRACE_RETURN (u.format3.sanitize (c));
335 default:return TRACE_RETURN (true);
339 protected:
340 union {
341 USHORT format; /* Format identifier */
342 AnchorFormat1 format1;
343 AnchorFormat2 format2;
344 AnchorFormat3 format3;
345 } u;
346 public:
347 DEFINE_SIZE_UNION (2, format);
351 struct AnchorMatrix
353 inline const Anchor& get_anchor (unsigned int row, unsigned int col, unsigned int cols, bool *found) const {
354 *found = false;
355 if (unlikely (row >= rows || col >= cols)) return Null(Anchor);
356 *found = !matrixZ[row * cols + col].is_null ();
357 return this+matrixZ[row * cols + col];
360 inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) const
362 TRACE_SANITIZE (this);
363 if (!c->check_struct (this)) return TRACE_RETURN (false);
364 if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return TRACE_RETURN (false);
365 unsigned int count = rows * cols;
366 if (!c->check_array (matrixZ, matrixZ[0].static_size, count)) return TRACE_RETURN (false);
367 for (unsigned int i = 0; i < count; i++)
368 if (!matrixZ[i].sanitize (c, this)) return TRACE_RETURN (false);
369 return TRACE_RETURN (true);
372 USHORT rows; /* Number of rows */
373 protected:
374 OffsetTo<Anchor>
375 matrixZ[VAR]; /* Matrix of offsets to Anchor tables--
376 * from beginning of AnchorMatrix table */
377 public:
378 DEFINE_SIZE_ARRAY (2, matrixZ);
382 struct MarkRecord
384 friend struct MarkArray;
386 inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
388 TRACE_SANITIZE (this);
389 return TRACE_RETURN (c->check_struct (this) && markAnchor.sanitize (c, base));
392 protected:
393 USHORT klass; /* Class defined for this mark */
394 OffsetTo<Anchor>
395 markAnchor; /* Offset to Anchor table--from
396 * beginning of MarkArray table */
397 public:
398 DEFINE_SIZE_STATIC (4);
401 struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage order */
403 inline bool apply (hb_apply_context_t *c,
404 unsigned int mark_index, unsigned int glyph_index,
405 const AnchorMatrix &anchors, unsigned int class_count,
406 unsigned int glyph_pos) const
408 TRACE_APPLY (this);
409 hb_buffer_t *buffer = c->buffer;
410 const MarkRecord &record = ArrayOf<MarkRecord>::operator[](mark_index);
411 unsigned int mark_class = record.klass;
413 const Anchor& mark_anchor = this + record.markAnchor;
414 bool found;
415 const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count, &found);
416 /* If this subtable doesn't have an anchor for this base and this class,
417 * return false such that the subsequent subtables have a chance at it. */
418 if (unlikely (!found)) return TRACE_RETURN (false);
420 hb_position_t mark_x, mark_y, base_x, base_y;
422 mark_anchor.get_anchor (c->font, buffer->cur().codepoint, &mark_x, &mark_y);
423 glyph_anchor.get_anchor (c->font, buffer->info[glyph_pos].codepoint, &base_x, &base_y);
425 hb_glyph_position_t &o = buffer->cur_pos();
426 o.x_offset = base_x - mark_x;
427 o.y_offset = base_y - mark_y;
428 o.attach_lookback() = buffer->idx - glyph_pos;
430 buffer->idx++;
431 return TRACE_RETURN (true);
434 inline bool sanitize (hb_sanitize_context_t *c) const
436 TRACE_SANITIZE (this);
437 return TRACE_RETURN (ArrayOf<MarkRecord>::sanitize (c, this));
442 /* Lookups */
444 struct SinglePosFormat1
446 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
448 TRACE_COLLECT_GLYPHS (this);
449 (this+coverage).add_coverage (c->input);
452 inline const Coverage &get_coverage (void) const
454 return this+coverage;
457 inline bool apply (hb_apply_context_t *c) const
459 TRACE_APPLY (this);
460 hb_buffer_t *buffer = c->buffer;
461 unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
462 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
464 valueFormat.apply_value (c->font, c->direction, this,
465 values, buffer->cur_pos());
467 buffer->idx++;
468 return TRACE_RETURN (true);
471 inline bool sanitize (hb_sanitize_context_t *c) const
473 TRACE_SANITIZE (this);
474 return TRACE_RETURN (c->check_struct (this)
475 && coverage.sanitize (c, this)
476 && valueFormat.sanitize_value (c, this, values));
479 protected:
480 USHORT format; /* Format identifier--format = 1 */
481 OffsetTo<Coverage>
482 coverage; /* Offset to Coverage table--from
483 * beginning of subtable */
484 ValueFormat valueFormat; /* Defines the types of data in the
485 * ValueRecord */
486 ValueRecord values; /* Defines positioning
487 * value(s)--applied to all glyphs in
488 * the Coverage table */
489 public:
490 DEFINE_SIZE_ARRAY (6, values);
493 struct SinglePosFormat2
495 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
497 TRACE_COLLECT_GLYPHS (this);
498 (this+coverage).add_coverage (c->input);
501 inline const Coverage &get_coverage (void) const
503 return this+coverage;
506 inline bool apply (hb_apply_context_t *c) const
508 TRACE_APPLY (this);
509 hb_buffer_t *buffer = c->buffer;
510 unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
511 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
513 if (likely (index >= valueCount)) return TRACE_RETURN (false);
515 valueFormat.apply_value (c->font, c->direction, this,
516 &values[index * valueFormat.get_len ()],
517 buffer->cur_pos());
519 buffer->idx++;
520 return TRACE_RETURN (true);
523 inline bool sanitize (hb_sanitize_context_t *c) const
525 TRACE_SANITIZE (this);
526 return TRACE_RETURN (c->check_struct (this)
527 && coverage.sanitize (c, this)
528 && valueFormat.sanitize_values (c, this, values, valueCount));
531 protected:
532 USHORT format; /* Format identifier--format = 2 */
533 OffsetTo<Coverage>
534 coverage; /* Offset to Coverage table--from
535 * beginning of subtable */
536 ValueFormat valueFormat; /* Defines the types of data in the
537 * ValueRecord */
538 USHORT valueCount; /* Number of ValueRecords */
539 ValueRecord values; /* Array of ValueRecords--positioning
540 * values applied to glyphs */
541 public:
542 DEFINE_SIZE_ARRAY (8, values);
545 struct SinglePos
547 template <typename context_t>
548 inline typename context_t::return_t dispatch (context_t *c) const
550 TRACE_DISPATCH (this, u.format);
551 if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
552 switch (u.format) {
553 case 1: return TRACE_RETURN (c->dispatch (u.format1));
554 case 2: return TRACE_RETURN (c->dispatch (u.format2));
555 default:return TRACE_RETURN (c->default_return_value ());
559 protected:
560 union {
561 USHORT format; /* Format identifier */
562 SinglePosFormat1 format1;
563 SinglePosFormat2 format2;
564 } u;
568 struct PairValueRecord
570 friend struct PairSet;
572 protected:
573 GlyphID secondGlyph; /* GlyphID of second glyph in the
574 * pair--first glyph is listed in the
575 * Coverage table */
576 ValueRecord values; /* Positioning data for the first glyph
577 * followed by for second glyph */
578 public:
579 DEFINE_SIZE_ARRAY (2, values);
582 struct PairSet
584 friend struct PairPosFormat1;
586 inline void collect_glyphs (hb_collect_glyphs_context_t *c,
587 const ValueFormat *valueFormats) const
589 TRACE_COLLECT_GLYPHS (this);
590 unsigned int len1 = valueFormats[0].get_len ();
591 unsigned int len2 = valueFormats[1].get_len ();
592 unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
594 const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
595 unsigned int count = len;
596 for (unsigned int i = 0; i < count; i++)
598 c->input->add (record->secondGlyph);
599 record = &StructAtOffset<PairValueRecord> (record, record_size);
603 inline bool apply (hb_apply_context_t *c,
604 const ValueFormat *valueFormats,
605 unsigned int pos) const
607 TRACE_APPLY (this);
608 hb_buffer_t *buffer = c->buffer;
609 unsigned int len1 = valueFormats[0].get_len ();
610 unsigned int len2 = valueFormats[1].get_len ();
611 unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
613 const PairValueRecord *record_array = CastP<PairValueRecord> (arrayZ);
614 unsigned int count = len;
616 /* Hand-coded bsearch. */
617 if (unlikely (!count))
618 return TRACE_RETURN (false);
619 hb_codepoint_t x = buffer->info[pos].codepoint;
620 int min = 0, max = (int) count - 1;
621 while (min <= max)
623 int mid = (min + max) / 2;
624 const PairValueRecord *record = &StructAtOffset<PairValueRecord> (record_array, record_size * mid);
625 hb_codepoint_t mid_x = record->secondGlyph;
626 if (x < mid_x)
627 max = mid - 1;
628 else if (x > mid_x)
629 min = mid + 1;
630 else
632 valueFormats[0].apply_value (c->font, c->direction, this,
633 &record->values[0], buffer->cur_pos());
634 valueFormats[1].apply_value (c->font, c->direction, this,
635 &record->values[len1], buffer->pos[pos]);
636 if (len2)
637 pos++;
638 buffer->idx = pos;
639 return TRACE_RETURN (true);
643 return TRACE_RETURN (false);
646 struct sanitize_closure_t {
647 const void *base;
648 const ValueFormat *valueFormats;
649 unsigned int len1; /* valueFormats[0].get_len() */
650 unsigned int stride; /* 1 + len1 + len2 */
653 inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const
655 TRACE_SANITIZE (this);
656 if (!(c->check_struct (this)
657 && c->check_array (arrayZ, USHORT::static_size * closure->stride, len))) return TRACE_RETURN (false);
659 unsigned int count = len;
660 const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
661 return TRACE_RETURN (closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride)
662 && closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride));
665 protected:
666 USHORT len; /* Number of PairValueRecords */
667 USHORT arrayZ[VAR]; /* Array of PairValueRecords--ordered
668 * by GlyphID of the second glyph */
669 public:
670 DEFINE_SIZE_ARRAY (2, arrayZ);
673 struct PairPosFormat1
675 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
677 TRACE_COLLECT_GLYPHS (this);
678 (this+coverage).add_coverage (c->input);
679 unsigned int count = pairSet.len;
680 for (unsigned int i = 0; i < count; i++)
681 (this+pairSet[i]).collect_glyphs (c, &valueFormat1);
684 inline const Coverage &get_coverage (void) const
686 return this+coverage;
689 inline bool apply (hb_apply_context_t *c) const
691 TRACE_APPLY (this);
692 hb_buffer_t *buffer = c->buffer;
693 unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
694 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
696 hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
697 skippy_iter.reset (buffer->idx, 1);
698 if (!skippy_iter.next ()) return TRACE_RETURN (false);
700 return TRACE_RETURN ((this+pairSet[index]).apply (c, &valueFormat1, skippy_iter.idx));
703 inline bool sanitize (hb_sanitize_context_t *c) const
705 TRACE_SANITIZE (this);
707 unsigned int len1 = valueFormat1.get_len ();
708 unsigned int len2 = valueFormat2.get_len ();
709 PairSet::sanitize_closure_t closure = {
710 this,
711 &valueFormat1,
712 len1,
713 1 + len1 + len2
716 return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
719 protected:
720 USHORT format; /* Format identifier--format = 1 */
721 OffsetTo<Coverage>
722 coverage; /* Offset to Coverage table--from
723 * beginning of subtable */
724 ValueFormat valueFormat1; /* Defines the types of data in
725 * ValueRecord1--for the first glyph
726 * in the pair--may be zero (0) */
727 ValueFormat valueFormat2; /* Defines the types of data in
728 * ValueRecord2--for the second glyph
729 * in the pair--may be zero (0) */
730 OffsetArrayOf<PairSet>
731 pairSet; /* Array of PairSet tables
732 * ordered by Coverage Index */
733 public:
734 DEFINE_SIZE_ARRAY (10, pairSet);
737 struct PairPosFormat2
739 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
741 TRACE_COLLECT_GLYPHS (this);
742 /* (this+coverage).add_coverage (c->input); // Don't need this. */
744 unsigned int count1 = class1Count;
745 const ClassDef &klass1 = this+classDef1;
746 for (unsigned int i = 0; i < count1; i++)
747 klass1.add_class (c->input, i);
749 unsigned int count2 = class2Count;
750 const ClassDef &klass2 = this+classDef2;
751 for (unsigned int i = 0; i < count2; i++)
752 klass2.add_class (c->input, i);
755 inline const Coverage &get_coverage (void) const
757 return this+coverage;
760 inline bool apply (hb_apply_context_t *c) const
762 TRACE_APPLY (this);
763 hb_buffer_t *buffer = c->buffer;
764 unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
765 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
767 hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
768 skippy_iter.reset (buffer->idx, 1);
769 if (!skippy_iter.next ()) return TRACE_RETURN (false);
771 unsigned int len1 = valueFormat1.get_len ();
772 unsigned int len2 = valueFormat2.get_len ();
773 unsigned int record_len = len1 + len2;
775 unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint);
776 unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint);
777 if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return TRACE_RETURN (false);
779 const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
780 valueFormat1.apply_value (c->font, c->direction, this,
781 v, buffer->cur_pos());
782 valueFormat2.apply_value (c->font, c->direction, this,
783 v + len1, buffer->pos[skippy_iter.idx]);
785 buffer->idx = skippy_iter.idx;
786 if (len2)
787 buffer->idx++;
789 return TRACE_RETURN (true);
792 inline bool sanitize (hb_sanitize_context_t *c) const
794 TRACE_SANITIZE (this);
795 if (!(c->check_struct (this)
796 && coverage.sanitize (c, this)
797 && classDef1.sanitize (c, this)
798 && classDef2.sanitize (c, this))) return TRACE_RETURN (false);
800 unsigned int len1 = valueFormat1.get_len ();
801 unsigned int len2 = valueFormat2.get_len ();
802 unsigned int stride = len1 + len2;
803 unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
804 unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
805 return TRACE_RETURN (c->check_array (values, record_size, count) &&
806 valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
807 valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride));
810 protected:
811 USHORT format; /* Format identifier--format = 2 */
812 OffsetTo<Coverage>
813 coverage; /* Offset to Coverage table--from
814 * beginning of subtable */
815 ValueFormat valueFormat1; /* ValueRecord definition--for the
816 * first glyph of the pair--may be zero
817 * (0) */
818 ValueFormat valueFormat2; /* ValueRecord definition--for the
819 * second glyph of the pair--may be
820 * zero (0) */
821 OffsetTo<ClassDef>
822 classDef1; /* Offset to ClassDef table--from
823 * beginning of PairPos subtable--for
824 * the first glyph of the pair */
825 OffsetTo<ClassDef>
826 classDef2; /* Offset to ClassDef table--from
827 * beginning of PairPos subtable--for
828 * the second glyph of the pair */
829 USHORT class1Count; /* Number of classes in ClassDef1
830 * table--includes Class0 */
831 USHORT class2Count; /* Number of classes in ClassDef2
832 * table--includes Class0 */
833 ValueRecord values; /* Matrix of value pairs:
834 * class1-major, class2-minor,
835 * Each entry has value1 and value2 */
836 public:
837 DEFINE_SIZE_ARRAY (16, values);
840 struct PairPos
842 template <typename context_t>
843 inline typename context_t::return_t dispatch (context_t *c) const
845 TRACE_DISPATCH (this, u.format);
846 if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
847 switch (u.format) {
848 case 1: return TRACE_RETURN (c->dispatch (u.format1));
849 case 2: return TRACE_RETURN (c->dispatch (u.format2));
850 default:return TRACE_RETURN (c->default_return_value ());
854 protected:
855 union {
856 USHORT format; /* Format identifier */
857 PairPosFormat1 format1;
858 PairPosFormat2 format2;
859 } u;
863 struct EntryExitRecord
865 friend struct CursivePosFormat1;
867 inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
869 TRACE_SANITIZE (this);
870 return TRACE_RETURN (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
873 protected:
874 OffsetTo<Anchor>
875 entryAnchor; /* Offset to EntryAnchor table--from
876 * beginning of CursivePos
877 * subtable--may be NULL */
878 OffsetTo<Anchor>
879 exitAnchor; /* Offset to ExitAnchor table--from
880 * beginning of CursivePos
881 * subtable--may be NULL */
882 public:
883 DEFINE_SIZE_STATIC (4);
886 struct CursivePosFormat1
888 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
890 TRACE_COLLECT_GLYPHS (this);
891 (this+coverage).add_coverage (c->input);
894 inline const Coverage &get_coverage (void) const
896 return this+coverage;
899 inline bool apply (hb_apply_context_t *c) const
901 TRACE_APPLY (this);
902 hb_buffer_t *buffer = c->buffer;
904 /* We don't handle mark glyphs here. */
905 if (unlikely (_hb_glyph_info_is_mark (&buffer->cur()))) return TRACE_RETURN (false);
907 const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage (buffer->cur().codepoint)];
908 if (!this_record.exitAnchor) return TRACE_RETURN (false);
910 hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
911 skippy_iter.reset (buffer->idx, 1);
912 if (!skippy_iter.next ()) return TRACE_RETURN (false);
914 const EntryExitRecord &next_record = entryExitRecord[(this+coverage).get_coverage (buffer->info[skippy_iter.idx].codepoint)];
915 if (!next_record.entryAnchor) return TRACE_RETURN (false);
917 unsigned int i = buffer->idx;
918 unsigned int j = skippy_iter.idx;
920 hb_position_t entry_x, entry_y, exit_x, exit_y;
921 (this+this_record.exitAnchor).get_anchor (c->font, buffer->info[i].codepoint, &exit_x, &exit_y);
922 (this+next_record.entryAnchor).get_anchor (c->font, buffer->info[j].codepoint, &entry_x, &entry_y);
924 hb_glyph_position_t *pos = buffer->pos;
926 hb_position_t d;
927 /* Main-direction adjustment */
928 switch (c->direction) {
929 case HB_DIRECTION_LTR:
930 pos[i].x_advance = exit_x + pos[i].x_offset;
932 d = entry_x + pos[j].x_offset;
933 pos[j].x_advance -= d;
934 pos[j].x_offset -= d;
935 break;
936 case HB_DIRECTION_RTL:
937 d = exit_x + pos[i].x_offset;
938 pos[i].x_advance -= d;
939 pos[i].x_offset -= d;
941 pos[j].x_advance = entry_x + pos[j].x_offset;
942 break;
943 case HB_DIRECTION_TTB:
944 pos[i].y_advance = exit_y + pos[i].y_offset;
946 d = entry_y + pos[j].y_offset;
947 pos[j].y_advance -= d;
948 pos[j].y_offset -= d;
949 break;
950 case HB_DIRECTION_BTT:
951 d = exit_y + pos[i].y_offset;
952 pos[i].y_advance -= d;
953 pos[i].y_offset -= d;
955 pos[j].y_advance = entry_y;
956 break;
957 case HB_DIRECTION_INVALID:
958 default:
959 break;
962 /* Cross-direction adjustment */
963 if (c->lookup_props & LookupFlag::RightToLeft) {
964 pos[i].cursive_chain() = j - i;
965 if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
966 pos[i].y_offset = entry_y - exit_y;
967 else
968 pos[i].x_offset = entry_x - exit_x;
969 } else {
970 pos[j].cursive_chain() = i - j;
971 if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
972 pos[j].y_offset = exit_y - entry_y;
973 else
974 pos[j].x_offset = exit_x - entry_x;
977 buffer->idx = j;
978 return TRACE_RETURN (true);
981 inline bool sanitize (hb_sanitize_context_t *c) const
983 TRACE_SANITIZE (this);
984 return TRACE_RETURN (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
987 protected:
988 USHORT format; /* Format identifier--format = 1 */
989 OffsetTo<Coverage>
990 coverage; /* Offset to Coverage table--from
991 * beginning of subtable */
992 ArrayOf<EntryExitRecord>
993 entryExitRecord; /* Array of EntryExit records--in
994 * Coverage Index order */
995 public:
996 DEFINE_SIZE_ARRAY (6, entryExitRecord);
999 struct CursivePos
1001 template <typename context_t>
1002 inline typename context_t::return_t dispatch (context_t *c) const
1004 TRACE_DISPATCH (this, u.format);
1005 if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
1006 switch (u.format) {
1007 case 1: return TRACE_RETURN (c->dispatch (u.format1));
1008 default:return TRACE_RETURN (c->default_return_value ());
1012 protected:
1013 union {
1014 USHORT format; /* Format identifier */
1015 CursivePosFormat1 format1;
1016 } u;
1020 typedef AnchorMatrix BaseArray; /* base-major--
1021 * in order of BaseCoverage Index--,
1022 * mark-minor--
1023 * ordered by class--zero-based. */
1025 struct MarkBasePosFormat1
1027 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1029 TRACE_COLLECT_GLYPHS (this);
1030 (this+markCoverage).add_coverage (c->input);
1031 (this+baseCoverage).add_coverage (c->input);
1034 inline const Coverage &get_coverage (void) const
1036 return this+markCoverage;
1039 inline bool apply (hb_apply_context_t *c) const
1041 TRACE_APPLY (this);
1042 hb_buffer_t *buffer = c->buffer;
1043 unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint);
1044 if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
1046 /* now we search backwards for a non-mark glyph */
1047 hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
1048 skippy_iter.reset (buffer->idx, 1);
1049 skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
1050 do {
1051 if (!skippy_iter.prev ()) return TRACE_RETURN (false);
1052 /* We only want to attach to the first of a MultipleSubst sequence. Reject others. */
1053 if (0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx])) break;
1054 skippy_iter.reject ();
1055 } while (1);
1057 /* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */
1058 if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { /*return TRACE_RETURN (false);*/ }
1060 unsigned int base_index = (this+baseCoverage).get_coverage (buffer->info[skippy_iter.idx].codepoint);
1061 if (base_index == NOT_COVERED) return TRACE_RETURN (false);
1063 return TRACE_RETURN ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx));
1066 inline bool sanitize (hb_sanitize_context_t *c) const
1068 TRACE_SANITIZE (this);
1069 return TRACE_RETURN (c->check_struct (this) && markCoverage.sanitize (c, this) && baseCoverage.sanitize (c, this) &&
1070 markArray.sanitize (c, this) && baseArray.sanitize (c, this, (unsigned int) classCount));
1073 protected:
1074 USHORT format; /* Format identifier--format = 1 */
1075 OffsetTo<Coverage>
1076 markCoverage; /* Offset to MarkCoverage table--from
1077 * beginning of MarkBasePos subtable */
1078 OffsetTo<Coverage>
1079 baseCoverage; /* Offset to BaseCoverage table--from
1080 * beginning of MarkBasePos subtable */
1081 USHORT classCount; /* Number of classes defined for marks */
1082 OffsetTo<MarkArray>
1083 markArray; /* Offset to MarkArray table--from
1084 * beginning of MarkBasePos subtable */
1085 OffsetTo<BaseArray>
1086 baseArray; /* Offset to BaseArray table--from
1087 * beginning of MarkBasePos subtable */
1088 public:
1089 DEFINE_SIZE_STATIC (12);
1092 struct MarkBasePos
1094 template <typename context_t>
1095 inline typename context_t::return_t dispatch (context_t *c) const
1097 TRACE_DISPATCH (this, u.format);
1098 if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
1099 switch (u.format) {
1100 case 1: return TRACE_RETURN (c->dispatch (u.format1));
1101 default:return TRACE_RETURN (c->default_return_value ());
1105 protected:
1106 union {
1107 USHORT format; /* Format identifier */
1108 MarkBasePosFormat1 format1;
1109 } u;
1113 typedef AnchorMatrix LigatureAttach; /* component-major--
1114 * in order of writing direction--,
1115 * mark-minor--
1116 * ordered by class--zero-based. */
1118 typedef OffsetListOf<LigatureAttach> LigatureArray;
1119 /* Array of LigatureAttach
1120 * tables ordered by
1121 * LigatureCoverage Index */
1123 struct MarkLigPosFormat1
1125 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1127 TRACE_COLLECT_GLYPHS (this);
1128 (this+markCoverage).add_coverage (c->input);
1129 (this+ligatureCoverage).add_coverage (c->input);
1132 inline const Coverage &get_coverage (void) const
1134 return this+markCoverage;
1137 inline bool apply (hb_apply_context_t *c) const
1139 TRACE_APPLY (this);
1140 hb_buffer_t *buffer = c->buffer;
1141 unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint);
1142 if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
1144 /* now we search backwards for a non-mark glyph */
1145 hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
1146 skippy_iter.reset (buffer->idx, 1);
1147 skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
1148 if (!skippy_iter.prev ()) return TRACE_RETURN (false);
1150 /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */
1151 if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { /*return TRACE_RETURN (false);*/ }
1153 unsigned int j = skippy_iter.idx;
1154 unsigned int lig_index = (this+ligatureCoverage).get_coverage (buffer->info[j].codepoint);
1155 if (lig_index == NOT_COVERED) return TRACE_RETURN (false);
1157 const LigatureArray& lig_array = this+ligatureArray;
1158 const LigatureAttach& lig_attach = lig_array[lig_index];
1160 /* Find component to attach to */
1161 unsigned int comp_count = lig_attach.rows;
1162 if (unlikely (!comp_count)) return TRACE_RETURN (false);
1164 /* We must now check whether the ligature ID of the current mark glyph
1165 * is identical to the ligature ID of the found ligature. If yes, we
1166 * can directly use the component index. If not, we attach the mark
1167 * glyph to the last component of the ligature. */
1168 unsigned int comp_index;
1169 unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[j]);
1170 unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur());
1171 unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
1172 if (lig_id && lig_id == mark_id && mark_comp > 0)
1173 comp_index = MIN (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1;
1174 else
1175 comp_index = comp_count - 1;
1177 return TRACE_RETURN ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
1180 inline bool sanitize (hb_sanitize_context_t *c) const
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));
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);
1207 struct MarkLigPos
1209 template <typename context_t>
1210 inline typename context_t::return_t dispatch (context_t *c) const
1212 TRACE_DISPATCH (this, u.format);
1213 if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
1214 switch (u.format) {
1215 case 1: return TRACE_RETURN (c->dispatch (u.format1));
1216 default:return TRACE_RETURN (c->default_return_value ());
1220 protected:
1221 union {
1222 USHORT format; /* Format identifier */
1223 MarkLigPosFormat1 format1;
1224 } u;
1228 typedef AnchorMatrix Mark2Array; /* mark2-major--
1229 * in order of Mark2Coverage Index--,
1230 * mark1-minor--
1231 * ordered by class--zero-based. */
1233 struct MarkMarkPosFormat1
1235 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1237 TRACE_COLLECT_GLYPHS (this);
1238 (this+mark1Coverage).add_coverage (c->input);
1239 (this+mark2Coverage).add_coverage (c->input);
1242 inline const Coverage &get_coverage (void) const
1244 return this+mark1Coverage;
1247 inline bool apply (hb_apply_context_t *c) const
1249 TRACE_APPLY (this);
1250 hb_buffer_t *buffer = c->buffer;
1251 unsigned int mark1_index = (this+mark1Coverage).get_coverage (buffer->cur().codepoint);
1252 if (likely (mark1_index == NOT_COVERED)) return TRACE_RETURN (false);
1254 /* now we search backwards for a suitable mark glyph until a non-mark glyph */
1255 hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
1256 skippy_iter.reset (buffer->idx, 1);
1257 skippy_iter.set_lookup_props (c->lookup_props & ~LookupFlag::IgnoreFlags);
1258 if (!skippy_iter.prev ()) return TRACE_RETURN (false);
1260 if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])) { return TRACE_RETURN (false); }
1262 unsigned int j = skippy_iter.idx;
1264 unsigned int id1 = _hb_glyph_info_get_lig_id (&buffer->cur());
1265 unsigned int id2 = _hb_glyph_info_get_lig_id (&buffer->info[j]);
1266 unsigned int comp1 = _hb_glyph_info_get_lig_comp (&buffer->cur());
1267 unsigned int comp2 = _hb_glyph_info_get_lig_comp (&buffer->info[j]);
1269 if (likely (id1 == id2)) {
1270 if (id1 == 0) /* Marks belonging to the same base. */
1271 goto good;
1272 else if (comp1 == comp2) /* Marks belonging to the same ligature component. */
1273 goto good;
1274 } else {
1275 /* If ligature ids don't match, it may be the case that one of the marks
1276 * itself is a ligature. In which case match. */
1277 if ((id1 > 0 && !comp1) || (id2 > 0 && !comp2))
1278 goto good;
1281 /* Didn't match. */
1282 return TRACE_RETURN (false);
1284 good:
1285 unsigned int mark2_index = (this+mark2Coverage).get_coverage (buffer->info[j].codepoint);
1286 if (mark2_index == NOT_COVERED) return TRACE_RETURN (false);
1288 return TRACE_RETURN ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j));
1291 inline bool sanitize (hb_sanitize_context_t *c) const
1293 TRACE_SANITIZE (this);
1294 return TRACE_RETURN (c->check_struct (this) && mark1Coverage.sanitize (c, this) &&
1295 mark2Coverage.sanitize (c, this) && mark1Array.sanitize (c, this)
1296 && mark2Array.sanitize (c, this, (unsigned int) classCount));
1299 protected:
1300 USHORT format; /* Format identifier--format = 1 */
1301 OffsetTo<Coverage>
1302 mark1Coverage; /* Offset to Combining Mark1 Coverage
1303 * table--from beginning of MarkMarkPos
1304 * subtable */
1305 OffsetTo<Coverage>
1306 mark2Coverage; /* Offset to Combining Mark2 Coverage
1307 * table--from beginning of MarkMarkPos
1308 * subtable */
1309 USHORT classCount; /* Number of defined mark classes */
1310 OffsetTo<MarkArray>
1311 mark1Array; /* Offset to Mark1Array table--from
1312 * beginning of MarkMarkPos subtable */
1313 OffsetTo<Mark2Array>
1314 mark2Array; /* Offset to Mark2Array table--from
1315 * beginning of MarkMarkPos subtable */
1316 public:
1317 DEFINE_SIZE_STATIC (12);
1320 struct MarkMarkPos
1322 template <typename context_t>
1323 inline typename context_t::return_t dispatch (context_t *c) const
1325 TRACE_DISPATCH (this, u.format);
1326 if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
1327 switch (u.format) {
1328 case 1: return TRACE_RETURN (c->dispatch (u.format1));
1329 default:return TRACE_RETURN (c->default_return_value ());
1333 protected:
1334 union {
1335 USHORT format; /* Format identifier */
1336 MarkMarkPosFormat1 format1;
1337 } u;
1341 struct ContextPos : Context {};
1343 struct ChainContextPos : ChainContext {};
1345 struct ExtensionPos : Extension<ExtensionPos>
1347 typedef struct PosLookupSubTable LookupSubTable;
1353 * PosLookup
1357 struct PosLookupSubTable
1359 friend struct PosLookup;
1361 enum Type {
1362 Single = 1,
1363 Pair = 2,
1364 Cursive = 3,
1365 MarkBase = 4,
1366 MarkLig = 5,
1367 MarkMark = 6,
1368 Context = 7,
1369 ChainContext = 8,
1370 Extension = 9
1373 template <typename context_t>
1374 inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
1376 TRACE_DISPATCH (this, lookup_type);
1377 /* The sub_format passed to may_dispatch is unnecessary but harmless. */
1378 if (unlikely (!c->may_dispatch (this, &u.sub_format))) TRACE_RETURN (c->default_return_value ());
1379 switch (lookup_type) {
1380 case Single: return TRACE_RETURN (u.single.dispatch (c));
1381 case Pair: return TRACE_RETURN (u.pair.dispatch (c));
1382 case Cursive: return TRACE_RETURN (u.cursive.dispatch (c));
1383 case MarkBase: return TRACE_RETURN (u.markBase.dispatch (c));
1384 case MarkLig: return TRACE_RETURN (u.markLig.dispatch (c));
1385 case MarkMark: return TRACE_RETURN (u.markMark.dispatch (c));
1386 case Context: return TRACE_RETURN (u.context.dispatch (c));
1387 case ChainContext: return TRACE_RETURN (u.chainContext.dispatch (c));
1388 case Extension: return TRACE_RETURN (u.extension.dispatch (c));
1389 default: return TRACE_RETURN (c->default_return_value ());
1393 protected:
1394 union {
1395 USHORT sub_format;
1396 SinglePos single;
1397 PairPos pair;
1398 CursivePos cursive;
1399 MarkBasePos markBase;
1400 MarkLigPos markLig;
1401 MarkMarkPos markMark;
1402 ContextPos context;
1403 ChainContextPos chainContext;
1404 ExtensionPos extension;
1405 } u;
1406 public:
1407 DEFINE_SIZE_UNION (2, sub_format);
1411 struct PosLookup : Lookup
1413 inline const PosLookupSubTable& get_subtable (unsigned int i) const
1414 { return Lookup::get_subtable<PosLookupSubTable> (i); }
1416 inline bool is_reverse (void) const
1418 return false;
1421 inline bool apply (hb_apply_context_t *c) const
1423 TRACE_APPLY (this);
1424 return TRACE_RETURN (dispatch (c));
1427 inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
1429 TRACE_COLLECT_GLYPHS (this);
1430 return TRACE_RETURN (dispatch (c));
1433 template <typename set_t>
1434 inline void add_coverage (set_t *glyphs) const
1436 hb_add_coverage_context_t<set_t> c (glyphs);
1437 dispatch (&c);
1440 static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
1442 template <typename context_t>
1443 static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
1445 template <typename context_t>
1446 inline typename context_t::return_t dispatch (context_t *c) const
1447 { return Lookup::dispatch<PosLookupSubTable> (c); }
1449 inline bool sanitize (hb_sanitize_context_t *c) const
1451 TRACE_SANITIZE (this);
1452 if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
1453 const OffsetArrayOf<PosLookupSubTable> &list = get_subtables<PosLookupSubTable> ();
1454 return TRACE_RETURN (dispatch (c));
1458 typedef OffsetListOf<PosLookup> PosLookupList;
1461 * GPOS -- The Glyph Positioning Table
1464 struct GPOS : GSUBGPOS
1466 static const hb_tag_t tableTag = HB_OT_TAG_GPOS;
1468 inline const PosLookup& get_lookup (unsigned int i) const
1469 { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
1471 static inline void position_start (hb_font_t *font, hb_buffer_t *buffer);
1472 static inline void position_finish (hb_font_t *font, hb_buffer_t *buffer);
1474 inline bool sanitize (hb_sanitize_context_t *c) const
1476 TRACE_SANITIZE (this);
1477 if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
1478 const OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
1479 return TRACE_RETURN (list.sanitize (c, this));
1481 public:
1482 DEFINE_SIZE_STATIC (10);
1486 static void
1487 fix_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
1489 unsigned int j = pos[i].cursive_chain();
1490 if (likely (!j))
1491 return;
1493 j += i;
1495 pos[i].cursive_chain() = 0;
1497 fix_cursive_minor_offset (pos, j, direction);
1499 if (HB_DIRECTION_IS_HORIZONTAL (direction))
1500 pos[i].y_offset += pos[j].y_offset;
1501 else
1502 pos[i].x_offset += pos[j].x_offset;
1505 static void
1506 fix_mark_attachment (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
1508 if (likely (!(pos[i].attach_lookback())))
1509 return;
1511 unsigned int j = i - pos[i].attach_lookback();
1513 pos[i].x_offset += pos[j].x_offset;
1514 pos[i].y_offset += pos[j].y_offset;
1516 if (HB_DIRECTION_IS_FORWARD (direction))
1517 for (unsigned int k = j; k < i; k++) {
1518 pos[i].x_offset -= pos[k].x_advance;
1519 pos[i].y_offset -= pos[k].y_advance;
1521 else
1522 for (unsigned int k = j + 1; k < i + 1; k++) {
1523 pos[i].x_offset += pos[k].x_advance;
1524 pos[i].y_offset += pos[k].y_advance;
1528 void
1529 GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
1531 buffer->clear_positions ();
1533 unsigned int count = buffer->len;
1534 for (unsigned int i = 0; i < count; i++)
1535 buffer->pos[i].attach_lookback() = buffer->pos[i].cursive_chain() = 0;
1538 void
1539 GPOS::position_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
1541 _hb_buffer_assert_gsubgpos_vars (buffer);
1543 unsigned int len;
1544 hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
1545 hb_direction_t direction = buffer->props.direction;
1547 /* Handle cursive connections */
1548 for (unsigned int i = 0; i < len; i++)
1549 fix_cursive_minor_offset (pos, i, direction);
1551 /* Handle attachments */
1552 for (unsigned int i = 0; i < len; i++)
1553 fix_mark_attachment (pos, i, direction);
1557 /* Out-of-class implementation for methods recursing */
1559 template <typename context_t>
1560 /*static*/ inline typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
1562 const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
1563 const PosLookup &l = gpos.get_lookup (lookup_index);
1564 return l.dispatch (c);
1567 /*static*/ inline bool PosLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
1569 const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
1570 const PosLookup &l = gpos.get_lookup (lookup_index);
1571 unsigned int saved_lookup_props = c->lookup_props;
1572 c->set_lookup (l);
1573 bool ret = l.dispatch (c);
1574 c->set_lookup_props (saved_lookup_props);
1575 return ret;
1579 #undef attach_lookback
1580 #undef cursive_chain
1583 } /* namespace OT */
1586 #endif /* HB_OT_LAYOUT_GPOS_TABLE_HH */