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 /* Shared Tables: ValueRecord, Anchor Table, and MarkArray */
39 typedef Value ValueRecord[VAR];
41 struct ValueFormat : USHORT
45 xPlacement = 0x0001, /* Includes horizontal adjustment for placement */
46 yPlacement = 0x0002, /* Includes vertical adjustment for placement */
47 xAdvance = 0x0004, /* Includes horizontal adjustment for advance */
48 yAdvance = 0x0008, /* Includes vertical adjustment for advance */
49 xPlaDevice = 0x0010, /* Includes horizontal Device table for placement */
50 yPlaDevice = 0x0020, /* Includes vertical Device table for placement */
51 xAdvDevice = 0x0040, /* Includes horizontal Device table for advance */
52 yAdvDevice = 0x0080, /* Includes vertical Device table for advance */
53 ignored = 0x0F00, /* Was used in TrueType Open for MM fonts */
54 reserved = 0xF000, /* For future use */
56 devices = 0x00F0 /* Mask for having any Device table */
59 /* All fields are options. Only those available advance the value pointer. */
61 SHORT xPlacement; /* Horizontal adjustment for
62 * placement--in design units */
63 SHORT yPlacement; /* Vertical adjustment for
64 * placement--in design units */
65 SHORT xAdvance; /* Horizontal adjustment for
66 * advance--in design units (only used
67 * for horizontal writing) */
68 SHORT yAdvance; /* Vertical adjustment for advance--in
69 * design units (only used for vertical
71 Offset xPlaDevice; /* Offset to Device table for
72 * horizontal placement--measured from
73 * beginning of PosTable (may be NULL) */
74 Offset yPlaDevice; /* Offset to Device table for vertical
75 * placement--measured from beginning
76 * of PosTable (may be NULL) */
77 Offset xAdvDevice; /* Offset to Device table for
78 * horizontal advance--measured from
79 * beginning of PosTable (may be NULL) */
80 Offset yAdvDevice; /* Offset to Device table for vertical
81 * advance--measured from beginning of
82 * PosTable (may be NULL) */
85 inline unsigned int get_len (void) const
86 { return _hb_popcount32 ((unsigned int) *this); }
87 inline unsigned int get_size (void) const
88 { return get_len () * Value::static_size; }
90 void apply_value (hb_ot_layout_context_t *layout,
93 hb_glyph_position_t &glyph_pos) const
95 unsigned int x_ppem, y_ppem;
96 unsigned int format = *this;
100 /* design units -> fractional pixel */
101 if (format & xPlacement) glyph_pos.x_offset += layout->scale_x (get_short (values++));
102 if (format & yPlacement) glyph_pos.y_offset += layout->scale_y (get_short (values++));
103 if (format & xAdvance) glyph_pos.x_advance += layout->scale_x (get_short (values++));
104 if (format & yAdvance) glyph_pos.y_advance += layout->scale_y (get_short (values++));
106 if (!has_device ()) return;
108 x_ppem = layout->font->x_ppem;
109 y_ppem = layout->font->y_ppem;
111 if (!x_ppem && !y_ppem) return;
113 /* pixel -> fractional pixel */
114 if (format & xPlaDevice) {
115 if (x_ppem) glyph_pos.x_offset += (base + get_device (values++)).get_x_delta (layout); else values++;
117 if (format & yPlaDevice) {
118 if (y_ppem) glyph_pos.y_offset += (base + get_device (values++)).get_y_delta (layout); else values++;
120 if (format & xAdvDevice) {
121 if (x_ppem) glyph_pos.x_advance += (base + get_device (values++)).get_x_delta (layout); else values++;
123 if (format & yAdvDevice) {
124 if (y_ppem) glyph_pos.y_advance += (base + get_device (values++)).get_y_delta (layout); else values++;
129 inline bool sanitize_value_devices (hb_sanitize_context_t *c, void *base, Value *values) {
130 unsigned int format = *this;
132 if (format & xPlacement) values++;
133 if (format & yPlacement) values++;
134 if (format & xAdvance) values++;
135 if (format & yAdvance) values++;
137 if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
138 if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
139 if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
140 if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
145 static inline OffsetTo<Device>& get_device (Value* value)
146 { return *CastP<OffsetTo<Device> > (value); }
147 static inline const OffsetTo<Device>& get_device (const Value* value)
148 { return *CastP<OffsetTo<Device> > (value); }
150 static inline const SHORT& get_short (const Value* value)
151 { return *CastP<SHORT> (value); }
155 inline bool has_device (void) const {
156 unsigned int format = *this;
157 return (format & devices) != 0;
160 inline bool sanitize_value (hb_sanitize_context_t *c, void *base, Value *values) {
162 return c->check_range (values, get_size ())
163 && (!has_device () || sanitize_value_devices (c, base, values));
166 inline bool sanitize_values (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count) {
168 unsigned int len = get_len ();
170 if (!c->check_array (values, get_size (), count)) return false;
172 if (!has_device ()) return true;
174 for (unsigned int i = 0; i < count; i++) {
175 if (!sanitize_value_devices (c, base, values))
183 /* Just sanitize referenced Device tables. Doesn't check the values themselves. */
184 inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count, unsigned int stride) {
187 if (!has_device ()) return true;
189 for (unsigned int i = 0; i < count; i++) {
190 if (!sanitize_value_devices (c, base, values))
202 friend struct Anchor;
205 inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id HB_UNUSED,
206 hb_position_t *x, hb_position_t *y) const
208 *x = layout->scale_x (xCoordinate);
209 *y = layout->scale_y (yCoordinate);
212 inline bool sanitize (hb_sanitize_context_t *c) {
214 return c->check_struct (this);
218 USHORT format; /* Format identifier--format = 1 */
219 SHORT xCoordinate; /* Horizontal value--in design units */
220 SHORT yCoordinate; /* Vertical value--in design units */
222 DEFINE_SIZE_STATIC (6);
227 friend struct Anchor;
230 inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id,
231 hb_position_t *x, hb_position_t *y) const
233 unsigned int x_ppem = layout->font->x_ppem;
234 unsigned int y_ppem = layout->font->y_ppem;
235 hb_position_t cx, cy;
238 if (x_ppem || y_ppem)
239 ret = hb_font_get_contour_point (layout->font, layout->face, anchorPoint, glyph_id, &cx, &cy);
240 *x = x_ppem && ret ? cx : layout->scale_x (xCoordinate);
241 *y = y_ppem && ret ? cy : layout->scale_y (yCoordinate);
244 inline bool sanitize (hb_sanitize_context_t *c) {
246 return c->check_struct (this);
250 USHORT format; /* Format identifier--format = 2 */
251 SHORT xCoordinate; /* Horizontal value--in design units */
252 SHORT yCoordinate; /* Vertical value--in design units */
253 USHORT anchorPoint; /* Index to glyph contour point */
255 DEFINE_SIZE_STATIC (8);
260 friend struct Anchor;
263 inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id HB_UNUSED,
264 hb_position_t *x, hb_position_t *y) const
266 *x = layout->scale_x (xCoordinate);
267 *y = layout->scale_y (yCoordinate);
269 /* pixel -> fractional pixel */
270 if (layout->font->x_ppem)
271 *x += (this+xDeviceTable).get_x_delta (layout);
272 if (layout->font->y_ppem)
273 *y += (this+yDeviceTable).get_x_delta (layout);
276 inline bool sanitize (hb_sanitize_context_t *c) {
278 return c->check_struct (this)
279 && xDeviceTable.sanitize (c, this)
280 && yDeviceTable.sanitize (c, this);
284 USHORT format; /* Format identifier--format = 3 */
285 SHORT xCoordinate; /* Horizontal value--in design units */
286 SHORT yCoordinate; /* Vertical value--in design units */
288 xDeviceTable; /* Offset to Device table for X
289 * coordinate-- from beginning of
290 * Anchor table (may be NULL) */
292 yDeviceTable; /* Offset to Device table for Y
293 * coordinate-- from beginning of
294 * Anchor table (may be NULL) */
296 DEFINE_SIZE_STATIC (10);
301 inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id,
302 hb_position_t *x, hb_position_t *y) const
306 case 1: u.format1.get_anchor (layout, glyph_id, x, y); return;
307 case 2: u.format2.get_anchor (layout, glyph_id, x, y); return;
308 case 3: u.format3.get_anchor (layout, glyph_id, x, y); return;
313 inline bool sanitize (hb_sanitize_context_t *c) {
315 if (!u.format.sanitize (c)) return false;
317 case 1: return u.format1.sanitize (c);
318 case 2: return u.format2.sanitize (c);
319 case 3: return u.format3.sanitize (c);
326 USHORT format; /* Format identifier */
327 AnchorFormat1 format1;
328 AnchorFormat2 format2;
329 AnchorFormat3 format3;
332 DEFINE_SIZE_UNION (2, format);
338 inline const Anchor& get_anchor (unsigned int row, unsigned int col, unsigned int cols) const {
339 if (unlikely (row >= rows || col >= cols)) return Null(Anchor);
340 return this+matrix[row * cols + col];
343 inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) {
345 if (!c->check_struct (this)) return false;
346 if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return false;
347 unsigned int count = rows * cols;
348 if (!c->check_array (matrix, matrix[0].static_size, count)) return false;
349 for (unsigned int i = 0; i < count; i++)
350 if (!matrix[i].sanitize (c, this)) return false;
354 USHORT rows; /* Number of rows */
357 matrix[VAR]; /* Matrix of offsets to Anchor tables--
358 * from beginning of AnchorMatrix table */
360 DEFINE_SIZE_ARRAY (2, matrix);
366 friend struct MarkArray;
368 inline bool sanitize (hb_sanitize_context_t *c, void *base) {
370 return c->check_struct (this)
371 && markAnchor.sanitize (c, base);
375 USHORT klass; /* Class defined for this mark */
377 markAnchor; /* Offset to Anchor table--from
378 * beginning of MarkArray table */
380 DEFINE_SIZE_STATIC (4);
383 struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage order */
385 inline bool apply (hb_apply_context_t *c,
386 unsigned int mark_index, unsigned int glyph_index,
387 const AnchorMatrix &anchors, unsigned int class_count,
388 unsigned int glyph_pos) const
391 const MarkRecord &record = ArrayOf<MarkRecord>::operator[](mark_index);
392 unsigned int mark_class = record.klass;
394 const Anchor& mark_anchor = this + record.markAnchor;
395 const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count);
397 hb_position_t mark_x, mark_y, base_x, base_y;
399 mark_anchor.get_anchor (c->layout, c->buffer->info[c->buffer->i].codepoint, &mark_x, &mark_y);
400 glyph_anchor.get_anchor (c->layout, c->buffer->info[glyph_pos].codepoint, &base_x, &base_y);
402 hb_glyph_position_t &o = c->buffer->pos[c->buffer->i];
403 o.x_offset = base_x - mark_x;
404 o.y_offset = base_y - mark_y;
405 o.back() = c->buffer->i - glyph_pos;
411 inline bool sanitize (hb_sanitize_context_t *c) {
413 return ArrayOf<MarkRecord>::sanitize (c, this);
420 struct SinglePosFormat1
422 friend struct SinglePos;
425 inline bool apply (hb_apply_context_t *c) const
428 unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
429 if (likely (index == NOT_COVERED))
432 valueFormat.apply_value (c->layout, this, values, c->buffer->pos[c->buffer->i]);
438 inline bool sanitize (hb_sanitize_context_t *c) {
440 return c->check_struct (this)
441 && coverage.sanitize (c, this)
442 && valueFormat.sanitize_value (c, this, values);
446 USHORT format; /* Format identifier--format = 1 */
448 coverage; /* Offset to Coverage table--from
449 * beginning of subtable */
450 ValueFormat valueFormat; /* Defines the types of data in the
452 ValueRecord values; /* Defines positioning
453 * value(s)--applied to all glyphs in
454 * the Coverage table */
456 DEFINE_SIZE_ARRAY (6, values);
459 struct SinglePosFormat2
461 friend struct SinglePos;
464 inline bool apply (hb_apply_context_t *c) const
467 unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
468 if (likely (index == NOT_COVERED))
471 if (likely (index >= valueCount))
474 valueFormat.apply_value (c->layout, this,
475 &values[index * valueFormat.get_len ()],
476 c->buffer->pos[c->buffer->i]);
482 inline bool sanitize (hb_sanitize_context_t *c) {
484 return c->check_struct (this)
485 && coverage.sanitize (c, this)
486 && valueFormat.sanitize_values (c, this, values, valueCount);
490 USHORT format; /* Format identifier--format = 2 */
492 coverage; /* Offset to Coverage table--from
493 * beginning of subtable */
494 ValueFormat valueFormat; /* Defines the types of data in the
496 USHORT valueCount; /* Number of ValueRecords */
497 ValueRecord values; /* Array of ValueRecords--positioning
498 * values applied to glyphs */
500 DEFINE_SIZE_ARRAY (8, values);
505 friend struct PosLookupSubTable;
508 inline bool apply (hb_apply_context_t *c) const
512 case 1: return u.format1.apply (c);
513 case 2: return u.format2.apply (c);
514 default:return false;
518 inline bool sanitize (hb_sanitize_context_t *c) {
520 if (!u.format.sanitize (c)) return false;
522 case 1: return u.format1.sanitize (c);
523 case 2: return u.format2.sanitize (c);
530 USHORT format; /* Format identifier */
531 SinglePosFormat1 format1;
532 SinglePosFormat2 format2;
537 struct PairValueRecord
539 friend struct PairSet;
542 GlyphID secondGlyph; /* GlyphID of second glyph in the
543 * pair--first glyph is listed in the
545 ValueRecord values; /* Positioning data for the first glyph
546 * followed by for second glyph */
548 DEFINE_SIZE_ARRAY (2, values);
553 friend struct PairPosFormat1;
555 inline bool apply (hb_apply_context_t *c,
556 const ValueFormat *valueFormats,
557 unsigned int pos) const
560 unsigned int len1 = valueFormats[0].get_len ();
561 unsigned int len2 = valueFormats[1].get_len ();
562 unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
564 unsigned int count = len;
565 const PairValueRecord *record = CastP<PairValueRecord> (array);
566 for (unsigned int i = 0; i < count; i++)
568 if (c->buffer->info[pos].codepoint == record->secondGlyph)
570 valueFormats[0].apply_value (c->layout, this, &record->values[0], c->buffer->pos[c->buffer->i]);
571 valueFormats[1].apply_value (c->layout, this, &record->values[len1], c->buffer->pos[pos]);
577 record = &StructAtOffset<PairValueRecord> (record, record_size);
583 struct sanitize_closure_t {
585 ValueFormat *valueFormats;
586 unsigned int len1; /* valueFormats[0].get_len() */
587 unsigned int stride; /* 1 + len1 + len2 */
590 inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) {
592 if (!(c->check_struct (this)
593 && c->check_array (array, USHORT::static_size * closure->stride, len))) return false;
595 unsigned int count = len;
596 PairValueRecord *record = CastP<PairValueRecord> (array);
597 return closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride)
598 && closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride);
602 USHORT len; /* Number of PairValueRecords */
603 USHORT array[VAR]; /* Array of PairValueRecords--ordered
604 * by GlyphID of the second glyph */
606 DEFINE_SIZE_ARRAY (2, array);
609 struct PairPosFormat1
611 friend struct PairPos;
614 inline bool apply (hb_apply_context_t *c) const
617 unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length);
618 if (unlikely (c->buffer->i + 2 > end))
621 unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
622 if (likely (index == NOT_COVERED))
625 unsigned int j = c->buffer->i + 1;
626 while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_flag, NULL))
628 if (unlikely (j == end))
633 return (this+pairSet[index]).apply (c, &valueFormat1, j);
636 inline bool sanitize (hb_sanitize_context_t *c) {
639 unsigned int len1 = valueFormat1.get_len ();
640 unsigned int len2 = valueFormat2.get_len ();
641 PairSet::sanitize_closure_t closure = {
648 return c->check_struct (this)
649 && coverage.sanitize (c, this)
650 && pairSet.sanitize (c, this, &closure);
654 USHORT format; /* Format identifier--format = 1 */
656 coverage; /* Offset to Coverage table--from
657 * beginning of subtable */
658 ValueFormat valueFormat1; /* Defines the types of data in
659 * ValueRecord1--for the first glyph
660 * in the pair--may be zero (0) */
661 ValueFormat valueFormat2; /* Defines the types of data in
662 * ValueRecord2--for the second glyph
663 * in the pair--may be zero (0) */
664 OffsetArrayOf<PairSet>
665 pairSet; /* Array of PairSet tables
666 * ordered by Coverage Index */
668 DEFINE_SIZE_ARRAY (10, pairSet);
671 struct PairPosFormat2
673 friend struct PairPos;
676 inline bool apply (hb_apply_context_t *c) const
679 unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length);
680 if (unlikely (c->buffer->i + 2 > end))
683 unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
684 if (likely (index == NOT_COVERED))
687 unsigned int j = c->buffer->i + 1;
688 while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_flag, NULL))
690 if (unlikely (j == end))
695 unsigned int len1 = valueFormat1.get_len ();
696 unsigned int len2 = valueFormat2.get_len ();
697 unsigned int record_len = len1 + len2;
699 unsigned int klass1 = (this+classDef1) (c->buffer->info[c->buffer->i].codepoint);
700 unsigned int klass2 = (this+classDef2) (c->buffer->info[j].codepoint);
701 if (unlikely (klass1 >= class1Count || klass2 >= class2Count))
704 const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
705 valueFormat1.apply_value (c->layout, this, v, c->buffer->pos[c->buffer->i]);
706 valueFormat2.apply_value (c->layout, this, v + len1, c->buffer->pos[j]);
715 inline bool sanitize (hb_sanitize_context_t *c) {
717 if (!(c->check_struct (this)
718 && coverage.sanitize (c, this)
719 && classDef1.sanitize (c, this)
720 && classDef2.sanitize (c, this))) return false;
722 unsigned int len1 = valueFormat1.get_len ();
723 unsigned int len2 = valueFormat2.get_len ();
724 unsigned int stride = len1 + len2;
725 unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
726 unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
727 return c->check_array (values, record_size, count) &&
728 valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
729 valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride);
733 USHORT format; /* Format identifier--format = 2 */
735 coverage; /* Offset to Coverage table--from
736 * beginning of subtable */
737 ValueFormat valueFormat1; /* ValueRecord definition--for the
738 * first glyph of the pair--may be zero
740 ValueFormat valueFormat2; /* ValueRecord definition--for the
741 * second glyph of the pair--may be
744 classDef1; /* Offset to ClassDef table--from
745 * beginning of PairPos subtable--for
746 * the first glyph of the pair */
748 classDef2; /* Offset to ClassDef table--from
749 * beginning of PairPos subtable--for
750 * the second glyph of the pair */
751 USHORT class1Count; /* Number of classes in ClassDef1
752 * table--includes Class0 */
753 USHORT class2Count; /* Number of classes in ClassDef2
754 * table--includes Class0 */
755 ValueRecord values; /* Matrix of value pairs:
756 * class1-major, class2-minor,
757 * Each entry has value1 and value2 */
759 DEFINE_SIZE_ARRAY (16, values);
764 friend struct PosLookupSubTable;
767 inline bool apply (hb_apply_context_t *c) const
771 case 1: return u.format1.apply (c);
772 case 2: return u.format2.apply (c);
773 default:return false;
777 inline bool sanitize (hb_sanitize_context_t *c) {
779 if (!u.format.sanitize (c)) return false;
781 case 1: return u.format1.sanitize (c);
782 case 2: return u.format2.sanitize (c);
789 USHORT format; /* Format identifier */
790 PairPosFormat1 format1;
791 PairPosFormat2 format2;
796 struct EntryExitRecord
798 friend struct CursivePosFormat1;
800 inline bool sanitize (hb_sanitize_context_t *c, void *base) {
802 return entryAnchor.sanitize (c, base)
803 && exitAnchor.sanitize (c, base);
808 entryAnchor; /* Offset to EntryAnchor table--from
809 * beginning of CursivePos
810 * subtable--may be NULL */
812 exitAnchor; /* Offset to ExitAnchor table--from
813 * beginning of CursivePos
814 * subtable--may be NULL */
816 DEFINE_SIZE_STATIC (4);
819 struct CursivePosFormat1
821 friend struct CursivePos;
824 inline bool apply (hb_apply_context_t *c) const
828 /* We don't handle mark glyphs here. */
829 if (c->property == HB_OT_LAYOUT_GLYPH_CLASS_MARK)
832 unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length);
833 if (unlikely (c->buffer->i + 2 > end))
836 const EntryExitRecord &this_record = entryExitRecord[(this+coverage) (c->buffer->info[c->buffer->i].codepoint)];
837 if (!this_record.exitAnchor)
840 unsigned int j = c->buffer->i + 1;
841 while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_flag, NULL))
843 if (unlikely (j == end))
848 const EntryExitRecord &next_record = entryExitRecord[(this+coverage) (c->buffer->info[j].codepoint)];
849 if (!next_record.entryAnchor)
852 unsigned int i = c->buffer->i;
854 hb_position_t entry_x, entry_y, exit_x, exit_y;
855 (this+this_record.exitAnchor).get_anchor (c->layout, c->buffer->info[i].codepoint, &exit_x, &exit_y);
856 (this+next_record.entryAnchor).get_anchor (c->layout, c->buffer->info[j].codepoint, &entry_x, &entry_y);
858 hb_direction_t direction = c->buffer->props.direction;
860 /* Align the exit anchor of the left/top glyph with the entry anchor of the right/bottom glyph
861 * by adjusting advance of the left/top glyph. */
862 if (HB_DIRECTION_IS_BACKWARD (direction))
864 if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
865 c->buffer->pos[j].x_advance = c->buffer->pos[j].x_offset + entry_x - exit_x;
867 c->buffer->pos[j].y_advance = c->buffer->pos[j].y_offset + entry_y - exit_y;
871 if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
872 c->buffer->pos[i].x_advance = c->buffer->pos[i].x_offset + exit_x - entry_x;
874 c->buffer->pos[i].y_advance = c->buffer->pos[i].y_offset + exit_y - entry_y;
877 if (c->lookup_flag & LookupFlag::RightToLeft)
879 c->buffer->pos[i].cursive_chain() = j - i;
880 if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
881 c->buffer->pos[i].y_offset = entry_y - exit_y;
883 c->buffer->pos[i].x_offset = entry_x - exit_x;
887 c->buffer->pos[j].cursive_chain() = i - j;
888 if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
889 c->buffer->pos[j].y_offset = exit_y - entry_y;
891 c->buffer->pos[j].x_offset = exit_x - entry_x;
898 inline bool sanitize (hb_sanitize_context_t *c) {
900 return coverage.sanitize (c, this)
901 && entryExitRecord.sanitize (c, this);
905 USHORT format; /* Format identifier--format = 1 */
907 coverage; /* Offset to Coverage table--from
908 * beginning of subtable */
909 ArrayOf<EntryExitRecord>
910 entryExitRecord; /* Array of EntryExit records--in
911 * Coverage Index order */
913 DEFINE_SIZE_ARRAY (6, entryExitRecord);
918 friend struct PosLookupSubTable;
921 inline bool apply (hb_apply_context_t *c) const
925 case 1: return u.format1.apply (c);
926 default:return false;
930 inline bool sanitize (hb_sanitize_context_t *c) {
932 if (!u.format.sanitize (c)) return false;
934 case 1: return u.format1.sanitize (c);
941 USHORT format; /* Format identifier */
942 CursivePosFormat1 format1;
947 typedef AnchorMatrix BaseArray; /* base-major--
948 * in order of BaseCoverage Index--,
950 * ordered by class--zero-based. */
952 struct MarkBasePosFormat1
954 friend struct MarkBasePos;
957 inline bool apply (hb_apply_context_t *c) const
960 unsigned int mark_index = (this+markCoverage) (c->buffer->info[c->buffer->i].codepoint);
961 if (likely (mark_index == NOT_COVERED))
964 /* now we search backwards for a non-mark glyph */
965 unsigned int property;
966 unsigned int j = c->buffer->i;
972 } while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], LookupFlag::IgnoreMarks, &property));
974 /* The following assertion is too strong, so we've disabled it. */
975 if (false && !(property & HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH))
978 unsigned int base_index = (this+baseCoverage) (c->buffer->info[j].codepoint);
979 if (base_index == NOT_COVERED)
982 return (this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, j);
985 inline bool sanitize (hb_sanitize_context_t *c) {
987 return c->check_struct (this)
988 && markCoverage.sanitize (c, this)
989 && baseCoverage.sanitize (c, this)
990 && markArray.sanitize (c, this)
991 && baseArray.sanitize (c, this, (unsigned int) classCount);
995 USHORT format; /* Format identifier--format = 1 */
997 markCoverage; /* Offset to MarkCoverage table--from
998 * beginning of MarkBasePos subtable */
1000 baseCoverage; /* Offset to BaseCoverage table--from
1001 * beginning of MarkBasePos subtable */
1002 USHORT classCount; /* Number of classes defined for marks */
1004 markArray; /* Offset to MarkArray table--from
1005 * beginning of MarkBasePos subtable */
1007 baseArray; /* Offset to BaseArray table--from
1008 * beginning of MarkBasePos subtable */
1010 DEFINE_SIZE_STATIC (12);
1015 friend struct PosLookupSubTable;
1018 inline bool apply (hb_apply_context_t *c) const
1022 case 1: return u.format1.apply (c);
1023 default:return false;
1027 inline bool sanitize (hb_sanitize_context_t *c) {
1029 if (!u.format.sanitize (c)) return false;
1031 case 1: return u.format1.sanitize (c);
1032 default:return true;
1038 USHORT format; /* Format identifier */
1039 MarkBasePosFormat1 format1;
1044 typedef AnchorMatrix LigatureAttach; /* component-major--
1045 * in order of writing direction--,
1047 * ordered by class--zero-based. */
1049 typedef OffsetListOf<LigatureAttach> LigatureArray;
1050 /* Array of LigatureAttach
1052 * LigatureCoverage Index */
1054 struct MarkLigPosFormat1
1056 friend struct MarkLigPos;
1059 inline bool apply (hb_apply_context_t *c) const
1062 unsigned int mark_index = (this+markCoverage) (c->buffer->info[c->buffer->i].codepoint);
1063 if (likely (mark_index == NOT_COVERED))
1066 /* now we search backwards for a non-mark glyph */
1067 unsigned int property;
1068 unsigned int j = c->buffer->i;
1074 } while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], LookupFlag::IgnoreMarks, &property));
1076 /* The following assertion is too strong, so we've disabled it. */
1077 if (false && !(property & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE))
1080 unsigned int lig_index = (this+ligatureCoverage) (c->buffer->info[j].codepoint);
1081 if (lig_index == NOT_COVERED)
1084 const LigatureArray& lig_array = this+ligatureArray;
1085 const LigatureAttach& lig_attach = lig_array[lig_index];
1087 /* Find component to attach to */
1088 unsigned int comp_count = lig_attach.rows;
1089 if (unlikely (!comp_count))
1091 unsigned int comp_index;
1092 /* We must now check whether the ligature ID of the current mark glyph
1093 * is identical to the ligature ID of the found ligature. If yes, we
1094 * can directly use the component index. If not, we attach the mark
1095 * glyph to the last component of the ligature. */
1096 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())
1098 comp_index = c->buffer->info[c->buffer->i].component() - 1;
1099 if (comp_index >= comp_count)
1100 comp_index = comp_count - 1;
1103 comp_index = comp_count - 1;
1105 return (this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j);
1108 inline bool sanitize (hb_sanitize_context_t *c) {
1110 return c->check_struct (this)
1111 && markCoverage.sanitize (c, this)
1112 && ligatureCoverage.sanitize (c, this)
1113 && markArray.sanitize (c, this)
1114 && ligatureArray.sanitize (c, this, (unsigned int) classCount);
1118 USHORT format; /* Format identifier--format = 1 */
1120 markCoverage; /* Offset to Mark Coverage table--from
1121 * beginning of MarkLigPos subtable */
1123 ligatureCoverage; /* Offset to Ligature Coverage
1124 * table--from beginning of MarkLigPos
1126 USHORT classCount; /* Number of defined mark classes */
1128 markArray; /* Offset to MarkArray table--from
1129 * beginning of MarkLigPos subtable */
1130 OffsetTo<LigatureArray>
1131 ligatureArray; /* Offset to LigatureArray table--from
1132 * beginning of MarkLigPos subtable */
1134 DEFINE_SIZE_STATIC (12);
1139 friend struct PosLookupSubTable;
1142 inline bool apply (hb_apply_context_t *c) const
1146 case 1: return u.format1.apply (c);
1147 default:return false;
1151 inline bool sanitize (hb_sanitize_context_t *c) {
1153 if (!u.format.sanitize (c)) return false;
1155 case 1: return u.format1.sanitize (c);
1156 default:return true;
1162 USHORT format; /* Format identifier */
1163 MarkLigPosFormat1 format1;
1168 typedef AnchorMatrix Mark2Array; /* mark2-major--
1169 * in order of Mark2Coverage Index--,
1171 * ordered by class--zero-based. */
1173 struct MarkMarkPosFormat1
1175 friend struct MarkMarkPos;
1178 inline bool apply (hb_apply_context_t *c) const
1181 unsigned int mark1_index = (this+mark1Coverage) (c->buffer->info[c->buffer->i].codepoint);
1182 if (likely (mark1_index == NOT_COVERED))
1185 /* now we search backwards for a suitable mark glyph until a non-mark glyph */
1186 unsigned int property;
1187 unsigned int j = c->buffer->i;
1193 } while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_flag, &property));
1195 if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK))
1198 /* Two marks match only if they belong to the same base, or same component
1199 * of the same ligature. That is, the component numbers must match, and
1200 * if those are non-zero, the ligid number should also match. */
1201 if ((c->buffer->info[j].component() != c->buffer->info[c->buffer->i].component()) ||
1202 (c->buffer->info[j].component() && c->buffer->info[j].lig_id() != c->buffer->info[c->buffer->i].lig_id()))
1205 unsigned int mark2_index = (this+mark2Coverage) (c->buffer->info[j].codepoint);
1206 if (mark2_index == NOT_COVERED)
1209 return (this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j);
1212 inline bool sanitize (hb_sanitize_context_t *c) {
1214 return c->check_struct (this)
1215 && mark1Coverage.sanitize (c, this)
1216 && mark2Coverage.sanitize (c, this)
1217 && mark1Array.sanitize (c, this)
1218 && mark2Array.sanitize (c, this, (unsigned int) classCount);
1222 USHORT format; /* Format identifier--format = 1 */
1224 mark1Coverage; /* Offset to Combining Mark1 Coverage
1225 * table--from beginning of MarkMarkPos
1228 mark2Coverage; /* Offset to Combining Mark2 Coverage
1229 * table--from beginning of MarkMarkPos
1231 USHORT classCount; /* Number of defined mark classes */
1233 mark1Array; /* Offset to Mark1Array table--from
1234 * beginning of MarkMarkPos subtable */
1235 OffsetTo<Mark2Array>
1236 mark2Array; /* Offset to Mark2Array table--from
1237 * beginning of MarkMarkPos subtable */
1239 DEFINE_SIZE_STATIC (12);
1244 friend struct PosLookupSubTable;
1247 inline bool apply (hb_apply_context_t *c) const
1251 case 1: return u.format1.apply (c);
1252 default:return false;
1256 inline bool sanitize (hb_sanitize_context_t *c) {
1258 if (!u.format.sanitize (c)) return false;
1260 case 1: return u.format1.sanitize (c);
1261 default:return true;
1267 USHORT format; /* Format identifier */
1268 MarkMarkPosFormat1 format1;
1274 static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index);
1277 struct ContextPos : Context
1279 friend struct PosLookupSubTable;
1282 inline bool apply (hb_apply_context_t *c) const
1285 return Context::apply (c, position_lookup);
1289 struct ChainContextPos : ChainContext
1291 friend struct PosLookupSubTable;
1294 inline bool apply (hb_apply_context_t *c) const
1297 return ChainContext::apply (c, position_lookup);
1302 struct ExtensionPos : Extension
1304 friend struct PosLookupSubTable;
1307 inline const struct PosLookupSubTable& get_subtable (void) const
1309 unsigned int offset = get_offset ();
1310 if (unlikely (!offset)) return Null(PosLookupSubTable);
1311 return StructAtOffset<PosLookupSubTable> (this, offset);
1314 inline bool apply (hb_apply_context_t *c) const;
1316 inline bool sanitize (hb_sanitize_context_t *c);
1326 struct PosLookupSubTable
1328 friend struct PosLookup;
1342 inline bool apply (hb_apply_context_t *c, unsigned int lookup_type) const
1345 switch (lookup_type) {
1346 case Single: return u.single.apply (c);
1347 case Pair: return u.pair.apply (c);
1348 case Cursive: return u.cursive.apply (c);
1349 case MarkBase: return u.markBase.apply (c);
1350 case MarkLig: return u.markLig.apply (c);
1351 case MarkMark: return u.markMark.apply (c);
1352 case Context: return u.c.apply (c);
1353 case ChainContext: return u.chainContext.apply (c);
1354 case Extension: return u.extension.apply (c);
1355 default:return false;
1359 inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
1361 switch (lookup_type) {
1362 case Single: return u.single.sanitize (c);
1363 case Pair: return u.pair.sanitize (c);
1364 case Cursive: return u.cursive.sanitize (c);
1365 case MarkBase: return u.markBase.sanitize (c);
1366 case MarkLig: return u.markLig.sanitize (c);
1367 case MarkMark: return u.markMark.sanitize (c);
1368 case Context: return u.c.sanitize (c);
1369 case ChainContext: return u.chainContext.sanitize (c);
1370 case Extension: return u.extension.sanitize (c);
1371 default:return true;
1381 MarkBasePos markBase;
1383 MarkMarkPos markMark;
1385 ChainContextPos chainContext;
1386 ExtensionPos extension;
1389 DEFINE_SIZE_UNION (2, sub_format);
1393 struct PosLookup : Lookup
1395 inline const PosLookupSubTable& get_subtable (unsigned int i) const
1396 { return this+CastR<OffsetArrayOf<PosLookupSubTable> > (subTable)[i]; }
1398 inline bool apply_once (hb_ot_layout_context_t *layout,
1399 hb_buffer_t *buffer,
1400 hb_mask_t lookup_mask,
1401 unsigned int context_length,
1402 unsigned int nesting_level_left) const
1404 unsigned int lookup_type = get_type ();
1405 hb_apply_context_t c[1] = {{0}};
1409 c->lookup_mask = lookup_mask;
1410 c->context_length = context_length;
1411 c->nesting_level_left = nesting_level_left;
1412 c->lookup_flag = get_flag ();
1414 if (!_hb_ot_layout_check_glyph_property (c->layout->face, &c->buffer->info[c->buffer->i], c->lookup_flag, &c->property))
1417 for (unsigned int i = 0; i < get_subtable_count (); i++)
1418 if (get_subtable (i).apply (c, lookup_type))
1424 inline bool apply_string (hb_ot_layout_context_t *layout,
1425 hb_buffer_t *buffer,
1426 hb_mask_t mask) const
1430 if (unlikely (!buffer->len))
1434 while (buffer->i < buffer->len)
1436 if ((buffer->info[buffer->i].mask & mask) &&
1437 apply_once (layout, buffer, mask, NO_CONTEXT, MAX_NESTING_LEVEL))
1446 inline bool sanitize (hb_sanitize_context_t *c) {
1448 if (unlikely (!Lookup::sanitize (c))) return false;
1449 OffsetArrayOf<PosLookupSubTable> &list = CastR<OffsetArrayOf<PosLookupSubTable> > (subTable);
1450 return list.sanitize (c, this, get_type ());
1454 typedef OffsetListOf<PosLookup> PosLookupList;
1460 struct GPOS : GSUBGPOS
1462 static const hb_tag_t Tag = HB_OT_TAG_GPOS;
1464 inline const PosLookup& get_lookup (unsigned int i) const
1465 { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
1467 inline bool position_lookup (hb_ot_layout_context_t *layout,
1468 hb_buffer_t *buffer,
1469 unsigned int lookup_index,
1470 hb_mask_t mask) const
1471 { return get_lookup (lookup_index).apply_string (layout, buffer, mask); }
1473 inline bool sanitize (hb_sanitize_context_t *c) {
1475 if (unlikely (!GSUBGPOS::sanitize (c))) return false;
1476 OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
1477 return list.sanitize (c, this);
1480 DEFINE_SIZE_STATIC (10);
1484 /* Out-of-class implementation for methods recursing */
1486 inline bool ExtensionPos::apply (hb_apply_context_t *c) const
1489 return get_subtable ().apply (c, get_type ());
1492 inline bool ExtensionPos::sanitize (hb_sanitize_context_t *c)
1495 if (unlikely (!Extension::sanitize (c))) return false;
1496 unsigned int offset = get_offset ();
1497 if (unlikely (!offset)) return true;
1498 return StructAtOffset<PosLookupSubTable> (this, offset).sanitize (c, get_type ());
1501 static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index)
1503 const GPOS &gpos = *(c->layout->face->ot_layout->gpos);
1504 const PosLookup &l = gpos.get_lookup (lookup_index);
1506 if (unlikely (c->nesting_level_left == 0))
1509 if (unlikely (c->context_length < 1))
1512 return l.apply_once (c->layout, c->buffer, c->lookup_mask, c->context_length, c->nesting_level_left - 1);
1518 #endif /* HB_OT_LAYOUT_GPOS_PRIVATE_HH */