2 * Copyright (C) 2007,2008,2009 Red Hat, Inc.
4 * This is part of HarfBuzz, an OpenType Layout engine 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_H
28 #define HB_OT_LAYOUT_GPOS_PRIVATE_H
30 #include "hb-ot-layout-gsubgpos-private.h"
32 #define HB_OT_LAYOUT_GPOS_NO_LAST ((unsigned int) -1)
34 /* Shared Tables: ValueRecord, Anchor Table, and MarkArray */
37 typedef Value ValueRecord[];
39 struct ValueFormat : USHORT
43 xPlacement = 0x0001, /* Includes horizontal adjustment for placement */
44 yPlacement = 0x0002, /* Includes vertical adjustment for placement */
45 xAdvance = 0x0004, /* Includes horizontal adjustment for advance */
46 yAdvance = 0x0008, /* Includes vertical adjustment for advance */
47 xPlaDevice = 0x0010, /* Includes horizontal Device table for placement */
48 yPlaDevice = 0x0020, /* Includes vertical Device table for placement */
49 xAdvDevice = 0x0040, /* Includes horizontal Device table for advance */
50 yAdvDevice = 0x0080, /* Includes vertical Device table for advance */
51 reserved = 0xF000, /* For future use */
54 inline unsigned int get_len () const
56 return _hb_popcount32 ((unsigned int) *this);
59 const void apply_value (hb_ot_layout_t *layout,
62 hb_glyph_position_t *glyph_pos) const
64 unsigned int x_ppem, y_ppem;
65 hb_16dot16_t x_scale, y_scale;
66 unsigned int pixel_value;
67 unsigned int format = *this;
72 /* All fields are options. Only those available advance the value
76 SHORT xPlacement; /* Horizontal adjustment for
77 * placement--in design units */
78 SHORT yPlacement; /* Vertical adjustment for
79 * placement--in design units */
80 SHORT xAdvance; /* Horizontal adjustment for
81 * advance--in design units (only used
82 * for horizontal writing) */
83 SHORT yAdvance; /* Vertical adjustment for advance--in
84 * design units (only used for vertical
86 Offset xPlaDevice; /* Offset to Device table for
87 * horizontal placement--measured from
88 * beginning of PosTable (may be NULL) */
89 Offset yPlaDevice; /* Offset to Device table for vertical
90 * placement--measured from beginning
91 * of PosTable (may be NULL) */
92 Offset xAdvDevice; /* Offset to Device table for
93 * horizontal advance--measured from
94 * beginning of PosTable (may be NULL) */
95 Offset yAdvDevice; /* Offset to Device table for vertical
96 * advance--measured from beginning of
97 * PosTable (may be NULL) */
101 x_scale = layout->gpos_info.x_scale;
102 y_scale = layout->gpos_info.y_scale;
103 /* design units -> fractional pixel */
104 if (format & xPlacement)
105 glyph_pos->x_pos += x_scale * *(USHORT*)values++ / 0x10000;
106 if (format & yPlacement)
107 glyph_pos->y_pos += y_scale * *(USHORT*)values++ / 0x10000;
108 if (format & xAdvance)
109 glyph_pos->x_advance += x_scale * *(USHORT*)values++ / 0x10000;
110 if (format & yAdvance)
111 glyph_pos->y_advance += y_scale * *(USHORT*)values++ / 0x10000;
113 if (HB_LIKELY (!layout->gpos_info.dvi))
115 x_ppem = layout->gpos_info.x_ppem;
116 y_ppem = layout->gpos_info.y_ppem;
117 /* pixel -> fractional pixel */
118 if (format & xPlaDevice)
119 glyph_pos->x_pos += (base+*(OffsetTo<Device>*)values++).get_delta (x_ppem) << 6;
120 if (format & yPlaDevice)
121 glyph_pos->y_pos += (base+*(OffsetTo<Device>*)values++).get_delta (y_ppem) << 6;
122 if (format & xAdvDevice)
123 glyph_pos->x_advance += (base+*(OffsetTo<Device>*)values++).get_delta (x_ppem) << 6;
124 if (format & yAdvDevice)
125 glyph_pos->y_advance += (base+*(OffsetTo<Device>*)values++).get_delta (y_ppem) << 6;
129 ASSERT_SIZE (ValueFormat, 2);
134 friend struct Anchor;
137 inline void get_anchor (hb_ot_layout_t *layout, hb_codepoint_t glyph_id,
138 hb_position_t *x, hb_position_t *y) const
140 *x = layout->gpos_info.x_scale * xCoordinate / 0x10000;
141 *y = layout->gpos_info.y_scale * yCoordinate / 0x10000;
145 USHORT format; /* Format identifier--format = 1 */
146 SHORT xCoordinate; /* Horizontal value--in design units */
147 SHORT yCoordinate; /* Vertical value--in design units */
149 ASSERT_SIZE (AnchorFormat1, 6);
153 friend struct Anchor;
156 inline void get_anchor (hb_ot_layout_t *layout, hb_codepoint_t glyph_id,
157 hb_position_t *x, hb_position_t *y) const
160 *x = layout->gpos_info.x_scale * xCoordinate / 0x10000;
161 *y = layout->gpos_info.y_scale * yCoordinate / 0x10000;
165 USHORT format; /* Format identifier--format = 2 */
166 SHORT xCoordinate; /* Horizontal value--in design units */
167 SHORT yCoordinate; /* Vertical value--in design units */
168 USHORT anchorPoint; /* Index to glyph contour point */
170 ASSERT_SIZE (AnchorFormat2, 8);
174 friend struct Anchor;
177 inline void get_anchor (hb_ot_layout_t *layout, hb_codepoint_t glyph_id,
178 hb_position_t *x, hb_position_t *y) const
180 *x = layout->gpos_info.x_scale * xCoordinate / 0x10000;
181 *y = layout->gpos_info.y_scale * yCoordinate / 0x10000;
183 if (!layout->gpos_info.dvi)
185 *x += (this+xDeviceTable).get_delta (layout->gpos_info.x_ppem) << 6;
186 *y += (this+yDeviceTable).get_delta (layout->gpos_info.y_ppem) << 6;
191 USHORT format; /* Format identifier--format = 3 */
192 SHORT xCoordinate; /* Horizontal value--in design units */
193 SHORT yCoordinate; /* Vertical value--in design units */
195 xDeviceTable; /* Offset to Device table for X
196 * coordinate-- from beginning of
197 * Anchor table (may be NULL) */
199 yDeviceTable; /* Offset to Device table for Y
200 * coordinate-- from beginning of
201 * Anchor table (may be NULL) */
203 ASSERT_SIZE (AnchorFormat3, 10);
207 inline void get_anchor (hb_ot_layout_t *layout, hb_codepoint_t glyph_id,
208 hb_position_t *x, hb_position_t *y) const
212 case 1: u.format1->get_anchor (layout, glyph_id, x, y); return;
213 case 2: u.format2->get_anchor (layout, glyph_id, x, y); return;
214 case 3: u.format3->get_anchor (layout, glyph_id, x, y); return;
221 USHORT format; /* Format identifier */
222 AnchorFormat1 format1[];
223 AnchorFormat2 format2[];
224 AnchorFormat3 format3[];
227 ASSERT_SIZE (Anchor, 2);
232 friend struct MarkArray;
235 USHORT klass; /* Class defined for this mark */
237 markAnchor; /* Offset to Anchor table--from
238 * beginning of MarkArray table */
240 ASSERT_SIZE (MarkRecord, 4);
244 inline unsigned int get_class (unsigned int index) const { return markRecord[index].klass; }
245 inline const Anchor& get_anchor (unsigned int index) const { return this+markRecord[index].markAnchor; }
249 markRecord; /* Array of MarkRecords--in Coverage order */
251 ASSERT_SIZE (MarkArray, 2);
256 struct SinglePosFormat1
258 friend struct SinglePos;
261 inline bool apply (APPLY_ARG_DEF) const
263 unsigned int index = (this+coverage) (IN_CURGLYPH ());
264 if (HB_LIKELY (index == NOT_COVERED))
267 valueFormat.apply_value (layout, (const char *) this, values, CURPOSITION ());
272 USHORT format; /* Format identifier--format = 1 */
274 coverage; /* Offset to Coverage table--from
275 * beginning of subtable */
276 ValueFormat valueFormat; /* Defines the types of data in the
278 ValueRecord values; /* Defines positioning
279 * value(s)--applied to all glyphs in
280 * the Coverage table */
282 ASSERT_SIZE (SinglePosFormat1, 6);
284 struct SinglePosFormat2
286 friend struct SinglePos;
289 inline bool apply (APPLY_ARG_DEF) const
291 unsigned int index = (this+coverage) (IN_CURGLYPH ());
292 if (HB_LIKELY (index == NOT_COVERED))
295 if (HB_LIKELY (index >= valueCount))
298 valueFormat.apply_value (layout, (const char *) this,
299 values + index * valueFormat.get_len (),
305 USHORT format; /* Format identifier--format = 2 */
307 coverage; /* Offset to Coverage table--from
308 * beginning of subtable */
309 ValueFormat valueFormat; /* Defines the types of data in the
311 USHORT valueCount; /* Number of ValueRecords */
312 ValueRecord values; /* Array of ValueRecords--positioning
313 * values applied to glyphs */
315 ASSERT_SIZE (SinglePosFormat2, 8);
319 friend struct PosLookupSubTable;
322 inline bool apply (APPLY_ARG_DEF) const
325 case 1: return u.format1->apply (APPLY_ARG);
326 case 2: return u.format2->apply (APPLY_ARG);
327 default:return false;
333 USHORT format; /* Format identifier */
334 SinglePosFormat1 format1[];
335 SinglePosFormat2 format2[];
338 ASSERT_SIZE (SinglePos, 2);
341 struct PairValueRecord
343 friend struct PairPosFormat1;
346 GlyphID secondGlyph; /* GlyphID of second glyph in the
347 * pair--first glyph is listed in the
349 ValueRecord values; /* Positioning data for the first glyph
350 * followed by for second glyph */
352 ASSERT_SIZE (PairValueRecord, 2);
356 friend struct PairPosFormat1;
359 USHORT len; /* Number of PairValueRecords */
362 array[]; /* Array of PairValueRecords--ordered
363 * by GlyphID of the second glyph */
365 ASSERT_SIZE (PairSet, 2);
367 struct PairPosFormat1
369 friend struct PairPos;
372 inline bool apply (APPLY_ARG_DEF) const
374 unsigned int end = MIN (buffer->in_length, buffer->in_pos + context_length);
375 if (HB_UNLIKELY (buffer->in_pos + 2 > end))
378 unsigned int index = (this+coverage) (IN_CURGLYPH ());
379 if (HB_LIKELY (index == NOT_COVERED))
382 unsigned int j = buffer->in_pos + 1;
383 while (!_hb_ot_layout_check_glyph_property (layout, IN_INFO (j), lookup_flag, &property))
385 if (HB_UNLIKELY (j == end))
390 const PairSet &pair_set = this+pairSet[index];
392 unsigned int len1 = valueFormat1.get_len ();
393 unsigned int len2 = valueFormat2.get_len ();
394 unsigned int record_len = 1 + len1 + len2;
396 unsigned int count = pair_set.len;
397 const PairValueRecord *record = pair_set.array;
398 for (unsigned int i = 0; i < count; i++)
400 if (IN_GLYPH (j) == record->secondGlyph)
402 valueFormat1.apply_value (layout, (const char *) this, record->values, CURPOSITION ());
403 valueFormat2.apply_value (layout, (const char *) this, record->values + len1, POSITION (j));
409 record += record_len;
416 USHORT format; /* Format identifier--format = 1 */
418 coverage; /* Offset to Coverage table--from
419 * beginning of subtable */
420 ValueFormat valueFormat1; /* Defines the types of data in
421 * ValueRecord1--for the first glyph
422 * in the pair--may be zero (0) */
423 ValueFormat valueFormat2; /* Defines the types of data in
424 * ValueRecord2--for the second glyph
425 * in the pair--may be zero (0) */
426 OffsetArrayOf<PairSet>
427 pairSet; /* Array of PairSet tables
428 * ordered by Coverage Index */
430 ASSERT_SIZE (PairPosFormat1, 10);
432 struct PairPosFormat2
434 friend struct PairPos;
437 inline bool apply (APPLY_ARG_DEF) const
439 unsigned int end = MIN (buffer->in_length, buffer->in_pos + context_length);
440 if (HB_UNLIKELY (buffer->in_pos + 2 > end))
443 unsigned int index = (this+coverage) (IN_CURGLYPH ());
444 if (HB_LIKELY (index == NOT_COVERED))
447 unsigned int j = buffer->in_pos + 1;
448 while (!_hb_ot_layout_check_glyph_property (layout, IN_INFO (j), lookup_flag, &property))
450 if (HB_UNLIKELY (j == end))
455 unsigned int len1 = valueFormat1.get_len ();
456 unsigned int len2 = valueFormat2.get_len ();
457 unsigned int record_len = len1 + len2;
459 unsigned int klass1 = (this+classDef1) (IN_CURGLYPH ());
460 unsigned int klass2 = (this+classDef2) (IN_GLYPH (j));
461 if (HB_UNLIKELY (klass1 >= class1Count || klass2 >= class2Count))
464 const Value *v = values + record_len * (klass1 * class2Count + klass2);
465 valueFormat1.apply_value (layout, (const char *) this, v, CURPOSITION ());
466 valueFormat2.apply_value (layout, (const char *) this, v + len1, POSITION (j));
477 USHORT format; /* Format identifier--format = 2 */
479 coverage; /* Offset to Coverage table--from
480 * beginning of subtable */
481 ValueFormat valueFormat1; /* ValueRecord definition--for the
482 * first glyph of the pair--may be zero
484 ValueFormat valueFormat2; /* ValueRecord definition--for the
485 * second glyph of the pair--may be
488 classDef1; /* Offset to ClassDef table--from
489 * beginning of PairPos subtable--for
490 * the first glyph of the pair */
492 classDef2; /* Offset to ClassDef table--from
493 * beginning of PairPos subtable--for
494 * the second glyph of the pair */
495 USHORT class1Count; /* Number of classes in ClassDef1
496 * table--includes Class0 */
497 USHORT class2Count; /* Number of classes in ClassDef2
498 * table--includes Class0 */
499 ValueRecord values; /* Matrix of value pairs:
500 * class1-major, class2-minor,
501 * Each entry has value1 and value2 */
503 ASSERT_SIZE (PairPosFormat2, 16);
507 friend struct PosLookupSubTable;
510 inline bool apply (APPLY_ARG_DEF) const
513 case 1: return u.format1->apply (APPLY_ARG);
514 case 2: return u.format2->apply (APPLY_ARG);
515 default:return false;
521 USHORT format; /* Format identifier */
522 PairPosFormat1 format1[];
523 PairPosFormat2 format2[];
526 ASSERT_SIZE (PairPos, 2);
529 struct EntryExitRecord
532 entryAnchor; /* Offset to EntryAnchor table--from
533 * beginning of CursivePos
534 * subtable--may be NULL */
536 exitAnchor; /* Offset to ExitAnchor table--from
537 * beginning of CursivePos
538 * subtable--may be NULL */
540 ASSERT_SIZE (EntryExitRecord, 4);
542 struct CursivePosFormat1
544 friend struct CursivePos;
547 inline bool apply (APPLY_ARG_DEF) const
549 /* Now comes the messiest part of the whole OpenType
550 specification. At first glance, cursive connections seem easy
551 to understand, but there are pitfalls! The reason is that
552 the specs don't mention how to compute the advance values
553 resp. glyph offsets. I was told it would be an omission, to
554 be fixed in the next OpenType version... Again many thanks to
555 Andrei Burago <andreib@microsoft.com> for clarifications.
557 Consider the following example:
570 glyph1: advance width = 12
573 glyph2: advance width = 11
576 LSB is 1 for both glyphs (so the boxes drawn above are glyph
577 bboxes). Writing direction is R2L; `0' denotes the glyph's
580 Now the surprising part: The advance width of the *left* glyph
581 (resp. of the *bottom* glyph) will be modified, no matter
582 whether the writing direction is L2R or R2L (resp. T2B or
583 B2T)! This assymetry is caused by the fact that the glyph's
584 coordinate origin is always the lower left corner for all
587 Continuing the above example, we can compute the new
588 (horizontal) advance width of glyph2 as
592 and the new vertical offset of glyph2 as
597 Vertical writing direction is far more complicated:
599 a) Assuming that we recompute the advance height of the lower glyph:
606 yadv2 | 0+--+------+ -- BSB1 --
609 BSB2 -- 0+--------+ --
612 glyph1: advance height = 6
615 glyph2: advance height = 7
618 TSB is 1 for both glyphs; writing direction is T2B.
621 BSB1 = yadv1 - (TSB1 + ymax1)
622 BSB2 = yadv2 - (TSB2 + ymax2)
625 vertical advance width of glyph2
626 = y_offset + BSB2 - BSB1
627 = (y2 - y1) + (yadv2 - (TSB2 + ymax2)) - (yadv1 - (TSB1 + ymax1))
628 = y2 - y1 + yadv2 - TSB2 - ymax2 - (yadv1 - TSB1 - ymax1)
629 = y2 - y1 + yadv2 - TSB2 - ymax2 - yadv1 + TSB1 + ymax1
632 b) Assuming that we recompute the advance height of the upper glyph:
637 TSB2 -- +-----+--+ 1 | yadv1 ymax1
639 yadv2 | 0+--+------+ -- --
640 ymax2 | 2 | -- y_offset
645 glyph1: advance height = 6
648 glyph2: advance height = 7
651 TSB is 1 for both glyphs; writing direction is T2B.
655 vertical advance width of glyph2
656 = TSB1 + ymax1 + y_offset - (TSB2 + ymax2)
657 = TSB1 + ymax1 + y2 - y1 - TSB2 - ymax2
660 Comparing a) with b) shows that b) is easier to compute. I'll wait
661 for a reply from Andrei to see what should really be implemented...
663 Since horizontal advance widths or vertical advance heights
664 can be used alone but not together, no ambiguity occurs. */
666 struct hb_ot_layout_t::gpos_info_t *gpi = &layout->gpos_info;
667 hb_codepoint_t last_pos = gpi->last;
668 gpi->last = HB_OT_LAYOUT_GPOS_NO_LAST;
670 /* We don't handle mark glyphs here. */
671 if (property == HB_OT_LAYOUT_GLYPH_CLASS_MARK)
674 unsigned int index = (this+coverage) (IN_CURGLYPH ());
675 if (HB_LIKELY (index == NOT_COVERED))
678 const EntryExitRecord &record = entryExitRecord[index];
680 hb_position_t entry_x, entry_y, exit_x, exit_y;
682 if (last_pos == HB_OT_LAYOUT_GPOS_NO_LAST || !record.entryAnchor)
685 (this+record.entryAnchor).get_anchor (layout, IN_CURGLYPH (), &entry_x, &entry_y);
689 POSITION (buffer->in_pos)->x_advance = entry_x - gpi->anchor_x;
690 POSITION (buffer->in_pos)->new_advance = TRUE;
694 POSITION (last_pos)->x_advance = gpi->anchor_x - entry_x;
695 POSITION (last_pos)->new_advance = TRUE;
698 if (lookup_flag & LookupFlag::RightToLeft)
700 POSITION (last_pos)->cursive_chain = last_pos - buffer->in_pos;
701 POSITION (last_pos)->y_pos = entry_y - gpi->anchor_y;
705 POSITION (buffer->in_pos)->cursive_chain = buffer->in_pos - last_pos;
706 POSITION (buffer->in_pos)->y_pos = gpi->anchor_y - entry_y;
710 if (record.exitAnchor)
712 gpi->last = buffer->in_pos;
713 (this+record.exitAnchor).get_anchor (layout, IN_CURGLYPH (), &gpi->anchor_x, &gpi->anchor_y);
721 USHORT format; /* Format identifier--format = 1 */
723 coverage; /* Offset to Coverage table--from
724 * beginning of subtable */
725 ArrayOf<EntryExitRecord>
726 entryExitRecord; /* Array of EntryExit records--in
727 * Coverage Index order */
729 ASSERT_SIZE (CursivePosFormat1, 6);
733 friend struct PosLookupSubTable;
736 inline bool apply (APPLY_ARG_DEF) const
739 case 1: return u.format1->apply (APPLY_ARG);
740 default:return false;
746 USHORT format; /* Format identifier */
747 CursivePosFormat1 format1[];
750 ASSERT_SIZE (CursivePos, 2);
755 friend struct MarkBasePosFormat1;
758 USHORT len; /* Number of rows */
760 matrix[]; /* Matrix of offsets to Anchor tables--
761 * from beginning of BaseArray table--
762 * base-major--in order of
763 * BaseCoverage Index--, mark-minor--
764 * ordered by class--zero-based. */
766 ASSERT_SIZE (BaseArray, 2);
768 struct MarkBasePosFormat1
770 friend struct MarkBasePos;
773 inline bool apply (APPLY_ARG_DEF) const
775 if (lookup_flag & LookupFlag::IgnoreBaseGlyphs)
778 unsigned int mark_index = (this+markCoverage) (IN_CURGLYPH ());
779 if (HB_LIKELY (mark_index == NOT_COVERED))
782 /* now we search backwards for a non-mark glyph */
783 unsigned int count = buffer->in_pos;
784 unsigned int i = 1, j = count - 1;
787 property = _hb_ot_layout_get_glyph_property (layout, IN_GLYPH (j));
788 if (!(property == HB_OT_LAYOUT_GLYPH_CLASS_MARK || property & LookupFlag::MarkAttachmentType))
792 if (HB_UNLIKELY (i > buffer->in_pos))
795 /* The following assertion is too strong -- at least for mangal.ttf. */
797 if (property != HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH)
801 unsigned int base_index = (this+baseCoverage) (IN_GLYPH (j));
802 if (base_index == NOT_COVERED)
805 const MarkArray& mark_array = this+markArray;
806 const BaseArray& base_array = this+baseArray;
808 unsigned int mark_class = mark_array.get_class (mark_index);
809 const Anchor& mark_anchor = mark_array.get_anchor (mark_index);
811 if (HB_UNLIKELY (mark_class >= classCount || base_index >= base_array.len))
814 hb_position_t mark_x, mark_y, base_x, base_y;
816 mark_anchor.get_anchor (layout, IN_CURGLYPH (), &mark_x, &mark_y);
817 unsigned int index = base_index * classCount + mark_class;
818 (&base_array+base_array.matrix[index]).get_anchor (layout, IN_GLYPH (j), &base_x, &base_y);
820 hb_glyph_position_t *o = POSITION (buffer->in_pos);
821 o->x_pos = base_x - mark_x;
822 o->y_pos = base_y - mark_y;
832 USHORT format; /* Format identifier--format = 1 */
834 markCoverage; /* Offset to MarkCoverage table--from
835 * beginning of MarkBasePos subtable */
837 baseCoverage; /* Offset to BaseCoverage table--from
838 * beginning of MarkBasePos subtable */
839 USHORT classCount; /* Number of classes defined for marks */
841 markArray; /* Offset to MarkArray table--from
842 * beginning of MarkBasePos subtable */
844 baseArray; /* Offset to BaseArray table--from
845 * beginning of MarkBasePos subtable */
847 ASSERT_SIZE (MarkBasePosFormat1, 12);
851 friend struct PosLookupSubTable;
854 inline bool apply (APPLY_ARG_DEF) const
857 case 1: return u.format1->apply (APPLY_ARG);
858 default:return false;
864 USHORT format; /* Format identifier */
865 MarkBasePosFormat1 format1[];
868 ASSERT_SIZE (MarkBasePos, 2);
871 struct LigatureAttach
873 friend struct MarkLigPosFormat1;
876 USHORT len; /* Number of ComponentRecords in this
877 * ligature, ie. number of rows */
879 matrix[]; /* Matrix of offsets to Anchor tables--
880 * from beginning of LigatureAttach table--
881 * component-major--in order of
882 * writing direction--, mark-minor--
883 * ordered by class--zero-based. */
885 ASSERT_SIZE (LigatureAttach, 2);
887 typedef OffsetArrayOf<LigatureAttach> LigatureArray;
888 /* Array of LigatureAttach
890 * LigatureCoverage Index */
891 ASSERT_SIZE (LigatureArray, 2);
893 struct MarkLigPosFormat1
895 friend struct MarkLigPos;
898 inline bool apply (APPLY_ARG_DEF) const
900 if (lookup_flag & LookupFlag::IgnoreLigatures)
903 unsigned int mark_index = (this+markCoverage) (IN_CURGLYPH ());
904 if (HB_LIKELY (mark_index == NOT_COVERED))
907 /* now we search backwards for a non-mark glyph */
908 unsigned int count = buffer->in_pos;
909 unsigned int i = 1, j = count - 1;
912 property = _hb_ot_layout_get_glyph_property (layout, IN_GLYPH (j));
913 if (!(property == HB_OT_LAYOUT_GLYPH_CLASS_MARK || property & LookupFlag::MarkAttachmentType))
917 if (HB_UNLIKELY (i > buffer->in_pos))
920 /* The following assertion is too strong -- at least for mangal.ttf. */
922 if (property != HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE)
926 unsigned int lig_index = (this+ligatureCoverage) (IN_GLYPH (j));
927 if (lig_index == NOT_COVERED)
930 const MarkArray& mark_array = this+markArray;
931 const LigatureArray& lig_array = this+ligatureArray;
933 unsigned int mark_class = mark_array.get_class (mark_index);
934 const Anchor& mark_anchor = mark_array.get_anchor (mark_index);
936 if (HB_UNLIKELY (mark_class >= classCount || lig_index >= lig_array.len))
939 const LigatureAttach& lig_attach = &lig_array+lig_array[lig_index];
940 count = lig_attach.len;
941 if (HB_UNLIKELY (!count))
944 unsigned int comp_index;
945 /* We must now check whether the ligature ID of the current mark glyph
946 * is identical to the ligature ID of the found ligature. If yes, we
947 * can directly use the component index. If not, we attach the mark
948 * glyph to the last component of the ligature. */
949 if (IN_LIGID (j) == IN_LIGID (buffer->in_pos))
951 comp_index = IN_COMPONENT (buffer->in_pos);
952 if (comp_index >= count)
953 comp_index = count - 1;
956 comp_index = count - 1;
958 hb_position_t mark_x, mark_y, lig_x, lig_y;
960 mark_anchor.get_anchor (layout, IN_CURGLYPH (), &mark_x, &mark_y);
961 unsigned int index = comp_index * classCount + mark_class;
962 (&lig_attach+lig_attach.matrix[index]).get_anchor (layout, IN_GLYPH (j), &lig_x, &lig_y);
964 hb_glyph_position_t *o = POSITION (buffer->in_pos);
965 o->x_pos = lig_x - mark_x;
966 o->y_pos = lig_y - mark_y;
976 USHORT format; /* Format identifier--format = 1 */
978 markCoverage; /* Offset to Mark Coverage table--from
979 * beginning of MarkLigPos subtable */
981 ligatureCoverage; /* Offset to Ligature Coverage
982 * table--from beginning of MarkLigPos
984 USHORT classCount; /* Number of defined mark classes */
986 markArray; /* Offset to MarkArray table--from
987 * beginning of MarkLigPos subtable */
988 OffsetTo<LigatureArray>
989 ligatureArray; /* Offset to LigatureArray table--from
990 * beginning of MarkLigPos subtable */
992 ASSERT_SIZE (MarkLigPosFormat1, 12);
996 friend struct PosLookupSubTable;
999 inline bool apply (APPLY_ARG_DEF) const
1002 case 1: return u.format1->apply (APPLY_ARG);
1003 default:return false;
1009 USHORT format; /* Format identifier */
1010 MarkLigPosFormat1 format1[];
1013 ASSERT_SIZE (MarkLigPos, 2);
1018 friend struct MarkMarkPosFormat1;
1021 USHORT len; /* Number of rows */
1023 matrix[]; /* Matrix of offsets to Anchor tables--
1024 * from beginning of Mark2Array table--
1025 * mark2-major--in order of
1026 * Mark2Coverage Index--, mark1-minor--
1027 * ordered by class--zero-based. */
1029 ASSERT_SIZE (Mark2Array, 2);
1031 struct MarkMarkPosFormat1
1033 friend struct MarkMarkPos;
1036 inline bool apply (APPLY_ARG_DEF) const
1038 if (lookup_flag & LookupFlag::IgnoreMarks)
1041 unsigned int mark1_index = (this+mark1Coverage) (IN_CURGLYPH ());
1042 if (HB_LIKELY (mark1_index == NOT_COVERED))
1045 /* now we search backwards for a suitable mark glyph until a non-mark glyph */
1046 unsigned int count = buffer->in_pos;
1047 unsigned int i = 1, j = count - 1;
1050 property = _hb_ot_layout_get_glyph_property (layout, IN_GLYPH (j));
1051 if (!(property == HB_OT_LAYOUT_GLYPH_CLASS_MARK || property & LookupFlag::MarkAttachmentType))
1053 if (!(lookup_flag & LookupFlag::MarkAttachmentType) ||
1054 (lookup_flag & LookupFlag::MarkAttachmentType) == property)
1058 if (HB_UNLIKELY (i > buffer->in_pos))
1061 unsigned int mark2_index = (this+mark2Coverage) (IN_GLYPH (j));
1062 if (mark2_index == NOT_COVERED)
1065 const MarkArray& mark1_array = this+mark1Array;
1066 const Mark2Array& mark2_array = this+mark2Array;
1068 unsigned int mark1_class = mark1_array.get_class (mark1_index);
1069 const Anchor& mark1_anchor = mark1_array.get_anchor (mark1_index);
1071 if (HB_UNLIKELY (mark1_class >= classCount || mark2_index >= mark2_array.len))
1074 hb_position_t mark1_x, mark1_y, mark2_x, mark2_y;
1076 mark1_anchor.get_anchor (layout, IN_CURGLYPH (), &mark1_x, &mark1_y);
1077 unsigned int index = mark2_index * classCount + mark1_class;
1078 (&mark2_array+mark2_array.matrix[index]).get_anchor (layout, IN_GLYPH (j), &mark2_x, &mark2_y);
1080 hb_glyph_position_t *o = POSITION (buffer->in_pos);
1081 o->x_pos = mark2_x - mark1_x;
1082 o->y_pos = mark2_y - mark1_y;
1092 USHORT format; /* Format identifier--format = 1 */
1094 mark1Coverage; /* Offset to Combining Mark1 Coverage
1095 * table--from beginning of MarkMarkPos
1098 mark2Coverage; /* Offset to Combining Mark2 Coverage
1099 * table--from beginning of MarkMarkPos
1101 USHORT classCount; /* Number of defined mark classes */
1103 mark1Array; /* Offset to Mark1Array table--from
1104 * beginning of MarkMarkPos subtable */
1105 OffsetTo<Mark2Array>
1106 mark2Array; /* Offset to Mark2Array table--from
1107 * beginning of MarkMarkPos subtable */
1109 ASSERT_SIZE (MarkMarkPosFormat1, 12);
1113 friend struct PosLookupSubTable;
1116 inline bool apply (APPLY_ARG_DEF) const
1119 case 1: return u.format1->apply (APPLY_ARG);
1120 default:return false;
1126 USHORT format; /* Format identifier */
1127 MarkMarkPosFormat1 format1[];
1130 ASSERT_SIZE (MarkMarkPos, 2);
1133 static inline bool position_lookup (APPLY_ARG_DEF, unsigned int lookup_index);
1135 struct ContextPos : Context
1137 friend struct PosLookupSubTable;
1140 inline bool apply (APPLY_ARG_DEF) const
1142 return Context::apply (APPLY_ARG, position_lookup);
1145 ASSERT_SIZE (ContextPos, 2);
1147 struct ChainContextPos : ChainContext
1149 friend struct PosLookupSubTable;
1152 inline bool apply (APPLY_ARG_DEF) const
1154 return ChainContext::apply (APPLY_ARG, position_lookup);
1157 ASSERT_SIZE (ChainContextPos, 2);
1160 struct ExtensionPos : Extension
1162 friend struct PosLookupSubTable;
1165 inline bool apply (APPLY_ARG_DEF) const;
1167 ASSERT_SIZE (ExtensionPos, 2);
1176 struct PosLookupSubTable
1178 friend struct PosLookup;
1192 bool apply (APPLY_ARG_DEF, unsigned int lookup_type) const
1194 switch (lookup_type) {
1195 case Single: return u.single->apply (APPLY_ARG);
1196 case Pair: return u.pair->apply (APPLY_ARG);
1197 case Cursive: return u.cursive->apply (APPLY_ARG);
1198 case MarkBase: return u.markBase->apply (APPLY_ARG);
1199 case MarkLig: return u.markLig->apply (APPLY_ARG);
1200 case MarkMark: return u.markMark->apply (APPLY_ARG);
1201 case Context: return u.context->apply (APPLY_ARG);
1202 case ChainContext: return u.chainContext->apply (APPLY_ARG);
1203 case Extension: return u.extension->apply (APPLY_ARG);
1204 default:return false;
1213 CursivePos cursive[];
1214 MarkBasePos markBase[];
1215 MarkLigPos markLig[];
1216 MarkMarkPos markMark[];
1217 ContextPos context[];
1218 ChainContextPos chainContext[];
1219 ExtensionPos extension[];
1222 ASSERT_SIZE (PosLookupSubTable, 2);
1225 struct PosLookup : Lookup
1227 inline const PosLookupSubTable& get_subtable (unsigned int i) const
1229 return (const PosLookupSubTable&) Lookup::get_subtable (i);
1232 /* Like get_type(), but looks through extension lookups.
1233 * Never returns Extension */
1234 inline unsigned int get_effective_type (void) const
1236 unsigned int type = get_type ();
1238 if (HB_UNLIKELY (type == PosLookupSubTable::Extension))
1240 unsigned int count = get_subtable_count ();
1241 type = get_subtable(0).u.extension->get_type ();
1242 /* The spec says all subtables should have the same type.
1243 * This is specially important if one has a reverse type! */
1244 for (unsigned int i = 1; i < count; i++)
1245 if (get_subtable(i).u.extension->get_type () != type)
1252 inline bool apply_once (hb_ot_layout_t *layout,
1253 hb_buffer_t *buffer,
1254 unsigned int context_length,
1255 unsigned int nesting_level_left) const
1257 unsigned int lookup_type = get_type ();
1258 unsigned int lookup_flag = get_flag ();
1259 unsigned int property;
1261 if (!_hb_ot_layout_check_glyph_property (layout, IN_CURINFO (), lookup_flag, &property))
1264 for (unsigned int i = 0; i < get_subtable_count (); i++)
1265 if (get_subtable (i).apply (APPLY_ARG, lookup_type))
1271 bool apply_string (hb_ot_layout_t *layout,
1272 hb_buffer_t *buffer,
1273 hb_ot_layout_feature_mask_t mask) const
1277 if (HB_UNLIKELY (!buffer->in_length))
1280 layout->gpos_info.last = HB_OT_LAYOUT_GPOS_NO_LAST; /* no last valid glyph for cursive pos. */
1283 while (buffer->in_pos < buffer->in_length)
1286 if (~IN_PROPERTIES (buffer->in_pos) & mask)
1288 done = apply_once (layout, buffer, NO_CONTEXT, MAX_NESTING_LEVEL);
1294 /* Contrary to properties defined in GDEF, user-defined properties
1295 will always stop a possible cursive positioning. */
1296 layout->gpos_info.last = HB_OT_LAYOUT_GPOS_NO_LAST;
1306 ASSERT_SIZE (PosLookup, 6);
1313 struct GPOS : GSUBGPOS
1315 static const hb_tag_t Tag = HB_TAG ('G','P','O','S');
1317 static inline const GPOS& get_for_data (const char *data)
1319 return (const GPOS&) GSUBGPOS::get_for_data (data);
1322 inline const PosLookup& get_lookup (unsigned int i) const
1324 return (const PosLookup&) GSUBGPOS::get_lookup (i);
1327 inline bool position_lookup (hb_ot_layout_t *layout,
1328 hb_buffer_t *buffer,
1329 unsigned int lookup_index,
1330 hb_ot_layout_feature_mask_t mask) const
1332 return get_lookup (lookup_index).apply_string (layout, buffer, mask);
1336 ASSERT_SIZE (GPOS, 10);
1339 /* Out-of-class implementation for methods recursing */
1341 inline bool ExtensionPos::apply (APPLY_ARG_DEF) const
1343 unsigned int lookup_type = get_type ();
1345 if (HB_UNLIKELY (lookup_type == PosLookupSubTable::Extension))
1348 return ((PosLookupSubTable&) get_subtable ()).apply (APPLY_ARG, lookup_type);
1351 static inline bool position_lookup (APPLY_ARG_DEF, unsigned int lookup_index)
1353 const GPOS &gpos = *(layout->gpos);
1354 const PosLookup &l = gpos.get_lookup (lookup_index);
1356 if (HB_UNLIKELY (nesting_level_left == 0))
1358 nesting_level_left--;
1360 if (HB_UNLIKELY (context_length < 1))
1363 return l.apply_once (layout, buffer, context_length, nesting_level_left);
1367 #endif /* HB_OT_LAYOUT_GPOS_PRIVATE_H */