2 * Copyright © 2007,2008,2009,2010 Red Hat, Inc.
3 * Copyright © 2010,2012 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
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"
36 /* buffer **position** var allocations */
37 #define attach_lookback() var.u16[0] /* number of glyphs to go back to attach this glyph to its base */
38 #define cursive_chain() var.i16[1] /* character to which this connects, may be positive or negative */
41 /* Shared Tables: ValueRecord, Anchor Table, and MarkArray */
45 typedef Value ValueRecord[VAR];
47 struct ValueFormat : USHORT
50 xPlacement = 0x0001, /* Includes horizontal adjustment for placement */
51 yPlacement = 0x0002, /* Includes vertical adjustment for placement */
52 xAdvance = 0x0004, /* Includes horizontal adjustment for advance */
53 yAdvance = 0x0008, /* Includes vertical adjustment for advance */
54 xPlaDevice = 0x0010, /* Includes horizontal Device table for placement */
55 yPlaDevice = 0x0020, /* Includes vertical Device table for placement */
56 xAdvDevice = 0x0040, /* Includes horizontal Device table for advance */
57 yAdvDevice = 0x0080, /* Includes vertical Device table for advance */
58 ignored = 0x0F00, /* Was used in TrueType Open for MM fonts */
59 reserved = 0xF000, /* For future use */
61 devices = 0x00F0 /* Mask for having any Device table */
64 /* All fields are options. Only those available advance the value pointer. */
66 SHORT xPlacement; /* Horizontal adjustment for
67 * placement--in design units */
68 SHORT yPlacement; /* Vertical adjustment for
69 * placement--in design units */
70 SHORT xAdvance; /* Horizontal adjustment for
71 * advance--in design units (only used
72 * for horizontal writing) */
73 SHORT yAdvance; /* Vertical adjustment for advance--in
74 * design units (only used for vertical
76 Offset xPlaDevice; /* Offset to Device table for
77 * horizontal placement--measured from
78 * beginning of PosTable (may be NULL) */
79 Offset yPlaDevice; /* Offset to Device table for vertical
80 * placement--measured from beginning
81 * of PosTable (may be NULL) */
82 Offset xAdvDevice; /* Offset to Device table for
83 * horizontal advance--measured from
84 * beginning of PosTable (may be NULL) */
85 Offset yAdvDevice; /* Offset to Device table for vertical
86 * advance--measured from beginning of
87 * PosTable (may be NULL) */
90 inline unsigned int get_len (void) const
91 { return _hb_popcount32 ((unsigned int) *this); }
92 inline unsigned int get_size (void) const
93 { return get_len () * Value::static_size; }
95 void apply_value (hb_font_t *font,
96 hb_direction_t direction,
99 hb_glyph_position_t &glyph_pos) const
101 unsigned int x_ppem, y_ppem;
102 unsigned int format = *this;
103 hb_bool_t horizontal = HB_DIRECTION_IS_HORIZONTAL (direction);
107 if (format & xPlacement) glyph_pos.x_offset += font->em_scale_x (get_short (values++));
108 if (format & yPlacement) glyph_pos.y_offset += font->em_scale_y (get_short (values++));
109 if (format & xAdvance) {
110 if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values++)); else values++;
112 /* y_advance values grow downward but font-space grows upward, hence negation */
113 if (format & yAdvance) {
114 if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values++)); else values++;
117 if (!has_device ()) return;
119 x_ppem = font->x_ppem;
120 y_ppem = font->y_ppem;
122 if (!x_ppem && !y_ppem) return;
124 /* pixel -> fractional pixel */
125 if (format & xPlaDevice) {
126 if (x_ppem) glyph_pos.x_offset += (base + get_device (values++)).get_x_delta (font); else values++;
128 if (format & yPlaDevice) {
129 if (y_ppem) glyph_pos.y_offset += (base + get_device (values++)).get_y_delta (font); else values++;
131 if (format & xAdvDevice) {
132 if (horizontal && x_ppem) glyph_pos.x_advance += (base + get_device (values++)).get_x_delta (font); else values++;
134 if (format & yAdvDevice) {
135 /* y_advance values grow downward but font-space grows upward, hence negation */
136 if (!horizontal && y_ppem) glyph_pos.y_advance -= (base + get_device (values++)).get_y_delta (font); else values++;
141 inline bool sanitize_value_devices (hb_sanitize_context_t *c, void *base, Value *values) {
142 unsigned int format = *this;
144 if (format & xPlacement) values++;
145 if (format & yPlacement) values++;
146 if (format & xAdvance) values++;
147 if (format & yAdvance) values++;
149 if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
150 if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
151 if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
152 if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
157 static inline OffsetTo<Device>& get_device (Value* value)
158 { return *CastP<OffsetTo<Device> > (value); }
159 static inline const OffsetTo<Device>& get_device (const Value* value)
160 { return *CastP<OffsetTo<Device> > (value); }
162 static inline const SHORT& get_short (const Value* value)
163 { return *CastP<SHORT> (value); }
167 inline bool has_device (void) const {
168 unsigned int format = *this;
169 return (format & devices) != 0;
172 inline bool sanitize_value (hb_sanitize_context_t *c, void *base, Value *values) {
174 return TRACE_RETURN (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values)));
177 inline bool sanitize_values (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count) {
179 unsigned int len = get_len ();
181 if (!c->check_array (values, get_size (), count)) return TRACE_RETURN (false);
183 if (!has_device ()) return TRACE_RETURN (true);
185 for (unsigned int i = 0; i < count; i++) {
186 if (!sanitize_value_devices (c, base, values))
187 return TRACE_RETURN (false);
191 return TRACE_RETURN (true);
194 /* Just sanitize referenced Device tables. Doesn't check the values themselves. */
195 inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count, unsigned int stride) {
198 if (!has_device ()) return TRACE_RETURN (true);
200 for (unsigned int i = 0; i < count; i++) {
201 if (!sanitize_value_devices (c, base, values))
202 return TRACE_RETURN (false);
206 return TRACE_RETURN (true);
213 friend struct Anchor;
216 inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
217 hb_position_t *x, hb_position_t *y) const
219 *x = font->em_scale_x (xCoordinate);
220 *y = font->em_scale_y (yCoordinate);
223 inline bool sanitize (hb_sanitize_context_t *c) {
225 return TRACE_RETURN (c->check_struct (this));
229 USHORT format; /* Format identifier--format = 1 */
230 SHORT xCoordinate; /* Horizontal value--in design units */
231 SHORT yCoordinate; /* Vertical value--in design units */
233 DEFINE_SIZE_STATIC (6);
238 friend struct Anchor;
241 inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
242 hb_position_t *x, hb_position_t *y) const
244 unsigned int x_ppem = font->x_ppem;
245 unsigned int y_ppem = font->y_ppem;
246 hb_position_t cx, cy;
247 hb_bool_t ret = false;
249 if (x_ppem || y_ppem)
250 ret = font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
251 *x = x_ppem && ret ? cx : font->em_scale_x (xCoordinate);
252 *y = y_ppem && ret ? cy : font->em_scale_y (yCoordinate);
255 inline bool sanitize (hb_sanitize_context_t *c) {
257 return TRACE_RETURN (c->check_struct (this));
261 USHORT format; /* Format identifier--format = 2 */
262 SHORT xCoordinate; /* Horizontal value--in design units */
263 SHORT yCoordinate; /* Vertical value--in design units */
264 USHORT anchorPoint; /* Index to glyph contour point */
266 DEFINE_SIZE_STATIC (8);
271 friend struct Anchor;
274 inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
275 hb_position_t *x, hb_position_t *y) const
277 *x = font->em_scale_x (xCoordinate);
278 *y = font->em_scale_y (yCoordinate);
281 *x += (this+xDeviceTable).get_x_delta (font);
283 *y += (this+yDeviceTable).get_x_delta (font);
286 inline bool sanitize (hb_sanitize_context_t *c) {
288 return TRACE_RETURN (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
292 USHORT format; /* Format identifier--format = 3 */
293 SHORT xCoordinate; /* Horizontal value--in design units */
294 SHORT yCoordinate; /* Vertical value--in design units */
296 xDeviceTable; /* Offset to Device table for X
297 * coordinate-- from beginning of
298 * Anchor table (may be NULL) */
300 yDeviceTable; /* Offset to Device table for Y
301 * coordinate-- from beginning of
302 * Anchor table (may be NULL) */
304 DEFINE_SIZE_STATIC (10);
309 inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
310 hb_position_t *x, hb_position_t *y) const
314 case 1: u.format1.get_anchor (font, glyph_id, x, y); return;
315 case 2: u.format2.get_anchor (font, glyph_id, x, y); return;
316 case 3: u.format3.get_anchor (font, glyph_id, x, y); return;
321 inline bool sanitize (hb_sanitize_context_t *c) {
323 if (!u.format.sanitize (c)) return TRACE_RETURN (false);
325 case 1: return TRACE_RETURN (u.format1.sanitize (c));
326 case 2: return TRACE_RETURN (u.format2.sanitize (c));
327 case 3: return TRACE_RETURN (u.format3.sanitize (c));
328 default:return TRACE_RETURN (true);
334 USHORT format; /* Format identifier */
335 AnchorFormat1 format1;
336 AnchorFormat2 format2;
337 AnchorFormat3 format3;
340 DEFINE_SIZE_UNION (2, format);
346 inline const Anchor& get_anchor (unsigned int row, unsigned int col, unsigned int cols) const {
347 if (unlikely (row >= rows || col >= cols)) return Null(Anchor);
348 return this+matrix[row * cols + col];
351 inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) {
353 if (!c->check_struct (this)) return TRACE_RETURN (false);
354 if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return TRACE_RETURN (false);
355 unsigned int count = rows * cols;
356 if (!c->check_array (matrix, matrix[0].static_size, count)) return TRACE_RETURN (false);
357 for (unsigned int i = 0; i < count; i++)
358 if (!matrix[i].sanitize (c, this)) return TRACE_RETURN (false);
359 return TRACE_RETURN (true);
362 USHORT rows; /* Number of rows */
365 matrix[VAR]; /* Matrix of offsets to Anchor tables--
366 * from beginning of AnchorMatrix table */
368 DEFINE_SIZE_ARRAY (2, matrix);
374 friend struct MarkArray;
376 inline bool sanitize (hb_sanitize_context_t *c, void *base) {
378 return TRACE_RETURN (c->check_struct (this) && markAnchor.sanitize (c, base));
382 USHORT klass; /* Class defined for this mark */
384 markAnchor; /* Offset to Anchor table--from
385 * beginning of MarkArray table */
387 DEFINE_SIZE_STATIC (4);
390 struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage order */
392 inline bool apply (hb_apply_context_t *c,
393 unsigned int mark_index, unsigned int glyph_index,
394 const AnchorMatrix &anchors, unsigned int class_count,
395 unsigned int glyph_pos) const
398 const MarkRecord &record = ArrayOf<MarkRecord>::operator[](mark_index);
399 unsigned int mark_class = record.klass;
401 const Anchor& mark_anchor = this + record.markAnchor;
402 const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count);
404 hb_position_t mark_x, mark_y, base_x, base_y;
406 mark_anchor.get_anchor (c->font, c->buffer->cur().codepoint, &mark_x, &mark_y);
407 glyph_anchor.get_anchor (c->font, c->buffer->info[glyph_pos].codepoint, &base_x, &base_y);
409 hb_glyph_position_t &o = c->buffer->cur_pos();
410 o.x_offset = base_x - mark_x;
411 o.y_offset = base_y - mark_y;
412 o.attach_lookback() = c->buffer->idx - glyph_pos;
415 return TRACE_RETURN (true);
418 inline bool sanitize (hb_sanitize_context_t *c) {
420 return TRACE_RETURN (ArrayOf<MarkRecord>::sanitize (c, this));
427 struct SinglePosFormat1
429 friend struct SinglePos;
433 inline const Coverage &get_coverage (void) const
435 return this+coverage;
438 inline bool apply (hb_apply_context_t *c) const
441 unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
442 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
444 valueFormat.apply_value (c->font, c->direction, this,
445 values, c->buffer->cur_pos());
448 return TRACE_RETURN (true);
451 inline bool sanitize (hb_sanitize_context_t *c) {
453 return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && valueFormat.sanitize_value (c, this, values));
457 USHORT format; /* Format identifier--format = 1 */
459 coverage; /* Offset to Coverage table--from
460 * beginning of subtable */
461 ValueFormat valueFormat; /* Defines the types of data in the
463 ValueRecord values; /* Defines positioning
464 * value(s)--applied to all glyphs in
465 * the Coverage table */
467 DEFINE_SIZE_ARRAY (6, values);
470 struct SinglePosFormat2
472 friend struct SinglePos;
476 inline const Coverage &get_coverage (void) const
478 return this+coverage;
481 inline bool apply (hb_apply_context_t *c) const
484 unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
485 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
487 if (likely (index >= valueCount)) return TRACE_RETURN (false);
489 valueFormat.apply_value (c->font, c->direction, this,
490 &values[index * valueFormat.get_len ()],
491 c->buffer->cur_pos());
494 return TRACE_RETURN (true);
497 inline bool sanitize (hb_sanitize_context_t *c) {
499 return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && valueFormat.sanitize_values (c, this, values, valueCount));
503 USHORT format; /* Format identifier--format = 2 */
505 coverage; /* Offset to Coverage table--from
506 * beginning of subtable */
507 ValueFormat valueFormat; /* Defines the types of data in the
509 USHORT valueCount; /* Number of ValueRecords */
510 ValueRecord values; /* Array of ValueRecords--positioning
511 * values applied to glyphs */
513 DEFINE_SIZE_ARRAY (8, values);
518 friend struct PosLookupSubTable;
522 inline const Coverage &get_coverage (void) const
525 case 1: return u.format1.get_coverage ();
526 case 2: return u.format2.get_coverage ();
527 default:return Null(Coverage);
531 inline bool apply (hb_apply_context_t *c) const
535 case 1: return TRACE_RETURN (u.format1.apply (c));
536 case 2: return TRACE_RETURN (u.format2.apply (c));
537 default:return TRACE_RETURN (false);
541 inline bool sanitize (hb_sanitize_context_t *c) {
543 if (!u.format.sanitize (c)) return TRACE_RETURN (false);
545 case 1: return TRACE_RETURN (u.format1.sanitize (c));
546 case 2: return TRACE_RETURN (u.format2.sanitize (c));
547 default:return TRACE_RETURN (true);
553 USHORT format; /* Format identifier */
554 SinglePosFormat1 format1;
555 SinglePosFormat2 format2;
560 struct PairValueRecord
562 friend struct PairSet;
565 GlyphID secondGlyph; /* GlyphID of second glyph in the
566 * pair--first glyph is listed in the
568 ValueRecord values; /* Positioning data for the first glyph
569 * followed by for second glyph */
571 DEFINE_SIZE_ARRAY (2, values);
576 friend struct PairPosFormat1;
578 inline bool apply (hb_apply_context_t *c,
579 const ValueFormat *valueFormats,
580 unsigned int pos) const
583 unsigned int len1 = valueFormats[0].get_len ();
584 unsigned int len2 = valueFormats[1].get_len ();
585 unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
587 unsigned int count = len;
588 const PairValueRecord *record = CastP<PairValueRecord> (array);
589 for (unsigned int i = 0; i < count; i++)
591 if (c->buffer->info[pos].codepoint == record->secondGlyph)
593 valueFormats[0].apply_value (c->font, c->direction, this,
594 &record->values[0], c->buffer->cur_pos());
595 valueFormats[1].apply_value (c->font, c->direction, this,
596 &record->values[len1], c->buffer->pos[pos]);
599 c->buffer->idx = pos;
600 return TRACE_RETURN (true);
602 record = &StructAtOffset<PairValueRecord> (record, record_size);
605 return TRACE_RETURN (false);
608 struct sanitize_closure_t {
610 ValueFormat *valueFormats;
611 unsigned int len1; /* valueFormats[0].get_len() */
612 unsigned int stride; /* 1 + len1 + len2 */
615 inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) {
617 if (!(c->check_struct (this)
618 && c->check_array (array, USHORT::static_size * closure->stride, len))) return TRACE_RETURN (false);
620 unsigned int count = len;
621 PairValueRecord *record = CastP<PairValueRecord> (array);
622 return TRACE_RETURN (closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride)
623 && closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride));
627 USHORT len; /* Number of PairValueRecords */
628 USHORT array[VAR]; /* Array of PairValueRecords--ordered
629 * by GlyphID of the second glyph */
631 DEFINE_SIZE_ARRAY (2, array);
634 struct PairPosFormat1
636 friend struct PairPos;
640 inline const Coverage &get_coverage (void) const
642 return this+coverage;
645 inline bool apply (hb_apply_context_t *c) const
648 hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1);
649 if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
651 unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
652 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
654 if (!skippy_iter.next ()) return TRACE_RETURN (false);
656 return TRACE_RETURN ((this+pairSet[index]).apply (c, &valueFormat1, skippy_iter.idx));
659 inline bool sanitize (hb_sanitize_context_t *c) {
662 unsigned int len1 = valueFormat1.get_len ();
663 unsigned int len2 = valueFormat2.get_len ();
664 PairSet::sanitize_closure_t closure = {
671 return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
675 USHORT format; /* Format identifier--format = 1 */
677 coverage; /* Offset to Coverage table--from
678 * beginning of subtable */
679 ValueFormat valueFormat1; /* Defines the types of data in
680 * ValueRecord1--for the first glyph
681 * in the pair--may be zero (0) */
682 ValueFormat valueFormat2; /* Defines the types of data in
683 * ValueRecord2--for the second glyph
684 * in the pair--may be zero (0) */
685 OffsetArrayOf<PairSet>
686 pairSet; /* Array of PairSet tables
687 * ordered by Coverage Index */
689 DEFINE_SIZE_ARRAY (10, pairSet);
692 struct PairPosFormat2
694 friend struct PairPos;
698 inline const Coverage &get_coverage (void) const
700 return this+coverage;
703 inline bool apply (hb_apply_context_t *c) const
706 hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1);
707 if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
709 unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
710 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
712 if (!skippy_iter.next ()) return TRACE_RETURN (false);
714 unsigned int len1 = valueFormat1.get_len ();
715 unsigned int len2 = valueFormat2.get_len ();
716 unsigned int record_len = len1 + len2;
718 unsigned int klass1 = (this+classDef1) (c->buffer->cur().codepoint);
719 unsigned int klass2 = (this+classDef2) (c->buffer->info[skippy_iter.idx].codepoint);
720 if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return TRACE_RETURN (false);
722 const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
723 valueFormat1.apply_value (c->font, c->direction, this,
724 v, c->buffer->cur_pos());
725 valueFormat2.apply_value (c->font, c->direction, this,
726 v + len1, c->buffer->pos[skippy_iter.idx]);
728 c->buffer->idx = skippy_iter.idx;
732 return TRACE_RETURN (true);
735 inline bool sanitize (hb_sanitize_context_t *c) {
737 if (!(c->check_struct (this)
738 && coverage.sanitize (c, this)
739 && classDef1.sanitize (c, this)
740 && classDef2.sanitize (c, this))) return TRACE_RETURN (false);
742 unsigned int len1 = valueFormat1.get_len ();
743 unsigned int len2 = valueFormat2.get_len ();
744 unsigned int stride = len1 + len2;
745 unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
746 unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
747 return TRACE_RETURN (c->check_array (values, record_size, count) &&
748 valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
749 valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride));
753 USHORT format; /* Format identifier--format = 2 */
755 coverage; /* Offset to Coverage table--from
756 * beginning of subtable */
757 ValueFormat valueFormat1; /* ValueRecord definition--for the
758 * first glyph of the pair--may be zero
760 ValueFormat valueFormat2; /* ValueRecord definition--for the
761 * second glyph of the pair--may be
764 classDef1; /* Offset to ClassDef table--from
765 * beginning of PairPos subtable--for
766 * the first glyph of the pair */
768 classDef2; /* Offset to ClassDef table--from
769 * beginning of PairPos subtable--for
770 * the second glyph of the pair */
771 USHORT class1Count; /* Number of classes in ClassDef1
772 * table--includes Class0 */
773 USHORT class2Count; /* Number of classes in ClassDef2
774 * table--includes Class0 */
775 ValueRecord values; /* Matrix of value pairs:
776 * class1-major, class2-minor,
777 * Each entry has value1 and value2 */
779 DEFINE_SIZE_ARRAY (16, values);
784 friend struct PosLookupSubTable;
788 inline const Coverage &get_coverage (void) const
791 case 1: return u.format1.get_coverage ();
792 case 2: return u.format2.get_coverage ();
793 default:return Null(Coverage);
797 inline bool apply (hb_apply_context_t *c) const
801 case 1: return TRACE_RETURN (u.format1.apply (c));
802 case 2: return TRACE_RETURN (u.format2.apply (c));
803 default:return TRACE_RETURN (false);
807 inline bool sanitize (hb_sanitize_context_t *c) {
809 if (!u.format.sanitize (c)) return TRACE_RETURN (false);
811 case 1: return TRACE_RETURN (u.format1.sanitize (c));
812 case 2: return TRACE_RETURN (u.format2.sanitize (c));
813 default:return TRACE_RETURN (true);
819 USHORT format; /* Format identifier */
820 PairPosFormat1 format1;
821 PairPosFormat2 format2;
826 struct EntryExitRecord
828 friend struct CursivePosFormat1;
830 inline bool sanitize (hb_sanitize_context_t *c, void *base) {
832 return TRACE_RETURN (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
837 entryAnchor; /* Offset to EntryAnchor table--from
838 * beginning of CursivePos
839 * subtable--may be NULL */
841 exitAnchor; /* Offset to ExitAnchor table--from
842 * beginning of CursivePos
843 * subtable--may be NULL */
845 DEFINE_SIZE_STATIC (4);
848 struct CursivePosFormat1
850 friend struct CursivePos;
854 inline const Coverage &get_coverage (void) const
856 return this+coverage;
859 inline bool apply (hb_apply_context_t *c) const
863 /* We don't handle mark glyphs here. */
864 if (c->property & HB_OT_LAYOUT_GLYPH_CLASS_MARK) return TRACE_RETURN (false);
866 hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1);
867 if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
869 const EntryExitRecord &this_record = entryExitRecord[(this+coverage) (c->buffer->cur().codepoint)];
870 if (!this_record.exitAnchor) return TRACE_RETURN (false);
872 if (!skippy_iter.next ()) return TRACE_RETURN (false);
874 const EntryExitRecord &next_record = entryExitRecord[(this+coverage) (c->buffer->info[skippy_iter.idx].codepoint)];
875 if (!next_record.entryAnchor) return TRACE_RETURN (false);
877 unsigned int i = c->buffer->idx;
878 unsigned int j = skippy_iter.idx;
880 hb_position_t entry_x, entry_y, exit_x, exit_y;
881 (this+this_record.exitAnchor).get_anchor (c->font, c->buffer->info[i].codepoint, &exit_x, &exit_y);
882 (this+next_record.entryAnchor).get_anchor (c->font, c->buffer->info[j].codepoint, &entry_x, &entry_y);
884 hb_glyph_position_t *pos = c->buffer->pos;
887 /* Main-direction adjustment */
888 switch (c->direction) {
889 case HB_DIRECTION_LTR:
890 pos[i].x_advance = exit_x + pos[i].x_offset;
892 d = entry_x + pos[j].x_offset;
893 pos[j].x_advance -= d;
894 pos[j].x_offset -= d;
896 case HB_DIRECTION_RTL:
897 d = exit_x + pos[i].x_offset;
898 pos[i].x_advance -= d;
899 pos[i].x_offset -= d;
901 pos[j].x_advance = entry_x + pos[j].x_offset;
903 case HB_DIRECTION_TTB:
904 pos[i].y_advance = exit_y + pos[i].y_offset;
906 d = entry_y + pos[j].y_offset;
907 pos[j].y_advance -= d;
908 pos[j].y_offset -= d;
910 case HB_DIRECTION_BTT:
911 d = exit_y + pos[i].y_offset;
912 pos[i].y_advance -= d;
913 pos[i].y_offset -= d;
915 pos[j].y_advance = entry_y;
917 case HB_DIRECTION_INVALID:
922 /* Cross-direction adjustment */
923 if (c->lookup_props & LookupFlag::RightToLeft) {
924 pos[i].cursive_chain() = j - i;
925 if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
926 pos[i].y_offset = entry_y - exit_y;
928 pos[i].x_offset = entry_x - exit_x;
930 pos[j].cursive_chain() = i - j;
931 if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
932 pos[j].y_offset = exit_y - entry_y;
934 pos[j].x_offset = exit_x - entry_x;
938 return TRACE_RETURN (true);
941 inline bool sanitize (hb_sanitize_context_t *c) {
943 return TRACE_RETURN (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
947 USHORT format; /* Format identifier--format = 1 */
949 coverage; /* Offset to Coverage table--from
950 * beginning of subtable */
951 ArrayOf<EntryExitRecord>
952 entryExitRecord; /* Array of EntryExit records--in
953 * Coverage Index order */
955 DEFINE_SIZE_ARRAY (6, entryExitRecord);
960 friend struct PosLookupSubTable;
964 inline const Coverage &get_coverage (void) const
967 case 1: return u.format1.get_coverage ();
968 default:return Null(Coverage);
972 inline bool apply (hb_apply_context_t *c) const
976 case 1: return TRACE_RETURN (u.format1.apply (c));
977 default:return TRACE_RETURN (false);
981 inline bool sanitize (hb_sanitize_context_t *c) {
983 if (!u.format.sanitize (c)) return TRACE_RETURN (false);
985 case 1: return TRACE_RETURN (u.format1.sanitize (c));
986 default:return TRACE_RETURN (true);
992 USHORT format; /* Format identifier */
993 CursivePosFormat1 format1;
998 typedef AnchorMatrix BaseArray; /* base-major--
999 * in order of BaseCoverage Index--,
1001 * ordered by class--zero-based. */
1003 struct MarkBasePosFormat1
1005 friend struct MarkBasePos;
1009 inline const Coverage &get_coverage (void) const
1011 return this+markCoverage;
1014 inline bool apply (hb_apply_context_t *c) const
1017 unsigned int mark_index = (this+markCoverage) (c->buffer->cur().codepoint);
1018 if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
1020 /* now we search backwards for a non-mark glyph */
1021 unsigned int property;
1022 hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1);
1024 if (!skippy_iter.prev (&property, LookupFlag::IgnoreMarks)) return TRACE_RETURN (false);
1025 /* We only want to attach to the first of a MultipleSubst sequence. Reject others. */
1026 if (0 == get_lig_comp (c->buffer->info[skippy_iter.idx])) break;
1027 skippy_iter.reject ();
1030 /* The following assertion is too strong, so we've disabled it. */
1031 if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH)) {/*return TRACE_RETURN (false);*/}
1033 unsigned int base_index = (this+baseCoverage) (c->buffer->info[skippy_iter.idx].codepoint);
1034 if (base_index == NOT_COVERED) return TRACE_RETURN (false);
1036 return TRACE_RETURN ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx));
1039 inline bool sanitize (hb_sanitize_context_t *c) {
1041 return TRACE_RETURN (c->check_struct (this) && markCoverage.sanitize (c, this) && baseCoverage.sanitize (c, this) &&
1042 markArray.sanitize (c, this) && baseArray.sanitize (c, this, (unsigned int) classCount));
1046 USHORT format; /* Format identifier--format = 1 */
1048 markCoverage; /* Offset to MarkCoverage table--from
1049 * beginning of MarkBasePos subtable */
1051 baseCoverage; /* Offset to BaseCoverage table--from
1052 * beginning of MarkBasePos subtable */
1053 USHORT classCount; /* Number of classes defined for marks */
1055 markArray; /* Offset to MarkArray table--from
1056 * beginning of MarkBasePos subtable */
1058 baseArray; /* Offset to BaseArray table--from
1059 * beginning of MarkBasePos subtable */
1061 DEFINE_SIZE_STATIC (12);
1066 friend struct PosLookupSubTable;
1070 inline const Coverage &get_coverage (void) const
1073 case 1: return u.format1.get_coverage ();
1074 default:return Null(Coverage);
1078 inline bool apply (hb_apply_context_t *c) const
1082 case 1: return TRACE_RETURN (u.format1.apply (c));
1083 default:return TRACE_RETURN (false);
1087 inline bool sanitize (hb_sanitize_context_t *c) {
1089 if (!u.format.sanitize (c)) return TRACE_RETURN (false);
1091 case 1: return TRACE_RETURN (u.format1.sanitize (c));
1092 default:return TRACE_RETURN (true);
1098 USHORT format; /* Format identifier */
1099 MarkBasePosFormat1 format1;
1104 typedef AnchorMatrix LigatureAttach; /* component-major--
1105 * in order of writing direction--,
1107 * ordered by class--zero-based. */
1109 typedef OffsetListOf<LigatureAttach> LigatureArray;
1110 /* Array of LigatureAttach
1112 * LigatureCoverage Index */
1114 struct MarkLigPosFormat1
1116 friend struct MarkLigPos;
1120 inline const Coverage &get_coverage (void) const
1122 return this+markCoverage;
1125 inline bool apply (hb_apply_context_t *c) const
1128 unsigned int mark_index = (this+markCoverage) (c->buffer->cur().codepoint);
1129 if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
1131 /* now we search backwards for a non-mark glyph */
1132 unsigned int property;
1133 hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1);
1134 if (!skippy_iter.prev (&property, LookupFlag::IgnoreMarks)) return TRACE_RETURN (false);
1136 /* The following assertion is too strong, so we've disabled it. */
1137 if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE)) {/*return TRACE_RETURN (false);*/}
1139 unsigned int j = skippy_iter.idx;
1140 unsigned int lig_index = (this+ligatureCoverage) (c->buffer->info[j].codepoint);
1141 if (lig_index == NOT_COVERED) return TRACE_RETURN (false);
1143 const LigatureArray& lig_array = this+ligatureArray;
1144 const LigatureAttach& lig_attach = lig_array[lig_index];
1146 /* Find component to attach to */
1147 unsigned int comp_count = lig_attach.rows;
1148 if (unlikely (!comp_count)) return TRACE_RETURN (false);
1150 /* We must now check whether the ligature ID of the current mark glyph
1151 * is identical to the ligature ID of the found ligature. If yes, we
1152 * can directly use the component index. If not, we attach the mark
1153 * glyph to the last component of the ligature. */
1154 unsigned int comp_index;
1155 unsigned int lig_id = get_lig_id (c->buffer->info[j]);
1156 unsigned int mark_id = get_lig_id (c->buffer->cur());
1157 unsigned int mark_comp = get_lig_comp (c->buffer->cur());
1158 if (lig_id && lig_id == mark_id && mark_comp > 0)
1159 comp_index = MIN (comp_count, get_lig_comp (c->buffer->cur())) - 1;
1161 comp_index = comp_count - 1;
1163 return TRACE_RETURN ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
1166 inline bool sanitize (hb_sanitize_context_t *c) {
1168 return TRACE_RETURN (c->check_struct (this) && markCoverage.sanitize (c, this) && ligatureCoverage.sanitize (c, this) &&
1169 markArray.sanitize (c, this) && ligatureArray.sanitize (c, this, (unsigned int) classCount));
1173 USHORT format; /* Format identifier--format = 1 */
1175 markCoverage; /* Offset to Mark Coverage table--from
1176 * beginning of MarkLigPos subtable */
1178 ligatureCoverage; /* Offset to Ligature Coverage
1179 * table--from beginning of MarkLigPos
1181 USHORT classCount; /* Number of defined mark classes */
1183 markArray; /* Offset to MarkArray table--from
1184 * beginning of MarkLigPos subtable */
1185 OffsetTo<LigatureArray>
1186 ligatureArray; /* Offset to LigatureArray table--from
1187 * beginning of MarkLigPos subtable */
1189 DEFINE_SIZE_STATIC (12);
1194 friend struct PosLookupSubTable;
1198 inline const Coverage &get_coverage (void) const
1201 case 1: return u.format1.get_coverage ();
1202 default:return Null(Coverage);
1206 inline bool apply (hb_apply_context_t *c) const
1210 case 1: return TRACE_RETURN (u.format1.apply (c));
1211 default:return TRACE_RETURN (false);
1215 inline bool sanitize (hb_sanitize_context_t *c) {
1217 if (!u.format.sanitize (c)) return TRACE_RETURN (false);
1219 case 1: return TRACE_RETURN (u.format1.sanitize (c));
1220 default:return TRACE_RETURN (true);
1226 USHORT format; /* Format identifier */
1227 MarkLigPosFormat1 format1;
1232 typedef AnchorMatrix Mark2Array; /* mark2-major--
1233 * in order of Mark2Coverage Index--,
1235 * ordered by class--zero-based. */
1237 struct MarkMarkPosFormat1
1239 friend struct MarkMarkPos;
1243 inline const Coverage &get_coverage (void) const
1245 return this+mark1Coverage;
1248 inline bool apply (hb_apply_context_t *c) const
1251 unsigned int mark1_index = (this+mark1Coverage) (c->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 unsigned int property;
1256 hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1);
1257 if (!skippy_iter.prev (&property)) return TRACE_RETURN (false);
1259 if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK)) return TRACE_RETURN (false);
1261 unsigned int j = skippy_iter.idx;
1263 unsigned int id1 = get_lig_id (c->buffer->cur());
1264 unsigned int id2 = get_lig_id (c->buffer->info[j]);
1265 unsigned int comp1 = get_lig_comp (c->buffer->cur());
1266 unsigned int comp2 = get_lig_comp (c->buffer->info[j]);
1268 if (likely (id1 == id2)) {
1269 if (id1 == 0) /* Marks belonging to the same base. */
1271 else if (comp1 == comp2) /* Marks belonging to the same ligature component. */
1274 /* If ligature ids don't match, it may be the case that one of the marks
1275 * itself is a ligature. In which case match. */
1276 if ((id1 > 0 && !comp1) || (id2 > 0 && !comp2))
1281 return TRACE_RETURN (false);
1284 unsigned int mark2_index = (this+mark2Coverage) (c->buffer->info[j].codepoint);
1285 if (mark2_index == NOT_COVERED) return TRACE_RETURN (false);
1287 return TRACE_RETURN ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j));
1290 inline bool sanitize (hb_sanitize_context_t *c) {
1292 return TRACE_RETURN (c->check_struct (this) && mark1Coverage.sanitize (c, this) &&
1293 mark2Coverage.sanitize (c, this) && mark1Array.sanitize (c, this)
1294 && mark2Array.sanitize (c, this, (unsigned int) classCount));
1298 USHORT format; /* Format identifier--format = 1 */
1300 mark1Coverage; /* Offset to Combining Mark1 Coverage
1301 * table--from beginning of MarkMarkPos
1304 mark2Coverage; /* Offset to Combining Mark2 Coverage
1305 * table--from beginning of MarkMarkPos
1307 USHORT classCount; /* Number of defined mark classes */
1309 mark1Array; /* Offset to Mark1Array table--from
1310 * beginning of MarkMarkPos subtable */
1311 OffsetTo<Mark2Array>
1312 mark2Array; /* Offset to Mark2Array table--from
1313 * beginning of MarkMarkPos subtable */
1315 DEFINE_SIZE_STATIC (12);
1320 friend struct PosLookupSubTable;
1324 inline const Coverage &get_coverage (void) const
1327 case 1: return u.format1.get_coverage ();
1328 default:return Null(Coverage);
1332 inline bool apply (hb_apply_context_t *c) const
1336 case 1: return TRACE_RETURN (u.format1.apply (c));
1337 default:return TRACE_RETURN (false);
1341 inline bool sanitize (hb_sanitize_context_t *c) {
1343 if (!u.format.sanitize (c)) return TRACE_RETURN (false);
1345 case 1: return TRACE_RETURN (u.format1.sanitize (c));
1346 default:return TRACE_RETURN (true);
1352 USHORT format; /* Format identifier */
1353 MarkMarkPosFormat1 format1;
1358 static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index);
1360 struct ContextPos : Context
1362 friend struct PosLookupSubTable;
1365 inline bool apply (hb_apply_context_t *c) const
1368 return TRACE_RETURN (Context::apply (c, position_lookup));
1372 struct ChainContextPos : ChainContext
1374 friend struct PosLookupSubTable;
1377 inline bool apply (hb_apply_context_t *c) const
1380 return TRACE_RETURN (ChainContext::apply (c, position_lookup));
1385 struct ExtensionPos : Extension
1387 friend struct PosLookupSubTable;
1390 inline const struct PosLookupSubTable& get_subtable (void) const
1392 unsigned int offset = get_offset ();
1393 if (unlikely (!offset)) return Null(PosLookupSubTable);
1394 return StructAtOffset<PosLookupSubTable> (this, offset);
1397 inline const Coverage &get_coverage (void) const;
1399 inline bool apply (hb_apply_context_t *c) const;
1401 inline bool sanitize (hb_sanitize_context_t *c);
1411 struct PosLookupSubTable
1413 friend struct PosLookup;
1427 inline const Coverage &get_coverage (unsigned int lookup_type) const
1429 switch (lookup_type) {
1430 case Single: return u.single.get_coverage ();
1431 case Pair: return u.pair.get_coverage ();
1432 case Cursive: return u.cursive.get_coverage ();
1433 case MarkBase: return u.markBase.get_coverage ();
1434 case MarkLig: return u.markLig.get_coverage ();
1435 case MarkMark: return u.markMark.get_coverage ();
1436 case Context: return u.context.get_coverage ();
1437 case ChainContext: return u.chainContext.get_coverage ();
1438 case Extension: return u.extension.get_coverage ();
1439 default: return Null(Coverage);
1443 inline bool apply (hb_apply_context_t *c, unsigned int lookup_type) const
1446 switch (lookup_type) {
1447 case Single: return TRACE_RETURN (u.single.apply (c));
1448 case Pair: return TRACE_RETURN (u.pair.apply (c));
1449 case Cursive: return TRACE_RETURN (u.cursive.apply (c));
1450 case MarkBase: return TRACE_RETURN (u.markBase.apply (c));
1451 case MarkLig: return TRACE_RETURN (u.markLig.apply (c));
1452 case MarkMark: return TRACE_RETURN (u.markMark.apply (c));
1453 case Context: return TRACE_RETURN (u.context.apply (c));
1454 case ChainContext: return TRACE_RETURN (u.chainContext.apply (c));
1455 case Extension: return TRACE_RETURN (u.extension.apply (c));
1456 default: return TRACE_RETURN (false);
1460 inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
1462 if (!u.header.sub_format.sanitize (c))
1463 return TRACE_RETURN (false);
1464 switch (lookup_type) {
1465 case Single: return TRACE_RETURN (u.single.sanitize (c));
1466 case Pair: return TRACE_RETURN (u.pair.sanitize (c));
1467 case Cursive: return TRACE_RETURN (u.cursive.sanitize (c));
1468 case MarkBase: return TRACE_RETURN (u.markBase.sanitize (c));
1469 case MarkLig: return TRACE_RETURN (u.markLig.sanitize (c));
1470 case MarkMark: return TRACE_RETURN (u.markMark.sanitize (c));
1471 case Context: return TRACE_RETURN (u.context.sanitize (c));
1472 case ChainContext: return TRACE_RETURN (u.chainContext.sanitize (c));
1473 case Extension: return TRACE_RETURN (u.extension.sanitize (c));
1474 default: return TRACE_RETURN (true);
1486 MarkBasePos markBase;
1488 MarkMarkPos markMark;
1490 ChainContextPos chainContext;
1491 ExtensionPos extension;
1494 DEFINE_SIZE_UNION (2, header.sub_format);
1498 struct PosLookup : Lookup
1500 inline const PosLookupSubTable& get_subtable (unsigned int i) const
1501 { return this+CastR<OffsetArrayOf<PosLookupSubTable> > (subTable)[i]; }
1503 template <typename set_t>
1504 inline void add_coverage (set_t *glyphs) const
1506 const Coverage *last = NULL;
1507 unsigned int count = get_subtable_count ();
1508 for (unsigned int i = 0; i < count; i++) {
1509 const Coverage *c = &get_subtable (i).get_coverage (get_type ());
1511 c->add_coverage (glyphs);
1517 inline bool apply_once (hb_apply_context_t *c) const
1519 unsigned int lookup_type = get_type ();
1521 if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props, &c->property))
1524 unsigned int count = get_subtable_count ();
1525 for (unsigned int i = 0; i < count; i++)
1526 if (get_subtable (i).apply (c, lookup_type))
1532 inline bool apply_string (hb_apply_context_t *c) const
1536 if (unlikely (!c->buffer->len))
1539 c->set_lookup (*this);
1543 while (c->buffer->idx < c->buffer->len)
1545 if ((c->buffer->cur().mask & c->lookup_mask) &&
1546 c->digest.may_have (c->buffer->cur().codepoint) &&
1556 inline bool sanitize (hb_sanitize_context_t *c) {
1558 if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
1559 OffsetArrayOf<PosLookupSubTable> &list = CastR<OffsetArrayOf<PosLookupSubTable> > (subTable);
1560 return TRACE_RETURN (list.sanitize (c, this, get_type ()));
1564 typedef OffsetListOf<PosLookup> PosLookupList;
1567 * GPOS -- The Glyph Positioning Table
1570 struct GPOS : GSUBGPOS
1572 static const hb_tag_t Tag = HB_OT_TAG_GPOS;
1574 inline const PosLookup& get_lookup (unsigned int i) const
1575 { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
1577 template <typename set_t>
1578 inline void add_coverage (set_t *glyphs, unsigned int lookup_index) const
1579 { get_lookup (lookup_index).add_coverage (glyphs); }
1581 inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index) const
1582 { return get_lookup (lookup_index).apply_string (c); }
1584 static inline void position_start (hb_font_t *font, hb_buffer_t *buffer);
1585 static inline void position_finish (hb_font_t *font, hb_buffer_t *buffer, hb_bool_t zero_width_attahced_marks);
1587 inline bool sanitize (hb_sanitize_context_t *c) {
1589 if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
1590 OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
1591 return TRACE_RETURN (list.sanitize (c, this));
1594 DEFINE_SIZE_STATIC (10);
1599 fix_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
1601 unsigned int j = pos[i].cursive_chain();
1607 pos[i].cursive_chain() = 0;
1609 fix_cursive_minor_offset (pos, j, direction);
1611 if (HB_DIRECTION_IS_HORIZONTAL (direction))
1612 pos[i].y_offset += pos[j].y_offset;
1614 pos[i].x_offset += pos[j].x_offset;
1618 fix_mark_attachment (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, hb_bool_t zero_width_attached_marks)
1620 if (likely (!(pos[i].attach_lookback())))
1623 unsigned int j = i - pos[i].attach_lookback();
1625 if (zero_width_attached_marks) {
1626 pos[i].x_advance = 0;
1627 pos[i].y_advance = 0;
1629 pos[i].x_offset += pos[j].x_offset;
1630 pos[i].y_offset += pos[j].y_offset;
1632 if (HB_DIRECTION_IS_FORWARD (direction))
1633 for (unsigned int k = j; k < i; k++) {
1634 pos[i].x_offset -= pos[k].x_advance;
1635 pos[i].y_offset -= pos[k].y_advance;
1638 for (unsigned int k = j + 1; k < i + 1; k++) {
1639 pos[i].x_offset += pos[k].x_advance;
1640 pos[i].y_offset += pos[k].y_advance;
1645 GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
1647 buffer->clear_positions ();
1649 unsigned int count = buffer->len;
1650 for (unsigned int i = 0; i < count; i++)
1651 buffer->pos[i].attach_lookback() = buffer->pos[i].cursive_chain() = 0;
1655 GPOS::position_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer, hb_bool_t zero_width_attached_marks)
1658 hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
1659 hb_direction_t direction = buffer->props.direction;
1661 /* Handle cursive connections */
1662 for (unsigned int i = 0; i < len; i++)
1663 fix_cursive_minor_offset (pos, i, direction);
1665 /* Handle attachments */
1666 for (unsigned int i = 0; i < len; i++)
1667 fix_mark_attachment (pos, i, direction, zero_width_attached_marks);
1669 HB_BUFFER_DEALLOCATE_VAR (buffer, syllable);
1670 HB_BUFFER_DEALLOCATE_VAR (buffer, lig_props);
1671 HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_props);
1675 /* Out-of-class implementation for methods recursing */
1677 inline const Coverage & ExtensionPos::get_coverage (void) const
1679 return get_subtable ().get_coverage (get_type ());
1682 inline bool ExtensionPos::apply (hb_apply_context_t *c) const
1685 return TRACE_RETURN (get_subtable ().apply (c, get_type ()));
1688 inline bool ExtensionPos::sanitize (hb_sanitize_context_t *c)
1691 if (unlikely (!Extension::sanitize (c))) return TRACE_RETURN (false);
1692 unsigned int offset = get_offset ();
1693 if (unlikely (!offset)) return TRACE_RETURN (true);
1694 return TRACE_RETURN (StructAtOffset<PosLookupSubTable> (this, offset).sanitize (c, get_type ()));
1697 static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index)
1699 const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
1700 const PosLookup &l = gpos.get_lookup (lookup_index);
1702 if (unlikely (c->nesting_level_left == 0))
1705 hb_apply_context_t new_c (*c);
1706 new_c.nesting_level_left--;
1707 new_c.set_lookup (l);
1708 return l.apply_once (&new_c);
1712 #undef attach_lookback
1713 #undef cursive_chain
1717 #endif /* HB_OT_LAYOUT_GPOS_TABLE_HH */