2 * Copyright © 2007,2008,2009,2010 Red Hat, Inc.
3 * Copyright © 2010 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_PRIVATE_HH
30 #define HB_OT_LAYOUT_GPOS_PRIVATE_HH
32 #include "hb-ot-layout-gsubgpos-private.hh"
37 /* buffer var allocations */
38 #define attach_lookback() var.u16[0] /* number of glyphs to go back to attach this glyph to its base */
39 #define cursive_chain() var.i16[1] /* character to which this connects, may be positive or negative */
42 /* Shared Tables: ValueRecord, Anchor Table, and MarkArray */
46 typedef Value ValueRecord[VAR];
48 struct ValueFormat : USHORT
52 xPlacement = 0x0001, /* Includes horizontal adjustment for placement */
53 yPlacement = 0x0002, /* Includes vertical adjustment for placement */
54 xAdvance = 0x0004, /* Includes horizontal adjustment for advance */
55 yAdvance = 0x0008, /* Includes vertical adjustment for advance */
56 xPlaDevice = 0x0010, /* Includes horizontal Device table for placement */
57 yPlaDevice = 0x0020, /* Includes vertical Device table for placement */
58 xAdvDevice = 0x0040, /* Includes horizontal Device table for advance */
59 yAdvDevice = 0x0080, /* Includes vertical Device table for advance */
60 ignored = 0x0F00, /* Was used in TrueType Open for MM fonts */
61 reserved = 0xF000, /* For future use */
63 devices = 0x00F0 /* Mask for having any Device table */
66 /* All fields are options. Only those available advance the value pointer. */
68 SHORT xPlacement; /* Horizontal adjustment for
69 * placement--in design units */
70 SHORT yPlacement; /* Vertical adjustment for
71 * placement--in design units */
72 SHORT xAdvance; /* Horizontal adjustment for
73 * advance--in design units (only used
74 * for horizontal writing) */
75 SHORT yAdvance; /* Vertical adjustment for advance--in
76 * design units (only used for vertical
78 Offset xPlaDevice; /* Offset to Device table for
79 * horizontal placement--measured from
80 * beginning of PosTable (may be NULL) */
81 Offset yPlaDevice; /* Offset to Device table for vertical
82 * placement--measured from beginning
83 * of PosTable (may be NULL) */
84 Offset xAdvDevice; /* Offset to Device table for
85 * horizontal advance--measured from
86 * beginning of PosTable (may be NULL) */
87 Offset yAdvDevice; /* Offset to Device table for vertical
88 * advance--measured from beginning of
89 * PosTable (may be NULL) */
92 inline unsigned int get_len (void) const
93 { return _hb_popcount32 ((unsigned int) *this); }
94 inline unsigned int get_size (void) const
95 { return get_len () * Value::static_size; }
97 void apply_value (hb_font_t *font,
98 hb_direction_t direction,
101 hb_glyph_position_t &glyph_pos) const
103 unsigned int x_ppem, y_ppem;
104 unsigned int format = *this;
105 hb_bool_t horizontal = HB_DIRECTION_IS_HORIZONTAL (direction);
109 if (format & xPlacement) glyph_pos.x_offset += font->em_scale_x (get_short (values++));
110 if (format & yPlacement) glyph_pos.y_offset += font->em_scale_y (get_short (values++));
111 if (format & xAdvance) {
112 if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values++)); else values++;
114 /* y_advance values grow downward but font-space grows upward, hence negation */
115 if (format & yAdvance) {
116 if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values++)); else values++;
119 if (!has_device ()) return;
121 x_ppem = font->x_ppem;
122 y_ppem = font->y_ppem;
124 if (!x_ppem && !y_ppem) return;
126 /* pixel -> fractional pixel */
127 if (format & xPlaDevice) {
128 if (x_ppem) glyph_pos.x_offset += (base + get_device (values++)).get_x_delta (font); else values++;
130 if (format & yPlaDevice) {
131 if (y_ppem) glyph_pos.y_offset += (base + get_device (values++)).get_y_delta (font); else values++;
133 if (format & xAdvDevice) {
134 if (horizontal && x_ppem) glyph_pos.x_advance += (base + get_device (values++)).get_x_delta (font); else values++;
136 if (format & yAdvDevice) {
137 /* y_advance values grow downward but font-space grows upward, hence negation */
138 if (!horizontal && y_ppem) glyph_pos.y_advance -= (base + get_device (values++)).get_y_delta (font); else values++;
143 inline bool sanitize_value_devices (hb_sanitize_context_t *c, void *base, Value *values) {
144 unsigned int format = *this;
146 if (format & xPlacement) values++;
147 if (format & yPlacement) values++;
148 if (format & xAdvance) values++;
149 if (format & yAdvance) values++;
151 if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
152 if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
153 if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
154 if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
159 static inline OffsetTo<Device>& get_device (Value* value)
160 { return *CastP<OffsetTo<Device> > (value); }
161 static inline const OffsetTo<Device>& get_device (const Value* value)
162 { return *CastP<OffsetTo<Device> > (value); }
164 static inline const SHORT& get_short (const Value* value)
165 { return *CastP<SHORT> (value); }
169 inline bool has_device (void) const {
170 unsigned int format = *this;
171 return (format & devices) != 0;
174 inline bool sanitize_value (hb_sanitize_context_t *c, void *base, Value *values) {
176 return c->check_range (values, get_size ())
177 && (!has_device () || sanitize_value_devices (c, base, values));
180 inline bool sanitize_values (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count) {
182 unsigned int len = get_len ();
184 if (!c->check_array (values, get_size (), count)) return false;
186 if (!has_device ()) return true;
188 for (unsigned int i = 0; i < count; i++) {
189 if (!sanitize_value_devices (c, base, values))
197 /* Just sanitize referenced Device tables. Doesn't check the values themselves. */
198 inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count, unsigned int stride) {
201 if (!has_device ()) return true;
203 for (unsigned int i = 0; i < count; i++) {
204 if (!sanitize_value_devices (c, base, values))
216 friend struct Anchor;
219 inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
220 hb_position_t *x, hb_position_t *y) const
222 *x = font->em_scale_x (xCoordinate);
223 *y = font->em_scale_y (yCoordinate);
226 inline bool sanitize (hb_sanitize_context_t *c) {
228 return c->check_struct (this);
232 USHORT format; /* Format identifier--format = 1 */
233 SHORT xCoordinate; /* Horizontal value--in design units */
234 SHORT yCoordinate; /* Vertical value--in design units */
236 DEFINE_SIZE_STATIC (6);
241 friend struct Anchor;
244 inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
245 hb_position_t *x, hb_position_t *y) const
247 unsigned int x_ppem = font->x_ppem;
248 unsigned int y_ppem = font->y_ppem;
249 hb_position_t cx, cy;
250 hb_bool_t ret = false;
252 if (x_ppem || y_ppem)
253 ret = hb_font_get_glyph_contour_point_for_origin (font, glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
254 *x = x_ppem && ret ? cx : font->em_scale_x (xCoordinate);
255 *y = y_ppem && ret ? cy : font->em_scale_y (yCoordinate);
258 inline bool sanitize (hb_sanitize_context_t *c) {
260 return c->check_struct (this);
264 USHORT format; /* Format identifier--format = 2 */
265 SHORT xCoordinate; /* Horizontal value--in design units */
266 SHORT yCoordinate; /* Vertical value--in design units */
267 USHORT anchorPoint; /* Index to glyph contour point */
269 DEFINE_SIZE_STATIC (8);
274 friend struct Anchor;
277 inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
278 hb_position_t *x, hb_position_t *y) const
280 *x = font->em_scale_x (xCoordinate);
281 *y = font->em_scale_y (yCoordinate);
284 *x += (this+xDeviceTable).get_x_delta (font);
286 *y += (this+yDeviceTable).get_x_delta (font);
289 inline bool sanitize (hb_sanitize_context_t *c) {
291 return c->check_struct (this)
292 && xDeviceTable.sanitize (c, this)
293 && yDeviceTable.sanitize (c, this);
297 USHORT format; /* Format identifier--format = 3 */
298 SHORT xCoordinate; /* Horizontal value--in design units */
299 SHORT yCoordinate; /* Vertical value--in design units */
301 xDeviceTable; /* Offset to Device table for X
302 * coordinate-- from beginning of
303 * Anchor table (may be NULL) */
305 yDeviceTable; /* Offset to Device table for Y
306 * coordinate-- from beginning of
307 * Anchor table (may be NULL) */
309 DEFINE_SIZE_STATIC (10);
314 inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
315 hb_position_t *x, hb_position_t *y) const
319 case 1: u.format1.get_anchor (font, glyph_id, x, y); return;
320 case 2: u.format2.get_anchor (font, glyph_id, x, y); return;
321 case 3: u.format3.get_anchor (font, glyph_id, x, y); return;
326 inline bool sanitize (hb_sanitize_context_t *c) {
328 if (!u.format.sanitize (c)) return false;
330 case 1: return u.format1.sanitize (c);
331 case 2: return u.format2.sanitize (c);
332 case 3: return u.format3.sanitize (c);
339 USHORT format; /* Format identifier */
340 AnchorFormat1 format1;
341 AnchorFormat2 format2;
342 AnchorFormat3 format3;
345 DEFINE_SIZE_UNION (2, format);
351 inline const Anchor& get_anchor (unsigned int row, unsigned int col, unsigned int cols) const {
352 if (unlikely (row >= rows || col >= cols)) return Null(Anchor);
353 return this+matrix[row * cols + col];
356 inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) {
358 if (!c->check_struct (this)) return false;
359 if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return false;
360 unsigned int count = rows * cols;
361 if (!c->check_array (matrix, matrix[0].static_size, count)) return false;
362 for (unsigned int i = 0; i < count; i++)
363 if (!matrix[i].sanitize (c, this)) return false;
367 USHORT rows; /* Number of rows */
370 matrix[VAR]; /* Matrix of offsets to Anchor tables--
371 * from beginning of AnchorMatrix table */
373 DEFINE_SIZE_ARRAY (2, matrix);
379 friend struct MarkArray;
381 inline bool sanitize (hb_sanitize_context_t *c, void *base) {
383 return c->check_struct (this)
384 && markAnchor.sanitize (c, base);
388 USHORT klass; /* Class defined for this mark */
390 markAnchor; /* Offset to Anchor table--from
391 * beginning of MarkArray table */
393 DEFINE_SIZE_STATIC (4);
396 struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage order */
398 inline bool apply (hb_apply_context_t *c,
399 unsigned int mark_index, unsigned int glyph_index,
400 const AnchorMatrix &anchors, unsigned int class_count,
401 unsigned int glyph_pos) const
404 const MarkRecord &record = ArrayOf<MarkRecord>::operator[](mark_index);
405 unsigned int mark_class = record.klass;
407 const Anchor& mark_anchor = this + record.markAnchor;
408 const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count);
410 hb_position_t mark_x, mark_y, base_x, base_y;
412 mark_anchor.get_anchor (c->font, c->buffer->info[c->buffer->i].codepoint, &mark_x, &mark_y);
413 glyph_anchor.get_anchor (c->font, c->buffer->info[glyph_pos].codepoint, &base_x, &base_y);
415 hb_glyph_position_t &o = c->buffer->pos[c->buffer->i];
416 o.x_offset = base_x - mark_x;
417 o.y_offset = base_y - mark_y;
418 o.attach_lookback() = c->buffer->i - glyph_pos;
424 inline bool sanitize (hb_sanitize_context_t *c) {
426 return ArrayOf<MarkRecord>::sanitize (c, this);
433 struct SinglePosFormat1
435 friend struct SinglePos;
438 inline bool apply (hb_apply_context_t *c) const
441 unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
442 if (likely (index == NOT_COVERED))
445 valueFormat.apply_value (c->font, c->direction, this,
446 values, c->buffer->pos[c->buffer->i]);
452 inline bool sanitize (hb_sanitize_context_t *c) {
454 return c->check_struct (this)
455 && coverage.sanitize (c, this)
456 && valueFormat.sanitize_value (c, this, values);
460 USHORT format; /* Format identifier--format = 1 */
462 coverage; /* Offset to Coverage table--from
463 * beginning of subtable */
464 ValueFormat valueFormat; /* Defines the types of data in the
466 ValueRecord values; /* Defines positioning
467 * value(s)--applied to all glyphs in
468 * the Coverage table */
470 DEFINE_SIZE_ARRAY (6, values);
473 struct SinglePosFormat2
475 friend struct SinglePos;
478 inline bool apply (hb_apply_context_t *c) const
481 unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
482 if (likely (index == NOT_COVERED))
485 if (likely (index >= valueCount))
488 valueFormat.apply_value (c->font, c->direction, this,
489 &values[index * valueFormat.get_len ()],
490 c->buffer->pos[c->buffer->i]);
496 inline bool sanitize (hb_sanitize_context_t *c) {
498 return c->check_struct (this)
499 && coverage.sanitize (c, this)
500 && valueFormat.sanitize_values (c, this, values, valueCount);
504 USHORT format; /* Format identifier--format = 2 */
506 coverage; /* Offset to Coverage table--from
507 * beginning of subtable */
508 ValueFormat valueFormat; /* Defines the types of data in the
510 USHORT valueCount; /* Number of ValueRecords */
511 ValueRecord values; /* Array of ValueRecords--positioning
512 * values applied to glyphs */
514 DEFINE_SIZE_ARRAY (8, values);
519 friend struct PosLookupSubTable;
522 inline bool apply (hb_apply_context_t *c) const
526 case 1: return u.format1.apply (c);
527 case 2: return u.format2.apply (c);
528 default:return false;
532 inline bool sanitize (hb_sanitize_context_t *c) {
534 if (!u.format.sanitize (c)) return false;
536 case 1: return u.format1.sanitize (c);
537 case 2: return u.format2.sanitize (c);
544 USHORT format; /* Format identifier */
545 SinglePosFormat1 format1;
546 SinglePosFormat2 format2;
551 struct PairValueRecord
553 friend struct PairSet;
556 GlyphID secondGlyph; /* GlyphID of second glyph in the
557 * pair--first glyph is listed in the
559 ValueRecord values; /* Positioning data for the first glyph
560 * followed by for second glyph */
562 DEFINE_SIZE_ARRAY (2, values);
567 friend struct PairPosFormat1;
569 inline bool apply (hb_apply_context_t *c,
570 const ValueFormat *valueFormats,
571 unsigned int pos) const
574 unsigned int len1 = valueFormats[0].get_len ();
575 unsigned int len2 = valueFormats[1].get_len ();
576 unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
578 unsigned int count = len;
579 const PairValueRecord *record = CastP<PairValueRecord> (array);
580 for (unsigned int i = 0; i < count; i++)
582 if (c->buffer->info[pos].codepoint == record->secondGlyph)
584 valueFormats[0].apply_value (c->font, c->direction, this,
585 &record->values[0], c->buffer->pos[c->buffer->i]);
586 valueFormats[1].apply_value (c->font, c->direction, this,
587 &record->values[len1], c->buffer->pos[pos]);
593 record = &StructAtOffset<PairValueRecord> (record, record_size);
599 struct sanitize_closure_t {
601 ValueFormat *valueFormats;
602 unsigned int len1; /* valueFormats[0].get_len() */
603 unsigned int stride; /* 1 + len1 + len2 */
606 inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) {
608 if (!(c->check_struct (this)
609 && c->check_array (array, USHORT::static_size * closure->stride, len))) return false;
611 unsigned int count = len;
612 PairValueRecord *record = CastP<PairValueRecord> (array);
613 return closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride)
614 && closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride);
618 USHORT len; /* Number of PairValueRecords */
619 USHORT array[VAR]; /* Array of PairValueRecords--ordered
620 * by GlyphID of the second glyph */
622 DEFINE_SIZE_ARRAY (2, array);
625 struct PairPosFormat1
627 friend struct PairPos;
630 inline bool apply (hb_apply_context_t *c) const
633 unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length);
634 if (unlikely (c->buffer->i + 2 > end))
637 unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
638 if (likely (index == NOT_COVERED))
641 unsigned int j = c->buffer->i + 1;
642 while (_hb_ot_layout_skip_mark (c->face, &c->buffer->info[j], c->lookup_props, NULL))
644 if (unlikely (j == end))
649 return (this+pairSet[index]).apply (c, &valueFormat1, j);
652 inline bool sanitize (hb_sanitize_context_t *c) {
655 unsigned int len1 = valueFormat1.get_len ();
656 unsigned int len2 = valueFormat2.get_len ();
657 PairSet::sanitize_closure_t closure = {
664 return c->check_struct (this)
665 && coverage.sanitize (c, this)
666 && pairSet.sanitize (c, this, &closure);
670 USHORT format; /* Format identifier--format = 1 */
672 coverage; /* Offset to Coverage table--from
673 * beginning of subtable */
674 ValueFormat valueFormat1; /* Defines the types of data in
675 * ValueRecord1--for the first glyph
676 * in the pair--may be zero (0) */
677 ValueFormat valueFormat2; /* Defines the types of data in
678 * ValueRecord2--for the second glyph
679 * in the pair--may be zero (0) */
680 OffsetArrayOf<PairSet>
681 pairSet; /* Array of PairSet tables
682 * ordered by Coverage Index */
684 DEFINE_SIZE_ARRAY (10, pairSet);
687 struct PairPosFormat2
689 friend struct PairPos;
692 inline bool apply (hb_apply_context_t *c) const
695 unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length);
696 if (unlikely (c->buffer->i + 2 > end))
699 unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
700 if (likely (index == NOT_COVERED))
703 unsigned int j = c->buffer->i + 1;
704 while (_hb_ot_layout_skip_mark (c->face, &c->buffer->info[j], c->lookup_props, NULL))
706 if (unlikely (j == end))
711 unsigned int len1 = valueFormat1.get_len ();
712 unsigned int len2 = valueFormat2.get_len ();
713 unsigned int record_len = len1 + len2;
715 unsigned int klass1 = (this+classDef1) (c->buffer->info[c->buffer->i].codepoint);
716 unsigned int klass2 = (this+classDef2) (c->buffer->info[j].codepoint);
717 if (unlikely (klass1 >= class1Count || klass2 >= class2Count))
720 const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
721 valueFormat1.apply_value (c->font, c->direction, this,
722 v, c->buffer->pos[c->buffer->i]);
723 valueFormat2.apply_value (c->font, c->direction, this,
724 v + len1, c->buffer->pos[j]);
733 inline bool sanitize (hb_sanitize_context_t *c) {
735 if (!(c->check_struct (this)
736 && coverage.sanitize (c, this)
737 && classDef1.sanitize (c, this)
738 && classDef2.sanitize (c, this))) return false;
740 unsigned int len1 = valueFormat1.get_len ();
741 unsigned int len2 = valueFormat2.get_len ();
742 unsigned int stride = len1 + len2;
743 unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
744 unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
745 return c->check_array (values, record_size, count) &&
746 valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
747 valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride);
751 USHORT format; /* Format identifier--format = 2 */
753 coverage; /* Offset to Coverage table--from
754 * beginning of subtable */
755 ValueFormat valueFormat1; /* ValueRecord definition--for the
756 * first glyph of the pair--may be zero
758 ValueFormat valueFormat2; /* ValueRecord definition--for the
759 * second glyph of the pair--may be
762 classDef1; /* Offset to ClassDef table--from
763 * beginning of PairPos subtable--for
764 * the first glyph of the pair */
766 classDef2; /* Offset to ClassDef table--from
767 * beginning of PairPos subtable--for
768 * the second glyph of the pair */
769 USHORT class1Count; /* Number of classes in ClassDef1
770 * table--includes Class0 */
771 USHORT class2Count; /* Number of classes in ClassDef2
772 * table--includes Class0 */
773 ValueRecord values; /* Matrix of value pairs:
774 * class1-major, class2-minor,
775 * Each entry has value1 and value2 */
777 DEFINE_SIZE_ARRAY (16, values);
782 friend struct PosLookupSubTable;
785 inline bool apply (hb_apply_context_t *c) const
789 case 1: return u.format1.apply (c);
790 case 2: return u.format2.apply (c);
791 default:return false;
795 inline bool sanitize (hb_sanitize_context_t *c) {
797 if (!u.format.sanitize (c)) return false;
799 case 1: return u.format1.sanitize (c);
800 case 2: return u.format2.sanitize (c);
807 USHORT format; /* Format identifier */
808 PairPosFormat1 format1;
809 PairPosFormat2 format2;
814 struct EntryExitRecord
816 friend struct CursivePosFormat1;
818 inline bool sanitize (hb_sanitize_context_t *c, void *base) {
820 return entryAnchor.sanitize (c, base)
821 && exitAnchor.sanitize (c, base);
826 entryAnchor; /* Offset to EntryAnchor table--from
827 * beginning of CursivePos
828 * subtable--may be NULL */
830 exitAnchor; /* Offset to ExitAnchor table--from
831 * beginning of CursivePos
832 * subtable--may be NULL */
834 DEFINE_SIZE_STATIC (4);
837 struct CursivePosFormat1
839 friend struct CursivePos;
842 inline bool apply (hb_apply_context_t *c) const
846 /* We don't handle mark glyphs here. */
847 if (c->property & HB_OT_LAYOUT_GLYPH_CLASS_MARK)
850 unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length);
851 if (unlikely (c->buffer->i + 2 > end))
854 const EntryExitRecord &this_record = entryExitRecord[(this+coverage) (c->buffer->info[c->buffer->i].codepoint)];
855 if (!this_record.exitAnchor)
858 unsigned int j = c->buffer->i + 1;
859 while (_hb_ot_layout_skip_mark (c->face, &c->buffer->info[j], c->lookup_props, NULL))
861 if (unlikely (j == end))
866 const EntryExitRecord &next_record = entryExitRecord[(this+coverage) (c->buffer->info[j].codepoint)];
867 if (!next_record.entryAnchor)
870 unsigned int i = c->buffer->i;
872 hb_position_t entry_x, entry_y, exit_x, exit_y;
873 (this+this_record.exitAnchor).get_anchor (c->font, c->buffer->info[i].codepoint, &exit_x, &exit_y);
874 (this+next_record.entryAnchor).get_anchor (c->font, c->buffer->info[j].codepoint, &entry_x, &entry_y);
876 hb_glyph_position_t *pos = c->buffer->pos;
879 /* Main-direction adjustment */
880 switch (c->direction) {
881 case HB_DIRECTION_LTR:
882 pos[i].x_advance = exit_x + pos[i].x_offset;
884 d = entry_x + pos[j].x_offset;
885 pos[j].x_advance -= d;
886 pos[j].x_offset -= d;
888 case HB_DIRECTION_RTL:
889 d = exit_x + pos[i].x_offset;
890 pos[i].x_advance -= d;
891 pos[i].x_offset -= d;
893 pos[j].x_advance = entry_x + pos[j].x_offset;
895 case HB_DIRECTION_TTB:
896 pos[i].y_advance = exit_y + pos[i].y_offset;
898 d = entry_y + pos[j].y_offset;
899 pos[j].y_advance -= d;
900 pos[j].y_offset -= d;
902 case HB_DIRECTION_BTT:
903 d = exit_y + pos[i].y_offset;
904 pos[i].y_advance -= d;
905 pos[i].y_offset -= d;
907 pos[j].y_advance = entry_y;
909 case HB_DIRECTION_INVALID:
914 /* Cross-direction adjustment */
915 if (c->lookup_props & LookupFlag::RightToLeft) {
916 pos[i].cursive_chain() = j - i;
917 if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
918 pos[i].y_offset = entry_y - exit_y;
920 pos[i].x_offset = entry_x - exit_x;
922 pos[j].cursive_chain() = i - j;
923 if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
924 pos[j].y_offset = exit_y - entry_y;
926 pos[j].x_offset = exit_x - entry_x;
933 inline bool sanitize (hb_sanitize_context_t *c) {
935 return coverage.sanitize (c, this)
936 && entryExitRecord.sanitize (c, this);
940 USHORT format; /* Format identifier--format = 1 */
942 coverage; /* Offset to Coverage table--from
943 * beginning of subtable */
944 ArrayOf<EntryExitRecord>
945 entryExitRecord; /* Array of EntryExit records--in
946 * Coverage Index order */
948 DEFINE_SIZE_ARRAY (6, entryExitRecord);
953 friend struct PosLookupSubTable;
956 inline bool apply (hb_apply_context_t *c) const
960 case 1: return u.format1.apply (c);
961 default:return false;
965 inline bool sanitize (hb_sanitize_context_t *c) {
967 if (!u.format.sanitize (c)) return false;
969 case 1: return u.format1.sanitize (c);
976 USHORT format; /* Format identifier */
977 CursivePosFormat1 format1;
982 typedef AnchorMatrix BaseArray; /* base-major--
983 * in order of BaseCoverage Index--,
985 * ordered by class--zero-based. */
987 struct MarkBasePosFormat1
989 friend struct MarkBasePos;
992 inline bool apply (hb_apply_context_t *c) const
995 unsigned int mark_index = (this+markCoverage) (c->buffer->info[c->buffer->i].codepoint);
996 if (likely (mark_index == NOT_COVERED))
999 /* now we search backwards for a non-mark glyph */
1000 unsigned int property;
1001 unsigned int j = c->buffer->i;
1007 } while (_hb_ot_layout_skip_mark (c->face, &c->buffer->info[j], LookupFlag::IgnoreMarks, &property));
1009 /* The following assertion is too strong, so we've disabled it. */
1010 if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH))
1013 unsigned int base_index = (this+baseCoverage) (c->buffer->info[j].codepoint);
1014 if (base_index == NOT_COVERED)
1017 return (this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, j);
1020 inline bool sanitize (hb_sanitize_context_t *c) {
1022 return c->check_struct (this)
1023 && markCoverage.sanitize (c, this)
1024 && baseCoverage.sanitize (c, this)
1025 && markArray.sanitize (c, this)
1026 && baseArray.sanitize (c, this, (unsigned int) classCount);
1030 USHORT format; /* Format identifier--format = 1 */
1032 markCoverage; /* Offset to MarkCoverage table--from
1033 * beginning of MarkBasePos subtable */
1035 baseCoverage; /* Offset to BaseCoverage table--from
1036 * beginning of MarkBasePos subtable */
1037 USHORT classCount; /* Number of classes defined for marks */
1039 markArray; /* Offset to MarkArray table--from
1040 * beginning of MarkBasePos subtable */
1042 baseArray; /* Offset to BaseArray table--from
1043 * beginning of MarkBasePos subtable */
1045 DEFINE_SIZE_STATIC (12);
1050 friend struct PosLookupSubTable;
1053 inline bool apply (hb_apply_context_t *c) const
1057 case 1: return u.format1.apply (c);
1058 default:return false;
1062 inline bool sanitize (hb_sanitize_context_t *c) {
1064 if (!u.format.sanitize (c)) return false;
1066 case 1: return u.format1.sanitize (c);
1067 default:return true;
1073 USHORT format; /* Format identifier */
1074 MarkBasePosFormat1 format1;
1079 typedef AnchorMatrix LigatureAttach; /* component-major--
1080 * in order of writing direction--,
1082 * ordered by class--zero-based. */
1084 typedef OffsetListOf<LigatureAttach> LigatureArray;
1085 /* Array of LigatureAttach
1087 * LigatureCoverage Index */
1089 struct MarkLigPosFormat1
1091 friend struct MarkLigPos;
1094 inline bool apply (hb_apply_context_t *c) const
1097 unsigned int mark_index = (this+markCoverage) (c->buffer->info[c->buffer->i].codepoint);
1098 if (likely (mark_index == NOT_COVERED))
1101 /* now we search backwards for a non-mark glyph */
1102 unsigned int property;
1103 unsigned int j = c->buffer->i;
1109 } while (_hb_ot_layout_skip_mark (c->face, &c->buffer->info[j], LookupFlag::IgnoreMarks, &property));
1111 /* The following assertion is too strong, so we've disabled it. */
1112 if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE))
1115 unsigned int lig_index = (this+ligatureCoverage) (c->buffer->info[j].codepoint);
1116 if (lig_index == NOT_COVERED)
1119 const LigatureArray& lig_array = this+ligatureArray;
1120 const LigatureAttach& lig_attach = lig_array[lig_index];
1122 /* Find component to attach to */
1123 unsigned int comp_count = lig_attach.rows;
1124 if (unlikely (!comp_count))
1126 unsigned int comp_index;
1127 /* We must now check whether the ligature ID of the current mark glyph
1128 * is identical to the ligature ID of the found ligature. If yes, we
1129 * can directly use the component index. If not, we attach the mark
1130 * glyph to the last component of the ligature. */
1131 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].lig_comp())
1133 comp_index = c->buffer->info[c->buffer->i].lig_comp() - 1;
1134 if (comp_index >= comp_count)
1135 comp_index = comp_count - 1;
1138 comp_index = comp_count - 1;
1140 return (this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j);
1143 inline bool sanitize (hb_sanitize_context_t *c) {
1145 return c->check_struct (this)
1146 && markCoverage.sanitize (c, this)
1147 && ligatureCoverage.sanitize (c, this)
1148 && markArray.sanitize (c, this)
1149 && ligatureArray.sanitize (c, this, (unsigned int) classCount);
1153 USHORT format; /* Format identifier--format = 1 */
1155 markCoverage; /* Offset to Mark Coverage table--from
1156 * beginning of MarkLigPos subtable */
1158 ligatureCoverage; /* Offset to Ligature Coverage
1159 * table--from beginning of MarkLigPos
1161 USHORT classCount; /* Number of defined mark classes */
1163 markArray; /* Offset to MarkArray table--from
1164 * beginning of MarkLigPos subtable */
1165 OffsetTo<LigatureArray>
1166 ligatureArray; /* Offset to LigatureArray table--from
1167 * beginning of MarkLigPos subtable */
1169 DEFINE_SIZE_STATIC (12);
1174 friend struct PosLookupSubTable;
1177 inline bool apply (hb_apply_context_t *c) const
1181 case 1: return u.format1.apply (c);
1182 default:return false;
1186 inline bool sanitize (hb_sanitize_context_t *c) {
1188 if (!u.format.sanitize (c)) return false;
1190 case 1: return u.format1.sanitize (c);
1191 default:return true;
1197 USHORT format; /* Format identifier */
1198 MarkLigPosFormat1 format1;
1203 typedef AnchorMatrix Mark2Array; /* mark2-major--
1204 * in order of Mark2Coverage Index--,
1206 * ordered by class--zero-based. */
1208 struct MarkMarkPosFormat1
1210 friend struct MarkMarkPos;
1213 inline bool apply (hb_apply_context_t *c) const
1216 unsigned int mark1_index = (this+mark1Coverage) (c->buffer->info[c->buffer->i].codepoint);
1217 if (likely (mark1_index == NOT_COVERED))
1220 /* now we search backwards for a suitable mark glyph until a non-mark glyph */
1221 unsigned int property;
1222 unsigned int j = c->buffer->i;
1228 } while (_hb_ot_layout_skip_mark (c->face, &c->buffer->info[j], c->lookup_props, &property));
1230 if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK))
1233 /* Two marks match only if they belong to the same base, or same component
1234 * of the same ligature. That is, the component numbers must match, and
1235 * if those are non-zero, the ligid number should also match. */
1236 if ((c->buffer->info[j].lig_comp() != c->buffer->info[c->buffer->i].lig_comp()) ||
1237 (c->buffer->info[j].lig_comp() && c->buffer->info[j].lig_id() != c->buffer->info[c->buffer->i].lig_id()))
1240 unsigned int mark2_index = (this+mark2Coverage) (c->buffer->info[j].codepoint);
1241 if (mark2_index == NOT_COVERED)
1244 return (this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j);
1247 inline bool sanitize (hb_sanitize_context_t *c) {
1249 return c->check_struct (this)
1250 && mark1Coverage.sanitize (c, this)
1251 && mark2Coverage.sanitize (c, this)
1252 && mark1Array.sanitize (c, this)
1253 && mark2Array.sanitize (c, this, (unsigned int) classCount);
1257 USHORT format; /* Format identifier--format = 1 */
1259 mark1Coverage; /* Offset to Combining Mark1 Coverage
1260 * table--from beginning of MarkMarkPos
1263 mark2Coverage; /* Offset to Combining Mark2 Coverage
1264 * table--from beginning of MarkMarkPos
1266 USHORT classCount; /* Number of defined mark classes */
1268 mark1Array; /* Offset to Mark1Array table--from
1269 * beginning of MarkMarkPos subtable */
1270 OffsetTo<Mark2Array>
1271 mark2Array; /* Offset to Mark2Array table--from
1272 * beginning of MarkMarkPos subtable */
1274 DEFINE_SIZE_STATIC (12);
1279 friend struct PosLookupSubTable;
1282 inline bool apply (hb_apply_context_t *c) const
1286 case 1: return u.format1.apply (c);
1287 default:return false;
1291 inline bool sanitize (hb_sanitize_context_t *c) {
1293 if (!u.format.sanitize (c)) return false;
1295 case 1: return u.format1.sanitize (c);
1296 default:return true;
1302 USHORT format; /* Format identifier */
1303 MarkMarkPosFormat1 format1;
1309 static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index);
1312 struct ContextPos : Context
1314 friend struct PosLookupSubTable;
1317 inline bool apply (hb_apply_context_t *c) const
1320 return Context::apply (c, position_lookup);
1324 struct ChainContextPos : ChainContext
1326 friend struct PosLookupSubTable;
1329 inline bool apply (hb_apply_context_t *c) const
1332 return ChainContext::apply (c, position_lookup);
1337 struct ExtensionPos : Extension
1339 friend struct PosLookupSubTable;
1342 inline const struct PosLookupSubTable& get_subtable (void) const
1344 unsigned int offset = get_offset ();
1345 if (unlikely (!offset)) return Null(PosLookupSubTable);
1346 return StructAtOffset<PosLookupSubTable> (this, offset);
1349 inline bool apply (hb_apply_context_t *c) const;
1351 inline bool sanitize (hb_sanitize_context_t *c);
1361 struct PosLookupSubTable
1363 friend struct PosLookup;
1377 inline bool apply (hb_apply_context_t *c, unsigned int lookup_type) const
1380 switch (lookup_type) {
1381 case Single: return u.single.apply (c);
1382 case Pair: return u.pair.apply (c);
1383 case Cursive: return u.cursive.apply (c);
1384 case MarkBase: return u.markBase.apply (c);
1385 case MarkLig: return u.markLig.apply (c);
1386 case MarkMark: return u.markMark.apply (c);
1387 case Context: return u.c.apply (c);
1388 case ChainContext: return u.chainContext.apply (c);
1389 case Extension: return u.extension.apply (c);
1390 default:return false;
1394 inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
1396 switch (lookup_type) {
1397 case Single: return u.single.sanitize (c);
1398 case Pair: return u.pair.sanitize (c);
1399 case Cursive: return u.cursive.sanitize (c);
1400 case MarkBase: return u.markBase.sanitize (c);
1401 case MarkLig: return u.markLig.sanitize (c);
1402 case MarkMark: return u.markMark.sanitize (c);
1403 case Context: return u.c.sanitize (c);
1404 case ChainContext: return u.chainContext.sanitize (c);
1405 case Extension: return u.extension.sanitize (c);
1406 default:return true;
1416 MarkBasePos markBase;
1418 MarkMarkPos markMark;
1420 ChainContextPos chainContext;
1421 ExtensionPos extension;
1424 DEFINE_SIZE_UNION (2, sub_format);
1428 struct PosLookup : Lookup
1430 inline const PosLookupSubTable& get_subtable (unsigned int i) const
1431 { return this+CastR<OffsetArrayOf<PosLookupSubTable> > (subTable)[i]; }
1433 inline bool apply_once (hb_font_t *font,
1434 hb_buffer_t *buffer,
1435 hb_mask_t lookup_mask,
1436 unsigned int context_length,
1437 unsigned int nesting_level_left) const
1439 unsigned int lookup_type = get_type ();
1440 hb_apply_context_t c[1] = {{0}};
1443 c->face = font->face;
1445 c->direction = buffer->props.direction;
1446 c->lookup_mask = lookup_mask;
1447 c->context_length = context_length;
1448 c->nesting_level_left = nesting_level_left;
1449 c->lookup_props = get_props ();
1451 if (!_hb_ot_layout_check_glyph_property (c->face, &c->buffer->info[c->buffer->i], c->lookup_props, &c->property))
1454 for (unsigned int i = 0; i < get_subtable_count (); i++)
1455 if (get_subtable (i).apply (c, lookup_type))
1461 inline bool apply_string (hb_font_t *font,
1462 hb_buffer_t *buffer,
1463 hb_mask_t mask) const
1467 if (unlikely (!buffer->len))
1471 while (buffer->i < buffer->len)
1473 if ((buffer->info[buffer->i].mask & mask) &&
1474 apply_once (font, buffer, mask, NO_CONTEXT, MAX_NESTING_LEVEL))
1483 inline bool sanitize (hb_sanitize_context_t *c) {
1485 if (unlikely (!Lookup::sanitize (c))) return false;
1486 OffsetArrayOf<PosLookupSubTable> &list = CastR<OffsetArrayOf<PosLookupSubTable> > (subTable);
1487 return list.sanitize (c, this, get_type ());
1491 typedef OffsetListOf<PosLookup> PosLookupList;
1497 struct GPOS : GSUBGPOS
1499 static const hb_tag_t Tag = HB_OT_TAG_GPOS;
1501 inline const PosLookup& get_lookup (unsigned int i) const
1502 { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
1504 inline bool position_lookup (hb_font_t *font,
1505 hb_buffer_t *buffer,
1506 unsigned int lookup_index,
1507 hb_mask_t mask) const
1508 { return get_lookup (lookup_index).apply_string (font, buffer, mask); }
1510 static inline void position_finish (hb_buffer_t *buffer);
1512 inline bool sanitize (hb_sanitize_context_t *c) {
1514 if (unlikely (!GSUBGPOS::sanitize (c))) return false;
1515 OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
1516 return list.sanitize (c, this);
1519 DEFINE_SIZE_STATIC (10);
1524 fix_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
1526 unsigned int j = pos[i].cursive_chain();
1532 pos[i].cursive_chain() = 0;
1534 fix_cursive_minor_offset (pos, j, direction);
1536 if (HB_DIRECTION_IS_HORIZONTAL (direction))
1537 pos[i].y_offset += pos[j].y_offset;
1539 pos[i].x_offset += pos[j].x_offset;
1543 fix_mark_attachment (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
1545 if (likely (!(pos[i].attach_lookback())))
1548 unsigned int j = i - pos[i].attach_lookback();
1550 pos[i].x_advance = 0;
1551 pos[i].y_advance = 0;
1552 pos[i].x_offset += pos[j].x_offset;
1553 pos[i].y_offset += pos[j].y_offset;
1555 if (HB_DIRECTION_IS_FORWARD (direction))
1556 for (unsigned int k = j; k < i; k++) {
1557 pos[i].x_offset -= pos[k].x_advance;
1558 pos[i].y_offset -= pos[k].y_advance;
1561 for (unsigned int k = j + 1; k < i + 1; k++) {
1562 pos[i].x_offset += pos[k].x_advance;
1563 pos[i].y_offset += pos[k].y_advance;
1568 GPOS::position_finish (hb_buffer_t *buffer)
1571 hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
1572 hb_direction_t direction = buffer->props.direction;
1574 /* Handle cursive connections */
1575 for (unsigned int i = 0; i < len; i++)
1577 fix_cursive_minor_offset (pos, i, direction);
1580 /* Handle attachments */
1581 for (unsigned int i = 0; i < len; i++)
1583 fix_mark_attachment (pos, i, direction);
1588 /* Out-of-class implementation for methods recursing */
1590 inline bool ExtensionPos::apply (hb_apply_context_t *c) const
1593 return get_subtable ().apply (c, get_type ());
1596 inline bool ExtensionPos::sanitize (hb_sanitize_context_t *c)
1599 if (unlikely (!Extension::sanitize (c))) return false;
1600 unsigned int offset = get_offset ();
1601 if (unlikely (!offset)) return true;
1602 return StructAtOffset<PosLookupSubTable> (this, offset).sanitize (c, get_type ());
1605 static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index)
1607 const GPOS &gpos = *(c->face->ot_layout->gpos);
1608 const PosLookup &l = gpos.get_lookup (lookup_index);
1610 if (unlikely (c->nesting_level_left == 0))
1613 if (unlikely (c->context_length < 1))
1616 return l.apply_once (c->font, c->buffer, c->lookup_mask, c->context_length, c->nesting_level_left - 1);
1620 #undef attach_lookback
1621 #undef cursive_chain
1626 #endif /* HB_OT_LAYOUT_GPOS_PRIVATE_HH */