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"
33 #define HB_OT_LAYOUT_GPOS_NO_LAST ((unsigned int) -1)
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 () const
86 { return _hb_popcount32 ((unsigned int) *this); }
87 inline unsigned int get_size () const
88 { return get_len () * Value::static_size; }
90 void apply_value (hb_ot_layout_context_t *layout,
93 hb_internal_glyph_position_t &glyph_pos) const
95 unsigned int x_ppem, y_ppem;
96 hb_16dot16_t x_scale, y_scale;
97 unsigned int format = *this;
101 x_scale = layout->font->x_scale;
102 y_scale = layout->font->y_scale;
103 /* design units -> fractional pixel */
104 if (format & xPlacement) glyph_pos.x_offset += _hb_16dot16_mul_round (x_scale, get_short (values++));
105 if (format & yPlacement) glyph_pos.y_offset += _hb_16dot16_mul_round (y_scale, get_short (values++));
106 if (format & xAdvance) glyph_pos.x_advance += _hb_16dot16_mul_round (x_scale, get_short (values++));
107 if (format & yAdvance) glyph_pos.y_advance += _hb_16dot16_mul_round (y_scale, get_short (values++));
109 if (!has_device ()) return;
111 x_ppem = layout->font->x_ppem;
112 y_ppem = layout->font->y_ppem;
114 if (!x_ppem && !y_ppem) return;
116 /* pixel -> fractional pixel */
117 if (format & xPlaDevice) {
118 if (x_ppem) glyph_pos.x_offset += (base + get_device (values++)).get_delta (x_ppem) << 16; else values++;
120 if (format & yPlaDevice) {
121 if (y_ppem) glyph_pos.y_offset += (base + get_device (values++)).get_delta (y_ppem) << 16; else values++;
123 if (format & xAdvDevice) {
124 if (x_ppem) glyph_pos.x_advance += (base + get_device (values++)).get_delta (x_ppem) << 16; else values++;
126 if (format & yAdvDevice) {
127 if (y_ppem) glyph_pos.y_advance += (base + get_device (values++)).get_delta (y_ppem) << 16; else values++;
132 inline bool sanitize_value_devices (hb_sanitize_context_t *c, void *base, Value *values) {
133 unsigned int format = *this;
135 if (format & xPlacement) values++;
136 if (format & yPlacement) values++;
137 if (format & xAdvance) values++;
138 if (format & yAdvance) values++;
140 if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
141 if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
142 if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
143 if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
148 static inline OffsetTo<Device>& get_device (Value* value)
149 { return *CastP<OffsetTo<Device> > (value); }
150 static inline const OffsetTo<Device>& get_device (const Value* value)
151 { return *CastP<OffsetTo<Device> > (value); }
153 static inline const SHORT& get_short (const Value* value)
154 { return *CastP<SHORT> (value); }
158 inline bool has_device () const {
159 unsigned int format = *this;
160 return (format & devices) != 0;
163 inline bool sanitize_value (hb_sanitize_context_t *c, void *base, Value *values) {
165 return c->check_range (values, get_size ())
166 && (!has_device () || sanitize_value_devices (c, base, values));
169 inline bool sanitize_values (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count) {
171 unsigned int len = get_len ();
173 if (!c->check_array (values, get_size (), count)) return false;
175 if (!has_device ()) return true;
177 for (unsigned int i = 0; i < count; i++) {
178 if (!sanitize_value_devices (c, base, values))
186 /* Just sanitize referenced Device tables. Doesn't check the values themselves. */
187 inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count, unsigned int stride) {
190 if (!has_device ()) return true;
192 for (unsigned int i = 0; i < count; i++) {
193 if (!sanitize_value_devices (c, base, values))
205 friend struct Anchor;
208 inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id HB_UNUSED,
209 hb_position_t *x, hb_position_t *y) const
211 *x = _hb_16dot16_mul_round (layout->font->x_scale, xCoordinate);
212 *y = _hb_16dot16_mul_round (layout->font->y_scale, yCoordinate);
215 inline bool sanitize (hb_sanitize_context_t *c) {
217 return c->check_struct (this);
221 USHORT format; /* Format identifier--format = 1 */
222 SHORT xCoordinate; /* Horizontal value--in design units */
223 SHORT yCoordinate; /* Vertical value--in design units */
225 DEFINE_SIZE_STATIC (6);
230 friend struct Anchor;
233 inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id,
234 hb_position_t *x, hb_position_t *y) const
236 unsigned int x_ppem = layout->font->x_ppem;
237 unsigned int y_ppem = layout->font->y_ppem;
238 hb_position_t cx, cy;
241 if (x_ppem || y_ppem)
242 ret = hb_font_get_contour_point (layout->font, layout->face, anchorPoint, glyph_id, &cx, &cy);
243 *x = x_ppem && ret ? cx : _hb_16dot16_mul_round (layout->font->x_scale, xCoordinate);
244 *y = y_ppem && ret ? cy : _hb_16dot16_mul_round (layout->font->y_scale, yCoordinate);
247 inline bool sanitize (hb_sanitize_context_t *c) {
249 return c->check_struct (this);
253 USHORT format; /* Format identifier--format = 2 */
254 SHORT xCoordinate; /* Horizontal value--in design units */
255 SHORT yCoordinate; /* Vertical value--in design units */
256 USHORT anchorPoint; /* Index to glyph contour point */
258 DEFINE_SIZE_STATIC (8);
263 friend struct Anchor;
266 inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id HB_UNUSED,
267 hb_position_t *x, hb_position_t *y) const
269 *x = _hb_16dot16_mul_round (layout->font->x_scale, xCoordinate);
270 *y = _hb_16dot16_mul_round (layout->font->y_scale, yCoordinate);
272 /* pixel -> fractional pixel */
273 if (layout->font->x_ppem)
274 *x += (this+xDeviceTable).get_delta (layout->font->x_ppem) << 16;
275 if (layout->font->y_ppem)
276 *y += (this+yDeviceTable).get_delta (layout->font->y_ppem) << 16;
279 inline bool sanitize (hb_sanitize_context_t *c) {
281 return c->check_struct (this)
282 && xDeviceTable.sanitize (c, this)
283 && yDeviceTable.sanitize (c, this);
287 USHORT format; /* Format identifier--format = 3 */
288 SHORT xCoordinate; /* Horizontal value--in design units */
289 SHORT yCoordinate; /* Vertical value--in design units */
291 xDeviceTable; /* Offset to Device table for X
292 * coordinate-- from beginning of
293 * Anchor table (may be NULL) */
295 yDeviceTable; /* Offset to Device table for Y
296 * coordinate-- from beginning of
297 * Anchor table (may be NULL) */
299 DEFINE_SIZE_STATIC (10);
304 inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id,
305 hb_position_t *x, hb_position_t *y) const
309 case 1: u.format1.get_anchor (layout, glyph_id, x, y); return;
310 case 2: u.format2.get_anchor (layout, glyph_id, x, y); return;
311 case 3: u.format3.get_anchor (layout, glyph_id, x, y); return;
316 inline bool sanitize (hb_sanitize_context_t *c) {
318 if (!u.format.sanitize (c)) return false;
320 case 1: return u.format1.sanitize (c);
321 case 2: return u.format2.sanitize (c);
322 case 3: return u.format3.sanitize (c);
329 USHORT format; /* Format identifier */
330 AnchorFormat1 format1;
331 AnchorFormat2 format2;
332 AnchorFormat3 format3;
335 DEFINE_SIZE_UNION (2, format);
341 inline const Anchor& get_anchor (unsigned int row, unsigned int col, unsigned int cols) const {
342 if (unlikely (row >= rows || col >= cols)) return Null(Anchor);
343 return this+matrix[row * cols + col];
346 inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) {
348 if (!c->check_struct (this)) return false;
349 if (unlikely (cols >= ((unsigned int) -1) / rows)) return false;
350 unsigned int count = rows * cols;
351 if (!c->check_array (matrix, matrix[0].static_size, count)) return false;
352 for (unsigned int i = 0; i < count; i++)
353 if (!matrix[i].sanitize (c, this)) return false;
357 USHORT rows; /* Number of rows */
360 matrix[VAR]; /* Matrix of offsets to Anchor tables--
361 * from beginning of AnchorMatrix table */
363 DEFINE_SIZE_ARRAY (2, matrix);
369 friend struct MarkArray;
371 inline bool sanitize (hb_sanitize_context_t *c, void *base) {
373 return c->check_struct (this)
374 && markAnchor.sanitize (c, base);
378 USHORT klass; /* Class defined for this mark */
380 markAnchor; /* Offset to Anchor table--from
381 * beginning of MarkArray table */
383 DEFINE_SIZE_STATIC (4);
386 struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage order */
388 inline bool apply (hb_apply_context_t *c,
389 unsigned int mark_index, unsigned int glyph_index,
390 const AnchorMatrix &anchors, unsigned int class_count,
391 unsigned int glyph_pos) const
394 const MarkRecord &record = ArrayOf<MarkRecord>::operator[](mark_index);
395 unsigned int mark_class = record.klass;
397 const Anchor& mark_anchor = this + record.markAnchor;
398 const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count);
400 hb_position_t mark_x, mark_y, base_x, base_y;
402 mark_anchor.get_anchor (c->layout, c->buffer->info[c->buffer->in_pos].codepoint, &mark_x, &mark_y);
403 glyph_anchor.get_anchor (c->layout, c->buffer->info[glyph_pos].codepoint, &base_x, &base_y);
405 hb_internal_glyph_position_t &o = c->buffer->positions[c->buffer->in_pos];
408 o.x_offset = base_x - mark_x;
409 o.y_offset = base_y - mark_y;
410 o.back = c->buffer->in_pos - glyph_pos;
416 inline bool sanitize (hb_sanitize_context_t *c) {
418 return ArrayOf<MarkRecord>::sanitize (c, this);
425 struct SinglePosFormat1
427 friend struct SinglePos;
430 inline bool apply (hb_apply_context_t *c) const
433 unsigned int index = (this+coverage) (c->buffer->info[c->buffer->in_pos].codepoint);
434 if (likely (index == NOT_COVERED))
437 valueFormat.apply_value (c->layout, this, values, c->buffer->positions[c->buffer->in_pos]);
443 inline bool sanitize (hb_sanitize_context_t *c) {
445 return c->check_struct (this)
446 && coverage.sanitize (c, this)
447 && valueFormat.sanitize_value (c, this, values);
451 USHORT format; /* Format identifier--format = 1 */
453 coverage; /* Offset to Coverage table--from
454 * beginning of subtable */
455 ValueFormat valueFormat; /* Defines the types of data in the
457 ValueRecord values; /* Defines positioning
458 * value(s)--applied to all glyphs in
459 * the Coverage table */
461 DEFINE_SIZE_ARRAY (6, values);
464 struct SinglePosFormat2
466 friend struct SinglePos;
469 inline bool apply (hb_apply_context_t *c) const
472 unsigned int index = (this+coverage) (c->buffer->info[c->buffer->in_pos].codepoint);
473 if (likely (index == NOT_COVERED))
476 if (likely (index >= valueCount))
479 valueFormat.apply_value (c->layout, this,
480 &values[index * valueFormat.get_len ()],
481 c->buffer->positions[c->buffer->in_pos]);
487 inline bool sanitize (hb_sanitize_context_t *c) {
489 return c->check_struct (this)
490 && coverage.sanitize (c, this)
491 && valueFormat.sanitize_values (c, this, values, valueCount);
495 USHORT format; /* Format identifier--format = 2 */
497 coverage; /* Offset to Coverage table--from
498 * beginning of subtable */
499 ValueFormat valueFormat; /* Defines the types of data in the
501 USHORT valueCount; /* Number of ValueRecords */
502 ValueRecord values; /* Array of ValueRecords--positioning
503 * values applied to glyphs */
505 DEFINE_SIZE_ARRAY (8, values);
510 friend struct PosLookupSubTable;
513 inline bool apply (hb_apply_context_t *c) const
517 case 1: return u.format1.apply (c);
518 case 2: return u.format2.apply (c);
519 default:return false;
523 inline bool sanitize (hb_sanitize_context_t *c) {
525 if (!u.format.sanitize (c)) return false;
527 case 1: return u.format1.sanitize (c);
528 case 2: return u.format2.sanitize (c);
535 USHORT format; /* Format identifier */
536 SinglePosFormat1 format1;
537 SinglePosFormat2 format2;
542 struct PairValueRecord
544 friend struct PairSet;
547 GlyphID secondGlyph; /* GlyphID of second glyph in the
548 * pair--first glyph is listed in the
550 ValueRecord values; /* Positioning data for the first glyph
551 * followed by for second glyph */
553 DEFINE_SIZE_ARRAY (2, values);
558 friend struct PairPosFormat1;
560 inline bool apply (hb_apply_context_t *c,
561 const ValueFormat *valueFormats,
562 unsigned int pos) const
565 unsigned int len1 = valueFormats[0].get_len ();
566 unsigned int len2 = valueFormats[1].get_len ();
567 unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
569 unsigned int count = len;
570 const PairValueRecord *record = CastP<PairValueRecord> (array);
571 for (unsigned int i = 0; i < count; i++)
573 if (c->buffer->info[pos].codepoint == record->secondGlyph)
575 valueFormats[0].apply_value (c->layout, this, &record->values[0], c->buffer->positions[c->buffer->in_pos]);
576 valueFormats[1].apply_value (c->layout, this, &record->values[len1], c->buffer->positions[pos]);
579 c->buffer->in_pos = pos;
582 record = &StructAtOffset<PairValueRecord> (record, record_size);
588 struct sanitize_closure_t {
590 ValueFormat *valueFormats;
591 unsigned int len1; /* valueFormats[0].get_len() */
592 unsigned int stride; /* 1 + len1 + len2 */
595 inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) {
597 if (!(c->check_struct (this)
598 && c->check_array (array, USHORT::static_size * closure->stride, len))) return false;
600 unsigned int count = len;
601 PairValueRecord *record = CastP<PairValueRecord> (array);
602 return closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride)
603 && closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride);
607 USHORT len; /* Number of PairValueRecords */
608 USHORT array[VAR]; /* Array of PairValueRecords--ordered
609 * by GlyphID of the second glyph */
611 DEFINE_SIZE_ARRAY (2, array);
614 struct PairPosFormat1
616 friend struct PairPos;
619 inline bool apply (hb_apply_context_t *c) const
622 unsigned int end = MIN (c->buffer->in_length, c->buffer->in_pos + c->context_length);
623 if (unlikely (c->buffer->in_pos + 2 > end))
626 unsigned int index = (this+coverage) (c->buffer->info[c->buffer->in_pos].codepoint);
627 if (likely (index == NOT_COVERED))
630 unsigned int j = c->buffer->in_pos + 1;
631 while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_flag, NULL))
633 if (unlikely (j == end))
638 return (this+pairSet[index]).apply (c, &valueFormat1, j);
641 inline bool sanitize (hb_sanitize_context_t *c) {
644 unsigned int len1 = valueFormat1.get_len ();
645 unsigned int len2 = valueFormat2.get_len ();
646 PairSet::sanitize_closure_t closure = {
653 return c->check_struct (this)
654 && coverage.sanitize (c, this)
655 && pairSet.sanitize (c, this, &closure);
659 USHORT format; /* Format identifier--format = 1 */
661 coverage; /* Offset to Coverage table--from
662 * beginning of subtable */
663 ValueFormat valueFormat1; /* Defines the types of data in
664 * ValueRecord1--for the first glyph
665 * in the pair--may be zero (0) */
666 ValueFormat valueFormat2; /* Defines the types of data in
667 * ValueRecord2--for the second glyph
668 * in the pair--may be zero (0) */
669 OffsetArrayOf<PairSet>
670 pairSet; /* Array of PairSet tables
671 * ordered by Coverage Index */
673 DEFINE_SIZE_ARRAY (10, pairSet);
676 struct PairPosFormat2
678 friend struct PairPos;
681 inline bool apply (hb_apply_context_t *c) const
684 unsigned int end = MIN (c->buffer->in_length, c->buffer->in_pos + c->context_length);
685 if (unlikely (c->buffer->in_pos + 2 > end))
688 unsigned int index = (this+coverage) (c->buffer->info[c->buffer->in_pos].codepoint);
689 if (likely (index == NOT_COVERED))
692 unsigned int j = c->buffer->in_pos + 1;
693 while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_flag, NULL))
695 if (unlikely (j == end))
700 unsigned int len1 = valueFormat1.get_len ();
701 unsigned int len2 = valueFormat2.get_len ();
702 unsigned int record_len = len1 + len2;
704 unsigned int klass1 = (this+classDef1) (c->buffer->info[c->buffer->in_pos].codepoint);
705 unsigned int klass2 = (this+classDef2) (c->buffer->info[j].codepoint);
706 if (unlikely (klass1 >= class1Count || klass2 >= class2Count))
709 const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
710 valueFormat1.apply_value (c->layout, this, v, c->buffer->positions[c->buffer->in_pos]);
711 valueFormat2.apply_value (c->layout, this, v + len1, c->buffer->positions[j]);
715 c->buffer->in_pos = j;
720 inline bool sanitize (hb_sanitize_context_t *c) {
722 if (!(c->check_struct (this)
723 && coverage.sanitize (c, this)
724 && classDef1.sanitize (c, this)
725 && classDef2.sanitize (c, this))) return false;
727 unsigned int len1 = valueFormat1.get_len ();
728 unsigned int len2 = valueFormat2.get_len ();
729 unsigned int stride = len1 + len2;
730 unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
731 unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
732 return c->check_array (values, record_size, count) &&
733 valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
734 valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride);
738 USHORT format; /* Format identifier--format = 2 */
740 coverage; /* Offset to Coverage table--from
741 * beginning of subtable */
742 ValueFormat valueFormat1; /* ValueRecord definition--for the
743 * first glyph of the pair--may be zero
745 ValueFormat valueFormat2; /* ValueRecord definition--for the
746 * second glyph of the pair--may be
749 classDef1; /* Offset to ClassDef table--from
750 * beginning of PairPos subtable--for
751 * the first glyph of the pair */
753 classDef2; /* Offset to ClassDef table--from
754 * beginning of PairPos subtable--for
755 * the second glyph of the pair */
756 USHORT class1Count; /* Number of classes in ClassDef1
757 * table--includes Class0 */
758 USHORT class2Count; /* Number of classes in ClassDef2
759 * table--includes Class0 */
760 ValueRecord values; /* Matrix of value pairs:
761 * class1-major, class2-minor,
762 * Each entry has value1 and value2 */
764 DEFINE_SIZE_ARRAY (16, values);
769 friend struct PosLookupSubTable;
772 inline bool apply (hb_apply_context_t *c) const
776 case 1: return u.format1.apply (c);
777 case 2: return u.format2.apply (c);
778 default:return false;
782 inline bool sanitize (hb_sanitize_context_t *c) {
784 if (!u.format.sanitize (c)) return false;
786 case 1: return u.format1.sanitize (c);
787 case 2: return u.format2.sanitize (c);
794 USHORT format; /* Format identifier */
795 PairPosFormat1 format1;
796 PairPosFormat2 format2;
801 struct EntryExitRecord
803 friend struct CursivePosFormat1;
805 inline bool sanitize (hb_sanitize_context_t *c, void *base) {
807 return entryAnchor.sanitize (c, base)
808 && exitAnchor.sanitize (c, base);
813 entryAnchor; /* Offset to EntryAnchor table--from
814 * beginning of CursivePos
815 * subtable--may be NULL */
817 exitAnchor; /* Offset to ExitAnchor table--from
818 * beginning of CursivePos
819 * subtable--may be NULL */
821 DEFINE_SIZE_STATIC (4);
824 struct CursivePosFormat1
826 friend struct CursivePos;
829 inline bool apply (hb_apply_context_t *c) const
832 /* Now comes the messiest part of the whole OpenType
833 specification. At first glance, cursive connections seem easy
834 to understand, but there are pitfalls! The reason is that
835 the specs don't mention how to compute the advance values
836 resp. glyph offsets. I was told it would be an omission, to
837 be fixed in the next OpenType version... Again many thanks to
838 Andrei Burago <andreib@microsoft.com> for clarifications.
840 Consider the following example:
853 glyph1: advance width = 12
856 glyph2: advance width = 11
859 LSB is 1 for both glyphs (so the boxes drawn above are glyph
860 bboxes). Writing direction is R2L; `0' denotes the glyph's
863 Now the surprising part: The advance width of the *left* glyph
864 (resp. of the *bottom* glyph) will be modified, no matter
865 whether the writing direction is L2R or R2L (resp. T2B or
866 B2T)! This assymetry is caused by the fact that the glyph's
867 coordinate origin is always the lower left corner for all
870 Continuing the above example, we can compute the new
871 (horizontal) advance width of glyph2 as
875 and the new vertical offset of glyph2 as
880 Vertical writing direction is far more complicated:
882 a) Assuming that we recompute the advance height of the lower glyph:
889 yadv2 | 0+--+------+ -- BSB1 --
892 BSB2 -- 0+--------+ --
895 glyph1: advance height = 6
898 glyph2: advance height = 7
901 TSB is 1 for both glyphs; writing direction is T2B.
904 BSB1 = yadv1 - (TSB1 + ymax1)
905 BSB2 = yadv2 - (TSB2 + ymax2)
908 vertical advance width of glyph2
909 = y_offset + BSB2 - BSB1
910 = (y2 - y1) + (yadv2 - (TSB2 + ymax2)) - (yadv1 - (TSB1 + ymax1))
911 = y2 - y1 + yadv2 - TSB2 - ymax2 - (yadv1 - TSB1 - ymax1)
912 = y2 - y1 + yadv2 - TSB2 - ymax2 - yadv1 + TSB1 + ymax1
915 b) Assuming that we recompute the advance height of the upper glyph:
920 TSB2 -- +-----+--+ 1 | yadv1 ymax1
922 yadv2 | 0+--+------+ -- --
923 ymax2 | 2 | -- y_offset
928 glyph1: advance height = 6
931 glyph2: advance height = 7
934 TSB is 1 for both glyphs; writing direction is T2B.
938 vertical advance width of glyph2
939 = TSB1 + ymax1 + y_offset - (TSB2 + ymax2)
940 = TSB1 + ymax1 + y2 - y1 - TSB2 - ymax2
943 Comparing a) with b) shows that b) is easier to compute. I'll wait
944 for a reply from Andrei to see what should really be implemented...
946 Since horizontal advance widths or vertical advance heights
947 can be used alone but not together, no ambiguity occurs. */
949 struct hb_ot_layout_context_t::info_t::gpos_t *gpi = &c->layout->info.gpos;
950 hb_codepoint_t last_pos = gpi->last;
951 gpi->last = HB_OT_LAYOUT_GPOS_NO_LAST;
953 /* We don't handle mark glyphs here. */
954 if (c->property == HB_OT_LAYOUT_GLYPH_CLASS_MARK)
957 unsigned int index = (this+coverage) (c->buffer->info[c->buffer->in_pos].codepoint);
958 if (likely (index == NOT_COVERED))
961 const EntryExitRecord &record = entryExitRecord[index];
963 if (last_pos == HB_OT_LAYOUT_GPOS_NO_LAST || !record.entryAnchor)
966 hb_position_t entry_x, entry_y;
967 (this+record.entryAnchor).get_anchor (c->layout, c->buffer->info[c->buffer->in_pos].codepoint, &entry_x, &entry_y);
971 if (c->buffer->direction == HB_DIRECTION_RTL)
973 /* advance is absolute, not relative */
974 c->buffer->positions[c->buffer->in_pos].x_advance = entry_x - gpi->anchor_x;
978 /* advance is absolute, not relative */
979 c->buffer->positions[last_pos].x_advance = gpi->anchor_x - entry_x;
982 if (c->lookup_flag & LookupFlag::RightToLeft)
984 c->buffer->positions[last_pos].cursive_chain = last_pos - c->buffer->in_pos;
985 c->buffer->positions[last_pos].y_offset = entry_y - gpi->anchor_y;
989 c->buffer->positions[c->buffer->in_pos].cursive_chain = c->buffer->in_pos - last_pos;
990 c->buffer->positions[c->buffer->in_pos].y_offset = gpi->anchor_y - entry_y;
994 if (record.exitAnchor)
996 gpi->last = c->buffer->in_pos;
997 (this+record.exitAnchor).get_anchor (c->layout, c->buffer->info[c->buffer->in_pos].codepoint, &gpi->anchor_x, &gpi->anchor_y);
1000 c->buffer->in_pos++;
1004 inline bool sanitize (hb_sanitize_context_t *c) {
1006 return coverage.sanitize (c, this)
1007 && entryExitRecord.sanitize (c, this);
1011 USHORT format; /* Format identifier--format = 1 */
1013 coverage; /* Offset to Coverage table--from
1014 * beginning of subtable */
1015 ArrayOf<EntryExitRecord>
1016 entryExitRecord; /* Array of EntryExit records--in
1017 * Coverage Index order */
1019 DEFINE_SIZE_ARRAY (6, entryExitRecord);
1024 friend struct PosLookupSubTable;
1027 inline bool apply (hb_apply_context_t *c) const
1031 case 1: return u.format1.apply (c);
1032 default:return false;
1036 inline bool sanitize (hb_sanitize_context_t *c) {
1038 if (!u.format.sanitize (c)) return false;
1040 case 1: return u.format1.sanitize (c);
1041 default:return true;
1047 USHORT format; /* Format identifier */
1048 CursivePosFormat1 format1;
1053 typedef AnchorMatrix BaseArray; /* base-major--
1054 * in order of BaseCoverage Index--,
1056 * ordered by class--zero-based. */
1058 struct MarkBasePosFormat1
1060 friend struct MarkBasePos;
1063 inline bool apply (hb_apply_context_t *c) const
1066 unsigned int mark_index = (this+markCoverage) (c->buffer->info[c->buffer->in_pos].codepoint);
1067 if (likely (mark_index == NOT_COVERED))
1070 /* now we search backwards for a non-mark glyph */
1071 unsigned int property;
1072 unsigned int j = c->buffer->in_pos;
1078 } while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], LookupFlag::IgnoreMarks, &property));
1080 /* The following assertion is too strong, so we've disabled it. */
1081 if (false && !(property & HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH))
1084 unsigned int base_index = (this+baseCoverage) (c->buffer->info[j].codepoint);
1085 if (base_index == NOT_COVERED)
1088 return (this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, j);
1091 inline bool sanitize (hb_sanitize_context_t *c) {
1093 return c->check_struct (this)
1094 && markCoverage.sanitize (c, this)
1095 && baseCoverage.sanitize (c, this)
1096 && markArray.sanitize (c, this)
1097 && baseArray.sanitize (c, this, (unsigned int) classCount);
1101 USHORT format; /* Format identifier--format = 1 */
1103 markCoverage; /* Offset to MarkCoverage table--from
1104 * beginning of MarkBasePos subtable */
1106 baseCoverage; /* Offset to BaseCoverage table--from
1107 * beginning of MarkBasePos subtable */
1108 USHORT classCount; /* Number of classes defined for marks */
1110 markArray; /* Offset to MarkArray table--from
1111 * beginning of MarkBasePos subtable */
1113 baseArray; /* Offset to BaseArray table--from
1114 * beginning of MarkBasePos subtable */
1116 DEFINE_SIZE_STATIC (12);
1121 friend struct PosLookupSubTable;
1124 inline bool apply (hb_apply_context_t *c) const
1128 case 1: return u.format1.apply (c);
1129 default:return false;
1133 inline bool sanitize (hb_sanitize_context_t *c) {
1135 if (!u.format.sanitize (c)) return false;
1137 case 1: return u.format1.sanitize (c);
1138 default:return true;
1144 USHORT format; /* Format identifier */
1145 MarkBasePosFormat1 format1;
1150 typedef AnchorMatrix LigatureAttach; /* component-major--
1151 * in order of writing direction--,
1153 * ordered by class--zero-based. */
1155 typedef OffsetListOf<LigatureAttach> LigatureArray;
1156 /* Array of LigatureAttach
1158 * LigatureCoverage Index */
1160 struct MarkLigPosFormat1
1162 friend struct MarkLigPos;
1165 inline bool apply (hb_apply_context_t *c) const
1168 unsigned int mark_index = (this+markCoverage) (c->buffer->info[c->buffer->in_pos].codepoint);
1169 if (likely (mark_index == NOT_COVERED))
1172 /* now we search backwards for a non-mark glyph */
1173 unsigned int property;
1174 unsigned int j = c->buffer->in_pos;
1180 } while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], LookupFlag::IgnoreMarks, &property));
1182 /* The following assertion is too strong, so we've disabled it. */
1183 if (false && !(property & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE))
1186 unsigned int lig_index = (this+ligatureCoverage) (c->buffer->info[j].codepoint);
1187 if (lig_index == NOT_COVERED)
1190 const LigatureArray& lig_array = this+ligatureArray;
1191 const LigatureAttach& lig_attach = lig_array[lig_index];
1193 /* Find component to attach to */
1194 unsigned int comp_count = lig_attach.rows;
1195 if (unlikely (!comp_count))
1197 unsigned int comp_index;
1198 /* We must now check whether the ligature ID of the current mark glyph
1199 * is identical to the ligature ID of the found ligature. If yes, we
1200 * can directly use the component index. If not, we attach the mark
1201 * glyph to the last component of the ligature. */
1202 if (c->buffer->info[j].lig_id && c->buffer->info[j].lig_id == c->buffer->info[c->buffer->in_pos].lig_id && c->buffer->info[c->buffer->in_pos].component)
1204 comp_index = c->buffer->info[c->buffer->in_pos].component - 1;
1205 if (comp_index >= comp_count)
1206 comp_index = comp_count - 1;
1209 comp_index = comp_count - 1;
1211 return (this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j);
1214 inline bool sanitize (hb_sanitize_context_t *c) {
1216 return c->check_struct (this)
1217 && markCoverage.sanitize (c, this)
1218 && ligatureCoverage.sanitize (c, this)
1219 && markArray.sanitize (c, this)
1220 && ligatureArray.sanitize (c, this, (unsigned int) classCount);
1224 USHORT format; /* Format identifier--format = 1 */
1226 markCoverage; /* Offset to Mark Coverage table--from
1227 * beginning of MarkLigPos subtable */
1229 ligatureCoverage; /* Offset to Ligature Coverage
1230 * table--from beginning of MarkLigPos
1232 USHORT classCount; /* Number of defined mark classes */
1234 markArray; /* Offset to MarkArray table--from
1235 * beginning of MarkLigPos subtable */
1236 OffsetTo<LigatureArray>
1237 ligatureArray; /* Offset to LigatureArray table--from
1238 * beginning of MarkLigPos subtable */
1240 DEFINE_SIZE_STATIC (12);
1245 friend struct PosLookupSubTable;
1248 inline bool apply (hb_apply_context_t *c) const
1252 case 1: return u.format1.apply (c);
1253 default:return false;
1257 inline bool sanitize (hb_sanitize_context_t *c) {
1259 if (!u.format.sanitize (c)) return false;
1261 case 1: return u.format1.sanitize (c);
1262 default:return true;
1268 USHORT format; /* Format identifier */
1269 MarkLigPosFormat1 format1;
1274 typedef AnchorMatrix Mark2Array; /* mark2-major--
1275 * in order of Mark2Coverage Index--,
1277 * ordered by class--zero-based. */
1279 struct MarkMarkPosFormat1
1281 friend struct MarkMarkPos;
1284 inline bool apply (hb_apply_context_t *c) const
1287 unsigned int mark1_index = (this+mark1Coverage) (c->buffer->info[c->buffer->in_pos].codepoint);
1288 if (likely (mark1_index == NOT_COVERED))
1291 /* now we search backwards for a suitable mark glyph until a non-mark glyph */
1292 unsigned int property;
1293 unsigned int j = c->buffer->in_pos;
1299 } while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_flag, &property));
1301 if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK))
1304 /* Two marks match only if they belong to the same base, or same component
1305 * of the same ligature. That is, the component numbers must match, and
1306 * if those are non-zero, the ligid number should also match. */
1307 if ((c->buffer->info[j].component != c->buffer->info[c->buffer->in_pos].component) ||
1308 (c->buffer->info[j].component && c->buffer->info[j].lig_id != c->buffer->info[c->buffer->in_pos].lig_id))
1311 unsigned int mark2_index = (this+mark2Coverage) (c->buffer->info[j].codepoint);
1312 if (mark2_index == NOT_COVERED)
1315 return (this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j);
1318 inline bool sanitize (hb_sanitize_context_t *c) {
1320 return c->check_struct (this)
1321 && mark1Coverage.sanitize (c, this)
1322 && mark2Coverage.sanitize (c, this)
1323 && mark1Array.sanitize (c, this)
1324 && mark2Array.sanitize (c, this, (unsigned int) classCount);
1328 USHORT format; /* Format identifier--format = 1 */
1330 mark1Coverage; /* Offset to Combining Mark1 Coverage
1331 * table--from beginning of MarkMarkPos
1334 mark2Coverage; /* Offset to Combining Mark2 Coverage
1335 * table--from beginning of MarkMarkPos
1337 USHORT classCount; /* Number of defined mark classes */
1339 mark1Array; /* Offset to Mark1Array table--from
1340 * beginning of MarkMarkPos subtable */
1341 OffsetTo<Mark2Array>
1342 mark2Array; /* Offset to Mark2Array table--from
1343 * beginning of MarkMarkPos subtable */
1345 DEFINE_SIZE_STATIC (12);
1350 friend struct PosLookupSubTable;
1353 inline bool apply (hb_apply_context_t *c) const
1357 case 1: return u.format1.apply (c);
1358 default:return false;
1362 inline bool sanitize (hb_sanitize_context_t *c) {
1364 if (!u.format.sanitize (c)) return false;
1366 case 1: return u.format1.sanitize (c);
1367 default:return true;
1373 USHORT format; /* Format identifier */
1374 MarkMarkPosFormat1 format1;
1379 static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index);
1381 struct ContextPos : Context
1383 friend struct PosLookupSubTable;
1386 inline bool apply (hb_apply_context_t *c) const
1389 return Context::apply (c, position_lookup);
1393 struct ChainContextPos : ChainContext
1395 friend struct PosLookupSubTable;
1398 inline bool apply (hb_apply_context_t *c) const
1401 return ChainContext::apply (c, position_lookup);
1406 struct ExtensionPos : Extension
1408 friend struct PosLookupSubTable;
1411 inline const struct PosLookupSubTable& get_subtable (void) const
1413 unsigned int offset = get_offset ();
1414 if (unlikely (!offset)) return Null(PosLookupSubTable);
1415 return StructAtOffset<PosLookupSubTable> (this, offset);
1418 inline bool apply (hb_apply_context_t *c) const;
1420 inline bool sanitize (hb_sanitize_context_t *c);
1430 struct PosLookupSubTable
1432 friend struct PosLookup;
1446 inline bool apply (hb_apply_context_t *c, unsigned int lookup_type) const
1449 switch (lookup_type) {
1450 case Single: return u.single.apply (c);
1451 case Pair: return u.pair.apply (c);
1452 case Cursive: return u.cursive.apply (c);
1453 case MarkBase: return u.markBase.apply (c);
1454 case MarkLig: return u.markLig.apply (c);
1455 case MarkMark: return u.markMark.apply (c);
1456 case Context: return u.c.apply (c);
1457 case ChainContext: return u.chainContext.apply (c);
1458 case Extension: return u.extension.apply (c);
1459 default:return false;
1463 inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
1465 switch (lookup_type) {
1466 case Single: return u.single.sanitize (c);
1467 case Pair: return u.pair.sanitize (c);
1468 case Cursive: return u.cursive.sanitize (c);
1469 case MarkBase: return u.markBase.sanitize (c);
1470 case MarkLig: return u.markLig.sanitize (c);
1471 case MarkMark: return u.markMark.sanitize (c);
1472 case Context: return u.c.sanitize (c);
1473 case ChainContext: return u.chainContext.sanitize (c);
1474 case Extension: return u.extension.sanitize (c);
1475 default:return true;
1485 MarkBasePos markBase;
1487 MarkMarkPos markMark;
1489 ChainContextPos chainContext;
1490 ExtensionPos extension;
1493 DEFINE_SIZE_UNION (2, sub_format);
1497 struct PosLookup : Lookup
1499 inline const PosLookupSubTable& get_subtable (unsigned int i) const
1500 { return this+CastR<OffsetArrayOf<PosLookupSubTable> > (subTable)[i]; }
1502 inline bool apply_once (hb_ot_layout_context_t *layout,
1503 hb_buffer_t *buffer,
1504 unsigned int context_length,
1505 unsigned int nesting_level_left) const
1507 unsigned int lookup_type = get_type ();
1508 hb_apply_context_t c[1] = {{0}};
1512 c->context_length = context_length;
1513 c->nesting_level_left = nesting_level_left;
1514 c->lookup_flag = get_flag ();
1516 if (!_hb_ot_layout_check_glyph_property (c->layout->face, &c->buffer->info[c->buffer->in_pos], c->lookup_flag, &c->property))
1519 for (unsigned int i = 0; i < get_subtable_count (); i++)
1520 if (get_subtable (i).apply (c, lookup_type))
1526 inline bool apply_string (hb_ot_layout_context_t *layout,
1527 hb_buffer_t *buffer,
1528 hb_mask_t mask) const
1532 if (unlikely (!buffer->in_length))
1535 layout->info.gpos.last = HB_OT_LAYOUT_GPOS_NO_LAST; /* no last valid glyph for cursive pos. */
1538 while (buffer->in_pos < buffer->in_length)
1541 if (~buffer->info[buffer->in_pos].mask & mask)
1543 done = apply_once (layout, buffer, NO_CONTEXT, MAX_NESTING_LEVEL);
1549 /* Contrary to properties defined in GDEF, user-defined properties
1550 will always stop a possible cursive positioning. */
1551 layout->info.gpos.last = HB_OT_LAYOUT_GPOS_NO_LAST;
1561 inline bool sanitize (hb_sanitize_context_t *c) {
1563 if (unlikely (!Lookup::sanitize (c))) return false;
1564 OffsetArrayOf<PosLookupSubTable> &list = CastR<OffsetArrayOf<PosLookupSubTable> > (subTable);
1565 return list.sanitize (c, this, get_type ());
1569 typedef OffsetListOf<PosLookup> PosLookupList;
1575 struct GPOS : GSUBGPOS
1577 static const hb_tag_t Tag = HB_OT_TAG_GPOS;
1579 inline const PosLookup& get_lookup (unsigned int i) const
1580 { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
1582 inline bool position_lookup (hb_ot_layout_context_t *layout,
1583 hb_buffer_t *buffer,
1584 unsigned int lookup_index,
1585 hb_mask_t mask) const
1586 { return get_lookup (lookup_index).apply_string (layout, buffer, mask); }
1588 inline bool sanitize (hb_sanitize_context_t *c) {
1590 if (unlikely (!GSUBGPOS::sanitize (c))) return false;
1591 OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
1592 return list.sanitize (c, this);
1595 DEFINE_SIZE_STATIC (10);
1599 /* Out-of-class implementation for methods recursing */
1601 inline bool ExtensionPos::apply (hb_apply_context_t *c) const
1604 return get_subtable ().apply (c, get_type ());
1607 inline bool ExtensionPos::sanitize (hb_sanitize_context_t *c)
1610 if (unlikely (!Extension::sanitize (c))) return false;
1611 unsigned int offset = get_offset ();
1612 if (unlikely (!offset)) return true;
1613 return StructAtOffset<PosLookupSubTable> (this, offset).sanitize (c, get_type ());
1616 static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index)
1618 const GPOS &gpos = *(c->layout->face->ot_layout.gpos);
1619 const PosLookup &l = gpos.get_lookup (lookup_index);
1621 if (unlikely (c->nesting_level_left == 0))
1624 if (unlikely (c->context_length < 1))
1627 return l.apply_once (c->layout, c->buffer, c->context_length, c->nesting_level_left - 1);
1631 #endif /* HB_OT_LAYOUT_GPOS_PRIVATE_HH */