2 * Copyright (C) 2007,2008,2009,2010 Red Hat, Inc.
4 * This is part of HarfBuzz, a text shaping library.
6 * Permission is hereby granted, without written agreement and without
7 * license or royalty fees, to use, copy, modify, and distribute this
8 * software and its documentation for any purpose, provided that the
9 * above copyright notice and the following two paragraphs appear in
10 * all copies of this software.
12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24 * Red Hat Author(s): Behdad Esfahbod
27 #ifndef HB_OT_LAYOUT_GPOS_PRIVATE_HH
28 #define HB_OT_LAYOUT_GPOS_PRIVATE_HH
30 #include "hb-ot-layout-gsubgpos-private.hh"
35 #define HB_OT_LAYOUT_GPOS_NO_LAST ((unsigned int) -1)
37 /* Shared Tables: ValueRecord, Anchor Table, and MarkArray */
41 typedef Value ValueRecord[VAR];
43 struct ValueFormat : USHORT
47 xPlacement = 0x0001, /* Includes horizontal adjustment for placement */
48 yPlacement = 0x0002, /* Includes vertical adjustment for placement */
49 xAdvance = 0x0004, /* Includes horizontal adjustment for advance */
50 yAdvance = 0x0008, /* Includes vertical adjustment for advance */
51 xPlaDevice = 0x0010, /* Includes horizontal Device table for placement */
52 yPlaDevice = 0x0020, /* Includes vertical Device table for placement */
53 xAdvDevice = 0x0040, /* Includes horizontal Device table for advance */
54 yAdvDevice = 0x0080, /* Includes vertical Device table for advance */
55 ignored = 0x0F00, /* Was used in TrueType Open for MM fonts */
56 reserved = 0xF000, /* For future use */
58 devices = 0x00F0 /* Mask for having any Device table */
61 /* All fields are options. Only those available advance the value pointer. */
63 SHORT xPlacement; /* Horizontal adjustment for
64 * placement--in design units */
65 SHORT yPlacement; /* Vertical adjustment for
66 * placement--in design units */
67 SHORT xAdvance; /* Horizontal adjustment for
68 * advance--in design units (only used
69 * for horizontal writing) */
70 SHORT yAdvance; /* Vertical adjustment for advance--in
71 * design units (only used for vertical
73 Offset xPlaDevice; /* Offset to Device table for
74 * horizontal placement--measured from
75 * beginning of PosTable (may be NULL) */
76 Offset yPlaDevice; /* Offset to Device table for vertical
77 * placement--measured from beginning
78 * of PosTable (may be NULL) */
79 Offset xAdvDevice; /* Offset to Device table for
80 * horizontal advance--measured from
81 * beginning of PosTable (may be NULL) */
82 Offset yAdvDevice; /* Offset to Device table for vertical
83 * advance--measured from beginning of
84 * PosTable (may be NULL) */
87 inline unsigned int get_len (void) const
88 { return _hb_popcount32 ((unsigned int) *this); }
89 inline unsigned int get_size (void) const
90 { return get_len () * Value::static_size; }
92 void apply_value (hb_ot_layout_context_t *layout,
95 hb_internal_glyph_position_t &glyph_pos) const
97 unsigned int x_ppem, y_ppem;
98 unsigned int format = *this;
102 /* design units -> fractional pixel */
103 if (format & xPlacement) glyph_pos.x_offset += layout->scale_x (get_short (values++));
104 if (format & yPlacement) glyph_pos.y_offset += layout->scale_y (get_short (values++));
105 if (format & xAdvance) glyph_pos.x_advance += layout->scale_x (get_short (values++));
106 if (format & yAdvance) glyph_pos.y_advance += layout->scale_y (get_short (values++));
108 if (!has_device ()) return;
110 x_ppem = layout->font->x_ppem;
111 y_ppem = layout->font->y_ppem;
113 if (!x_ppem && !y_ppem) return;
115 /* pixel -> fractional pixel */
116 if (format & xPlaDevice) {
117 if (x_ppem) glyph_pos.x_offset += (base + get_device (values++)).get_x_delta (layout); else values++;
119 if (format & yPlaDevice) {
120 if (y_ppem) glyph_pos.y_offset += (base + get_device (values++)).get_y_delta (layout); else values++;
122 if (format & xAdvDevice) {
123 if (x_ppem) glyph_pos.x_advance += (base + get_device (values++)).get_x_delta (layout); else values++;
125 if (format & yAdvDevice) {
126 if (y_ppem) glyph_pos.y_advance += (base + get_device (values++)).get_y_delta (layout); else values++;
131 inline bool sanitize_value_devices (hb_sanitize_context_t *c, void *base, Value *values) {
132 unsigned int format = *this;
134 if (format & xPlacement) values++;
135 if (format & yPlacement) values++;
136 if (format & xAdvance) values++;
137 if (format & yAdvance) values++;
139 if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
140 if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
141 if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
142 if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
147 static inline OffsetTo<Device>& get_device (Value* value)
148 { return *CastP<OffsetTo<Device> > (value); }
149 static inline const OffsetTo<Device>& get_device (const Value* value)
150 { return *CastP<OffsetTo<Device> > (value); }
152 static inline const SHORT& get_short (const Value* value)
153 { return *CastP<SHORT> (value); }
157 inline bool has_device (void) const {
158 unsigned int format = *this;
159 return (format & devices) != 0;
162 inline bool sanitize_value (hb_sanitize_context_t *c, void *base, Value *values) {
164 return c->check_range (values, get_size ())
165 && (!has_device () || sanitize_value_devices (c, base, values));
168 inline bool sanitize_values (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count) {
170 unsigned int len = get_len ();
172 if (!c->check_array (values, get_size (), count)) return false;
174 if (!has_device ()) return true;
176 for (unsigned int i = 0; i < count; i++) {
177 if (!sanitize_value_devices (c, base, values))
185 /* Just sanitize referenced Device tables. Doesn't check the values themselves. */
186 inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count, unsigned int stride) {
189 if (!has_device ()) return true;
191 for (unsigned int i = 0; i < count; i++) {
192 if (!sanitize_value_devices (c, base, values))
204 friend struct Anchor;
207 inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id HB_UNUSED,
208 hb_position_t *x, hb_position_t *y) const
210 *x = layout->scale_x (xCoordinate);
211 *y = layout->scale_y (yCoordinate);
214 inline bool sanitize (hb_sanitize_context_t *c) {
216 return c->check_struct (this);
220 USHORT format; /* Format identifier--format = 1 */
221 SHORT xCoordinate; /* Horizontal value--in design units */
222 SHORT yCoordinate; /* Vertical value--in design units */
224 DEFINE_SIZE_STATIC (6);
229 friend struct Anchor;
232 inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id,
233 hb_position_t *x, hb_position_t *y) const
235 unsigned int x_ppem = layout->font->x_ppem;
236 unsigned int y_ppem = layout->font->y_ppem;
237 hb_position_t cx, cy;
240 if (x_ppem || y_ppem)
241 ret = hb_font_get_contour_point (layout->font, layout->face, anchorPoint, glyph_id, &cx, &cy);
242 *x = x_ppem && ret ? cx : layout->scale_x (xCoordinate);
243 *y = y_ppem && ret ? cy : layout->scale_y (yCoordinate);
246 inline bool sanitize (hb_sanitize_context_t *c) {
248 return c->check_struct (this);
252 USHORT format; /* Format identifier--format = 2 */
253 SHORT xCoordinate; /* Horizontal value--in design units */
254 SHORT yCoordinate; /* Vertical value--in design units */
255 USHORT anchorPoint; /* Index to glyph contour point */
257 DEFINE_SIZE_STATIC (8);
262 friend struct Anchor;
265 inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id HB_UNUSED,
266 hb_position_t *x, hb_position_t *y) const
268 *x = layout->scale_x (xCoordinate);
269 *y = layout->scale_y (yCoordinate);
271 /* pixel -> fractional pixel */
272 if (layout->font->x_ppem)
273 *x += (this+xDeviceTable).get_x_delta (layout);
274 if (layout->font->y_ppem)
275 *y += (this+yDeviceTable).get_x_delta (layout);
278 inline bool sanitize (hb_sanitize_context_t *c) {
280 return c->check_struct (this)
281 && xDeviceTable.sanitize (c, this)
282 && yDeviceTable.sanitize (c, this);
286 USHORT format; /* Format identifier--format = 3 */
287 SHORT xCoordinate; /* Horizontal value--in design units */
288 SHORT yCoordinate; /* Vertical value--in design units */
290 xDeviceTable; /* Offset to Device table for X
291 * coordinate-- from beginning of
292 * Anchor table (may be NULL) */
294 yDeviceTable; /* Offset to Device table for Y
295 * coordinate-- from beginning of
296 * Anchor table (may be NULL) */
298 DEFINE_SIZE_STATIC (10);
303 inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id,
304 hb_position_t *x, hb_position_t *y) const
308 case 1: u.format1.get_anchor (layout, glyph_id, x, y); return;
309 case 2: u.format2.get_anchor (layout, glyph_id, x, y); return;
310 case 3: u.format3.get_anchor (layout, glyph_id, x, y); return;
315 inline bool sanitize (hb_sanitize_context_t *c) {
317 if (!u.format.sanitize (c)) return false;
319 case 1: return u.format1.sanitize (c);
320 case 2: return u.format2.sanitize (c);
321 case 3: return u.format3.sanitize (c);
328 USHORT format; /* Format identifier */
329 AnchorFormat1 format1;
330 AnchorFormat2 format2;
331 AnchorFormat3 format3;
334 DEFINE_SIZE_UNION (2, format);
340 inline const Anchor& get_anchor (unsigned int row, unsigned int col, unsigned int cols) const {
341 if (unlikely (row >= rows || col >= cols)) return Null(Anchor);
342 return this+matrix[row * cols + col];
345 inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) {
347 if (!c->check_struct (this)) return false;
348 if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return false;
349 unsigned int count = rows * cols;
350 if (!c->check_array (matrix, matrix[0].static_size, count)) return false;
351 for (unsigned int i = 0; i < count; i++)
352 if (!matrix[i].sanitize (c, this)) return false;
356 USHORT rows; /* Number of rows */
359 matrix[VAR]; /* Matrix of offsets to Anchor tables--
360 * from beginning of AnchorMatrix table */
362 DEFINE_SIZE_ARRAY (2, matrix);
368 friend struct MarkArray;
370 inline bool sanitize (hb_sanitize_context_t *c, void *base) {
372 return c->check_struct (this)
373 && markAnchor.sanitize (c, base);
377 USHORT klass; /* Class defined for this mark */
379 markAnchor; /* Offset to Anchor table--from
380 * beginning of MarkArray table */
382 DEFINE_SIZE_STATIC (4);
385 struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage order */
387 inline bool apply (hb_apply_context_t *c,
388 unsigned int mark_index, unsigned int glyph_index,
389 const AnchorMatrix &anchors, unsigned int class_count,
390 unsigned int glyph_pos) const
393 const MarkRecord &record = ArrayOf<MarkRecord>::operator[](mark_index);
394 unsigned int mark_class = record.klass;
396 const Anchor& mark_anchor = this + record.markAnchor;
397 const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count);
399 hb_position_t mark_x, mark_y, base_x, base_y;
401 mark_anchor.get_anchor (c->layout, c->buffer->info[c->buffer->i].codepoint, &mark_x, &mark_y);
402 glyph_anchor.get_anchor (c->layout, c->buffer->info[glyph_pos].codepoint, &base_x, &base_y);
404 hb_internal_glyph_position_t &o = c->buffer->pos[c->buffer->i];
405 o.x_offset = base_x - mark_x;
406 o.y_offset = base_y - mark_y;
407 o.back = c->buffer->i - glyph_pos;
413 inline bool sanitize (hb_sanitize_context_t *c) {
415 return ArrayOf<MarkRecord>::sanitize (c, this);
422 struct SinglePosFormat1
424 friend struct SinglePos;
427 inline bool apply (hb_apply_context_t *c) const
430 unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
431 if (likely (index == NOT_COVERED))
434 valueFormat.apply_value (c->layout, this, values, c->buffer->pos[c->buffer->i]);
440 inline bool sanitize (hb_sanitize_context_t *c) {
442 return c->check_struct (this)
443 && coverage.sanitize (c, this)
444 && valueFormat.sanitize_value (c, this, values);
448 USHORT format; /* Format identifier--format = 1 */
450 coverage; /* Offset to Coverage table--from
451 * beginning of subtable */
452 ValueFormat valueFormat; /* Defines the types of data in the
454 ValueRecord values; /* Defines positioning
455 * value(s)--applied to all glyphs in
456 * the Coverage table */
458 DEFINE_SIZE_ARRAY (6, values);
461 struct SinglePosFormat2
463 friend struct SinglePos;
466 inline bool apply (hb_apply_context_t *c) const
469 unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
470 if (likely (index == NOT_COVERED))
473 if (likely (index >= valueCount))
476 valueFormat.apply_value (c->layout, this,
477 &values[index * valueFormat.get_len ()],
478 c->buffer->pos[c->buffer->i]);
484 inline bool sanitize (hb_sanitize_context_t *c) {
486 return c->check_struct (this)
487 && coverage.sanitize (c, this)
488 && valueFormat.sanitize_values (c, this, values, valueCount);
492 USHORT format; /* Format identifier--format = 2 */
494 coverage; /* Offset to Coverage table--from
495 * beginning of subtable */
496 ValueFormat valueFormat; /* Defines the types of data in the
498 USHORT valueCount; /* Number of ValueRecords */
499 ValueRecord values; /* Array of ValueRecords--positioning
500 * values applied to glyphs */
502 DEFINE_SIZE_ARRAY (8, values);
507 friend struct PosLookupSubTable;
510 inline bool apply (hb_apply_context_t *c) const
514 case 1: return u.format1.apply (c);
515 case 2: return u.format2.apply (c);
516 default:return false;
520 inline bool sanitize (hb_sanitize_context_t *c) {
522 if (!u.format.sanitize (c)) return false;
524 case 1: return u.format1.sanitize (c);
525 case 2: return u.format2.sanitize (c);
532 USHORT format; /* Format identifier */
533 SinglePosFormat1 format1;
534 SinglePosFormat2 format2;
539 struct PairValueRecord
541 friend struct PairSet;
544 GlyphID secondGlyph; /* GlyphID of second glyph in the
545 * pair--first glyph is listed in the
547 ValueRecord values; /* Positioning data for the first glyph
548 * followed by for second glyph */
550 DEFINE_SIZE_ARRAY (2, values);
555 friend struct PairPosFormat1;
557 inline bool apply (hb_apply_context_t *c,
558 const ValueFormat *valueFormats,
559 unsigned int pos) const
562 unsigned int len1 = valueFormats[0].get_len ();
563 unsigned int len2 = valueFormats[1].get_len ();
564 unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
566 unsigned int count = len;
567 const PairValueRecord *record = CastP<PairValueRecord> (array);
568 for (unsigned int i = 0; i < count; i++)
570 if (c->buffer->info[pos].codepoint == record->secondGlyph)
572 valueFormats[0].apply_value (c->layout, this, &record->values[0], c->buffer->pos[c->buffer->i]);
573 valueFormats[1].apply_value (c->layout, this, &record->values[len1], c->buffer->pos[pos]);
579 record = &StructAtOffset<PairValueRecord> (record, record_size);
585 struct sanitize_closure_t {
587 ValueFormat *valueFormats;
588 unsigned int len1; /* valueFormats[0].get_len() */
589 unsigned int stride; /* 1 + len1 + len2 */
592 inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) {
594 if (!(c->check_struct (this)
595 && c->check_array (array, USHORT::static_size * closure->stride, len))) return false;
597 unsigned int count = len;
598 PairValueRecord *record = CastP<PairValueRecord> (array);
599 return closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride)
600 && closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride);
604 USHORT len; /* Number of PairValueRecords */
605 USHORT array[VAR]; /* Array of PairValueRecords--ordered
606 * by GlyphID of the second glyph */
608 DEFINE_SIZE_ARRAY (2, array);
611 struct PairPosFormat1
613 friend struct PairPos;
616 inline bool apply (hb_apply_context_t *c) const
619 unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length);
620 if (unlikely (c->buffer->i + 2 > end))
623 unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
624 if (likely (index == NOT_COVERED))
627 unsigned int j = c->buffer->i + 1;
628 while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_flag, NULL))
630 if (unlikely (j == end))
635 return (this+pairSet[index]).apply (c, &valueFormat1, j);
638 inline bool sanitize (hb_sanitize_context_t *c) {
641 unsigned int len1 = valueFormat1.get_len ();
642 unsigned int len2 = valueFormat2.get_len ();
643 PairSet::sanitize_closure_t closure = {
650 return c->check_struct (this)
651 && coverage.sanitize (c, this)
652 && pairSet.sanitize (c, this, &closure);
656 USHORT format; /* Format identifier--format = 1 */
658 coverage; /* Offset to Coverage table--from
659 * beginning of subtable */
660 ValueFormat valueFormat1; /* Defines the types of data in
661 * ValueRecord1--for the first glyph
662 * in the pair--may be zero (0) */
663 ValueFormat valueFormat2; /* Defines the types of data in
664 * ValueRecord2--for the second glyph
665 * in the pair--may be zero (0) */
666 OffsetArrayOf<PairSet>
667 pairSet; /* Array of PairSet tables
668 * ordered by Coverage Index */
670 DEFINE_SIZE_ARRAY (10, pairSet);
673 struct PairPosFormat2
675 friend struct PairPos;
678 inline bool apply (hb_apply_context_t *c) const
681 unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length);
682 if (unlikely (c->buffer->i + 2 > end))
685 unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
686 if (likely (index == NOT_COVERED))
689 unsigned int j = c->buffer->i + 1;
690 while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_flag, NULL))
692 if (unlikely (j == end))
697 unsigned int len1 = valueFormat1.get_len ();
698 unsigned int len2 = valueFormat2.get_len ();
699 unsigned int record_len = len1 + len2;
701 unsigned int klass1 = (this+classDef1) (c->buffer->info[c->buffer->i].codepoint);
702 unsigned int klass2 = (this+classDef2) (c->buffer->info[j].codepoint);
703 if (unlikely (klass1 >= class1Count || klass2 >= class2Count))
706 const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
707 valueFormat1.apply_value (c->layout, this, v, c->buffer->pos[c->buffer->i]);
708 valueFormat2.apply_value (c->layout, this, v + len1, c->buffer->pos[j]);
717 inline bool sanitize (hb_sanitize_context_t *c) {
719 if (!(c->check_struct (this)
720 && coverage.sanitize (c, this)
721 && classDef1.sanitize (c, this)
722 && classDef2.sanitize (c, this))) return false;
724 unsigned int len1 = valueFormat1.get_len ();
725 unsigned int len2 = valueFormat2.get_len ();
726 unsigned int stride = len1 + len2;
727 unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
728 unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
729 return c->check_array (values, record_size, count) &&
730 valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
731 valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride);
735 USHORT format; /* Format identifier--format = 2 */
737 coverage; /* Offset to Coverage table--from
738 * beginning of subtable */
739 ValueFormat valueFormat1; /* ValueRecord definition--for the
740 * first glyph of the pair--may be zero
742 ValueFormat valueFormat2; /* ValueRecord definition--for the
743 * second glyph of the pair--may be
746 classDef1; /* Offset to ClassDef table--from
747 * beginning of PairPos subtable--for
748 * the first glyph of the pair */
750 classDef2; /* Offset to ClassDef table--from
751 * beginning of PairPos subtable--for
752 * the second glyph of the pair */
753 USHORT class1Count; /* Number of classes in ClassDef1
754 * table--includes Class0 */
755 USHORT class2Count; /* Number of classes in ClassDef2
756 * table--includes Class0 */
757 ValueRecord values; /* Matrix of value pairs:
758 * class1-major, class2-minor,
759 * Each entry has value1 and value2 */
761 DEFINE_SIZE_ARRAY (16, values);
766 friend struct PosLookupSubTable;
769 inline bool apply (hb_apply_context_t *c) const
773 case 1: return u.format1.apply (c);
774 case 2: return u.format2.apply (c);
775 default:return false;
779 inline bool sanitize (hb_sanitize_context_t *c) {
781 if (!u.format.sanitize (c)) return false;
783 case 1: return u.format1.sanitize (c);
784 case 2: return u.format2.sanitize (c);
791 USHORT format; /* Format identifier */
792 PairPosFormat1 format1;
793 PairPosFormat2 format2;
798 struct EntryExitRecord
800 friend struct CursivePosFormat1;
802 inline bool sanitize (hb_sanitize_context_t *c, void *base) {
804 return entryAnchor.sanitize (c, base)
805 && exitAnchor.sanitize (c, base);
810 entryAnchor; /* Offset to EntryAnchor table--from
811 * beginning of CursivePos
812 * subtable--may be NULL */
814 exitAnchor; /* Offset to ExitAnchor table--from
815 * beginning of CursivePos
816 * subtable--may be NULL */
818 DEFINE_SIZE_STATIC (4);
821 struct CursivePosFormat1
823 friend struct CursivePos;
826 inline bool apply (hb_apply_context_t *c) const
829 struct hb_ot_layout_context_t::info_t::gpos_t *gpi = &c->layout->info.gpos;
830 hb_codepoint_t last_pos = gpi->last;
831 gpi->last = HB_OT_LAYOUT_GPOS_NO_LAST;
833 /* We don't handle mark glyphs here. */
834 if (c->property == HB_OT_LAYOUT_GLYPH_CLASS_MARK)
837 unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
838 if (likely (index == NOT_COVERED))
841 const EntryExitRecord &record = entryExitRecord[index];
843 if (last_pos == HB_OT_LAYOUT_GPOS_NO_LAST || !record.entryAnchor)
846 hb_position_t entry_x, entry_y;
847 (this+record.entryAnchor).get_anchor (c->layout, c->buffer->info[c->buffer->i].codepoint, &entry_x, &entry_y);
851 /* Align the exit anchor of the left glyph with the entry anchor of the right glyph. */
852 if (c->buffer->props.direction == HB_DIRECTION_RTL)
854 c->buffer->pos[c->buffer->i].x_advance = c->buffer->pos[c->buffer->i].x_offset + entry_x - gpi->anchor_x;
858 c->buffer->pos[last_pos].x_advance = c->buffer->pos[last_pos].x_advance + gpi->anchor_x - entry_x;
861 if (c->lookup_flag & LookupFlag::RightToLeft)
863 c->buffer->pos[last_pos].cursive_chain = last_pos - c->buffer->i;
864 c->buffer->pos[last_pos].y_offset = entry_y - gpi->anchor_y;
868 c->buffer->pos[c->buffer->i].cursive_chain = c->buffer->i - last_pos;
869 c->buffer->pos[c->buffer->i].y_offset = gpi->anchor_y - entry_y;
873 if (record.exitAnchor)
875 gpi->last = c->buffer->i;
876 (this+record.exitAnchor).get_anchor (c->layout, c->buffer->info[c->buffer->i].codepoint, &gpi->anchor_x, &gpi->anchor_y);
883 inline bool sanitize (hb_sanitize_context_t *c) {
885 return coverage.sanitize (c, this)
886 && entryExitRecord.sanitize (c, this);
890 USHORT format; /* Format identifier--format = 1 */
892 coverage; /* Offset to Coverage table--from
893 * beginning of subtable */
894 ArrayOf<EntryExitRecord>
895 entryExitRecord; /* Array of EntryExit records--in
896 * Coverage Index order */
898 DEFINE_SIZE_ARRAY (6, entryExitRecord);
903 friend struct PosLookupSubTable;
906 inline bool apply (hb_apply_context_t *c) const
910 case 1: return u.format1.apply (c);
911 default:return false;
915 inline bool sanitize (hb_sanitize_context_t *c) {
917 if (!u.format.sanitize (c)) return false;
919 case 1: return u.format1.sanitize (c);
926 USHORT format; /* Format identifier */
927 CursivePosFormat1 format1;
932 typedef AnchorMatrix BaseArray; /* base-major--
933 * in order of BaseCoverage Index--,
935 * ordered by class--zero-based. */
937 struct MarkBasePosFormat1
939 friend struct MarkBasePos;
942 inline bool apply (hb_apply_context_t *c) const
945 unsigned int mark_index = (this+markCoverage) (c->buffer->info[c->buffer->i].codepoint);
946 if (likely (mark_index == NOT_COVERED))
949 /* now we search backwards for a non-mark glyph */
950 unsigned int property;
951 unsigned int j = c->buffer->i;
957 } while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], LookupFlag::IgnoreMarks, &property));
959 /* The following assertion is too strong, so we've disabled it. */
960 if (false && !(property & HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH))
963 unsigned int base_index = (this+baseCoverage) (c->buffer->info[j].codepoint);
964 if (base_index == NOT_COVERED)
967 return (this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, j);
970 inline bool sanitize (hb_sanitize_context_t *c) {
972 return c->check_struct (this)
973 && markCoverage.sanitize (c, this)
974 && baseCoverage.sanitize (c, this)
975 && markArray.sanitize (c, this)
976 && baseArray.sanitize (c, this, (unsigned int) classCount);
980 USHORT format; /* Format identifier--format = 1 */
982 markCoverage; /* Offset to MarkCoverage table--from
983 * beginning of MarkBasePos subtable */
985 baseCoverage; /* Offset to BaseCoverage table--from
986 * beginning of MarkBasePos subtable */
987 USHORT classCount; /* Number of classes defined for marks */
989 markArray; /* Offset to MarkArray table--from
990 * beginning of MarkBasePos subtable */
992 baseArray; /* Offset to BaseArray table--from
993 * beginning of MarkBasePos subtable */
995 DEFINE_SIZE_STATIC (12);
1000 friend struct PosLookupSubTable;
1003 inline bool apply (hb_apply_context_t *c) const
1007 case 1: return u.format1.apply (c);
1008 default:return false;
1012 inline bool sanitize (hb_sanitize_context_t *c) {
1014 if (!u.format.sanitize (c)) return false;
1016 case 1: return u.format1.sanitize (c);
1017 default:return true;
1023 USHORT format; /* Format identifier */
1024 MarkBasePosFormat1 format1;
1029 typedef AnchorMatrix LigatureAttach; /* component-major--
1030 * in order of writing direction--,
1032 * ordered by class--zero-based. */
1034 typedef OffsetListOf<LigatureAttach> LigatureArray;
1035 /* Array of LigatureAttach
1037 * LigatureCoverage Index */
1039 struct MarkLigPosFormat1
1041 friend struct MarkLigPos;
1044 inline bool apply (hb_apply_context_t *c) const
1047 unsigned int mark_index = (this+markCoverage) (c->buffer->info[c->buffer->i].codepoint);
1048 if (likely (mark_index == NOT_COVERED))
1051 /* now we search backwards for a non-mark glyph */
1052 unsigned int property;
1053 unsigned int j = c->buffer->i;
1059 } while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], LookupFlag::IgnoreMarks, &property));
1061 /* The following assertion is too strong, so we've disabled it. */
1062 if (false && !(property & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE))
1065 unsigned int lig_index = (this+ligatureCoverage) (c->buffer->info[j].codepoint);
1066 if (lig_index == NOT_COVERED)
1069 const LigatureArray& lig_array = this+ligatureArray;
1070 const LigatureAttach& lig_attach = lig_array[lig_index];
1072 /* Find component to attach to */
1073 unsigned int comp_count = lig_attach.rows;
1074 if (unlikely (!comp_count))
1076 unsigned int comp_index;
1077 /* We must now check whether the ligature ID of the current mark glyph
1078 * is identical to the ligature ID of the found ligature. If yes, we
1079 * can directly use the component index. If not, we attach the mark
1080 * glyph to the last component of the ligature. */
1081 if (c->buffer->info[j].lig_id && c->buffer->info[j].lig_id == c->buffer->info[c->buffer->i].lig_id && c->buffer->info[c->buffer->i].component)
1083 comp_index = c->buffer->info[c->buffer->i].component - 1;
1084 if (comp_index >= comp_count)
1085 comp_index = comp_count - 1;
1088 comp_index = comp_count - 1;
1090 return (this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j);
1093 inline bool sanitize (hb_sanitize_context_t *c) {
1095 return c->check_struct (this)
1096 && markCoverage.sanitize (c, this)
1097 && ligatureCoverage.sanitize (c, this)
1098 && markArray.sanitize (c, this)
1099 && ligatureArray.sanitize (c, this, (unsigned int) classCount);
1103 USHORT format; /* Format identifier--format = 1 */
1105 markCoverage; /* Offset to Mark Coverage table--from
1106 * beginning of MarkLigPos subtable */
1108 ligatureCoverage; /* Offset to Ligature Coverage
1109 * table--from beginning of MarkLigPos
1111 USHORT classCount; /* Number of defined mark classes */
1113 markArray; /* Offset to MarkArray table--from
1114 * beginning of MarkLigPos subtable */
1115 OffsetTo<LigatureArray>
1116 ligatureArray; /* Offset to LigatureArray table--from
1117 * beginning of MarkLigPos subtable */
1119 DEFINE_SIZE_STATIC (12);
1124 friend struct PosLookupSubTable;
1127 inline bool apply (hb_apply_context_t *c) const
1131 case 1: return u.format1.apply (c);
1132 default:return false;
1136 inline bool sanitize (hb_sanitize_context_t *c) {
1138 if (!u.format.sanitize (c)) return false;
1140 case 1: return u.format1.sanitize (c);
1141 default:return true;
1147 USHORT format; /* Format identifier */
1148 MarkLigPosFormat1 format1;
1153 typedef AnchorMatrix Mark2Array; /* mark2-major--
1154 * in order of Mark2Coverage Index--,
1156 * ordered by class--zero-based. */
1158 struct MarkMarkPosFormat1
1160 friend struct MarkMarkPos;
1163 inline bool apply (hb_apply_context_t *c) const
1166 unsigned int mark1_index = (this+mark1Coverage) (c->buffer->info[c->buffer->i].codepoint);
1167 if (likely (mark1_index == NOT_COVERED))
1170 /* now we search backwards for a suitable mark glyph until a non-mark glyph */
1171 unsigned int property;
1172 unsigned int j = c->buffer->i;
1178 } while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_flag, &property));
1180 if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK))
1183 /* Two marks match only if they belong to the same base, or same component
1184 * of the same ligature. That is, the component numbers must match, and
1185 * if those are non-zero, the ligid number should also match. */
1186 if ((c->buffer->info[j].component != c->buffer->info[c->buffer->i].component) ||
1187 (c->buffer->info[j].component && c->buffer->info[j].lig_id != c->buffer->info[c->buffer->i].lig_id))
1190 unsigned int mark2_index = (this+mark2Coverage) (c->buffer->info[j].codepoint);
1191 if (mark2_index == NOT_COVERED)
1194 return (this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j);
1197 inline bool sanitize (hb_sanitize_context_t *c) {
1199 return c->check_struct (this)
1200 && mark1Coverage.sanitize (c, this)
1201 && mark2Coverage.sanitize (c, this)
1202 && mark1Array.sanitize (c, this)
1203 && mark2Array.sanitize (c, this, (unsigned int) classCount);
1207 USHORT format; /* Format identifier--format = 1 */
1209 mark1Coverage; /* Offset to Combining Mark1 Coverage
1210 * table--from beginning of MarkMarkPos
1213 mark2Coverage; /* Offset to Combining Mark2 Coverage
1214 * table--from beginning of MarkMarkPos
1216 USHORT classCount; /* Number of defined mark classes */
1218 mark1Array; /* Offset to Mark1Array table--from
1219 * beginning of MarkMarkPos subtable */
1220 OffsetTo<Mark2Array>
1221 mark2Array; /* Offset to Mark2Array table--from
1222 * beginning of MarkMarkPos subtable */
1224 DEFINE_SIZE_STATIC (12);
1229 friend struct PosLookupSubTable;
1232 inline bool apply (hb_apply_context_t *c) const
1236 case 1: return u.format1.apply (c);
1237 default:return false;
1241 inline bool sanitize (hb_sanitize_context_t *c) {
1243 if (!u.format.sanitize (c)) return false;
1245 case 1: return u.format1.sanitize (c);
1246 default:return true;
1252 USHORT format; /* Format identifier */
1253 MarkMarkPosFormat1 format1;
1259 static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index);
1262 struct ContextPos : Context
1264 friend struct PosLookupSubTable;
1267 inline bool apply (hb_apply_context_t *c) const
1270 return Context::apply (c, position_lookup);
1274 struct ChainContextPos : ChainContext
1276 friend struct PosLookupSubTable;
1279 inline bool apply (hb_apply_context_t *c) const
1282 return ChainContext::apply (c, position_lookup);
1287 struct ExtensionPos : Extension
1289 friend struct PosLookupSubTable;
1292 inline const struct PosLookupSubTable& get_subtable (void) const
1294 unsigned int offset = get_offset ();
1295 if (unlikely (!offset)) return Null(PosLookupSubTable);
1296 return StructAtOffset<PosLookupSubTable> (this, offset);
1299 inline bool apply (hb_apply_context_t *c) const;
1301 inline bool sanitize (hb_sanitize_context_t *c);
1311 struct PosLookupSubTable
1313 friend struct PosLookup;
1327 inline bool apply (hb_apply_context_t *c, unsigned int lookup_type) const
1330 switch (lookup_type) {
1331 case Single: return u.single.apply (c);
1332 case Pair: return u.pair.apply (c);
1333 case Cursive: return u.cursive.apply (c);
1334 case MarkBase: return u.markBase.apply (c);
1335 case MarkLig: return u.markLig.apply (c);
1336 case MarkMark: return u.markMark.apply (c);
1337 case Context: return u.c.apply (c);
1338 case ChainContext: return u.chainContext.apply (c);
1339 case Extension: return u.extension.apply (c);
1340 default:return false;
1344 inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
1346 switch (lookup_type) {
1347 case Single: return u.single.sanitize (c);
1348 case Pair: return u.pair.sanitize (c);
1349 case Cursive: return u.cursive.sanitize (c);
1350 case MarkBase: return u.markBase.sanitize (c);
1351 case MarkLig: return u.markLig.sanitize (c);
1352 case MarkMark: return u.markMark.sanitize (c);
1353 case Context: return u.c.sanitize (c);
1354 case ChainContext: return u.chainContext.sanitize (c);
1355 case Extension: return u.extension.sanitize (c);
1356 default:return true;
1366 MarkBasePos markBase;
1368 MarkMarkPos markMark;
1370 ChainContextPos chainContext;
1371 ExtensionPos extension;
1374 DEFINE_SIZE_UNION (2, sub_format);
1378 struct PosLookup : Lookup
1380 inline const PosLookupSubTable& get_subtable (unsigned int i) const
1381 { return this+CastR<OffsetArrayOf<PosLookupSubTable> > (subTable)[i]; }
1383 inline bool apply_once (hb_ot_layout_context_t *layout,
1384 hb_buffer_t *buffer,
1385 hb_mask_t lookup_mask,
1386 unsigned int context_length,
1387 unsigned int nesting_level_left) const
1389 unsigned int lookup_type = get_type ();
1390 hb_apply_context_t c[1] = {{0}};
1394 c->lookup_mask = lookup_mask;
1395 c->context_length = context_length;
1396 c->nesting_level_left = nesting_level_left;
1397 c->lookup_flag = get_flag ();
1399 if (!_hb_ot_layout_check_glyph_property (c->layout->face, &c->buffer->info[c->buffer->i], c->lookup_flag, &c->property))
1402 for (unsigned int i = 0; i < get_subtable_count (); i++)
1403 if (get_subtable (i).apply (c, lookup_type))
1409 inline bool apply_string (hb_ot_layout_context_t *layout,
1410 hb_buffer_t *buffer,
1411 hb_mask_t mask) const
1415 if (unlikely (!buffer->len))
1418 layout->info.gpos.last = HB_OT_LAYOUT_GPOS_NO_LAST; /* no last valid glyph for cursive pos. */
1421 while (buffer->i < buffer->len)
1424 if (buffer->info[buffer->i].mask & mask)
1426 done = apply_once (layout, buffer, mask, NO_CONTEXT, MAX_NESTING_LEVEL);
1432 /* Contrary to properties defined in GDEF, user-defined properties
1433 will always stop a possible cursive positioning. */
1434 layout->info.gpos.last = HB_OT_LAYOUT_GPOS_NO_LAST;
1444 inline bool sanitize (hb_sanitize_context_t *c) {
1446 if (unlikely (!Lookup::sanitize (c))) return false;
1447 OffsetArrayOf<PosLookupSubTable> &list = CastR<OffsetArrayOf<PosLookupSubTable> > (subTable);
1448 return list.sanitize (c, this, get_type ());
1452 typedef OffsetListOf<PosLookup> PosLookupList;
1458 struct GPOS : GSUBGPOS
1460 static const hb_tag_t Tag = HB_OT_TAG_GPOS;
1462 inline const PosLookup& get_lookup (unsigned int i) const
1463 { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
1465 inline bool position_lookup (hb_ot_layout_context_t *layout,
1466 hb_buffer_t *buffer,
1467 unsigned int lookup_index,
1468 hb_mask_t mask) const
1469 { return get_lookup (lookup_index).apply_string (layout, buffer, mask); }
1471 inline bool sanitize (hb_sanitize_context_t *c) {
1473 if (unlikely (!GSUBGPOS::sanitize (c))) return false;
1474 OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
1475 return list.sanitize (c, this);
1478 DEFINE_SIZE_STATIC (10);
1482 /* Out-of-class implementation for methods recursing */
1484 inline bool ExtensionPos::apply (hb_apply_context_t *c) const
1487 return get_subtable ().apply (c, get_type ());
1490 inline bool ExtensionPos::sanitize (hb_sanitize_context_t *c)
1493 if (unlikely (!Extension::sanitize (c))) return false;
1494 unsigned int offset = get_offset ();
1495 if (unlikely (!offset)) return true;
1496 return StructAtOffset<PosLookupSubTable> (this, offset).sanitize (c, get_type ());
1499 static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index)
1501 const GPOS &gpos = *(c->layout->face->ot_layout->gpos);
1502 const PosLookup &l = gpos.get_lookup (lookup_index);
1504 if (unlikely (c->nesting_level_left == 0))
1507 if (unlikely (c->context_length < 1))
1510 return l.apply_once (c->layout, c->buffer, c->lookup_mask, c->context_length, c->nesting_level_left - 1);
1516 #endif /* HB_OT_LAYOUT_GPOS_PRIVATE_HH */