2 * Copyright © 2007,2008,2009,2010 Red Hat, Inc.
3 * Copyright © 2010,2012,2013 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_TABLE_HH
30 #define HB_OT_LAYOUT_GPOS_TABLE_HH
32 #include "hb-ot-layout-gsubgpos-private.hh"
38 /* buffer **position** var allocations */
39 #define attach_lookback() var.u16[0] /* number of glyphs to go back to attach this glyph to its base */
40 #define cursive_chain() var.i16[1] /* character to which this connects, may be positive or negative */
43 /* Shared Tables: ValueRecord, Anchor Table, and MarkArray */
47 typedef Value ValueRecord
[VAR
];
49 struct ValueFormat
: USHORT
52 xPlacement
= 0x0001u
, /* Includes horizontal adjustment for placement */
53 yPlacement
= 0x0002u
, /* Includes vertical adjustment for placement */
54 xAdvance
= 0x0004u
, /* Includes horizontal adjustment for advance */
55 yAdvance
= 0x0008u
, /* Includes vertical adjustment for advance */
56 xPlaDevice
= 0x0010u
, /* Includes horizontal Device table for placement */
57 yPlaDevice
= 0x0020u
, /* Includes vertical Device table for placement */
58 xAdvDevice
= 0x0040u
, /* Includes horizontal Device table for advance */
59 yAdvDevice
= 0x0080u
, /* Includes vertical Device table for advance */
60 ignored
= 0x0F00u
, /* Was used in TrueType Open for MM fonts */
61 reserved
= 0xF000u
, /* For future use */
63 devices
= 0x00F0u
/* 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
));
115 /* y_advance values grow downward but font-space grows upward, hence negation */
116 if (format
& yAdvance
) {
117 if (unlikely (!horizontal
)) glyph_pos
.y_advance
-= font
->em_scale_y (get_short (values
));
121 if (!has_device ()) return;
123 x_ppem
= font
->x_ppem
;
124 y_ppem
= font
->y_ppem
;
126 if (!x_ppem
&& !y_ppem
) return;
128 /* pixel -> fractional pixel */
129 if (format
& xPlaDevice
) {
130 if (x_ppem
) glyph_pos
.x_offset
+= (base
+ get_device (values
)).get_x_delta (font
);
133 if (format
& yPlaDevice
) {
134 if (y_ppem
) glyph_pos
.y_offset
+= (base
+ get_device (values
)).get_y_delta (font
);
137 if (format
& xAdvDevice
) {
138 if (horizontal
&& x_ppem
) glyph_pos
.x_advance
+= (base
+ get_device (values
)).get_x_delta (font
);
141 if (format
& yAdvDevice
) {
142 /* y_advance values grow downward but font-space grows upward, hence negation */
143 if (!horizontal
&& y_ppem
) glyph_pos
.y_advance
-= (base
+ get_device (values
)).get_y_delta (font
);
149 inline bool sanitize_value_devices (hb_sanitize_context_t
*c
, const void *base
, const Value
*values
) const
151 unsigned int format
= *this;
153 if (format
& xPlacement
) values
++;
154 if (format
& yPlacement
) values
++;
155 if (format
& xAdvance
) values
++;
156 if (format
& yAdvance
) values
++;
158 if ((format
& xPlaDevice
) && !get_device (values
++).sanitize (c
, base
)) return false;
159 if ((format
& yPlaDevice
) && !get_device (values
++).sanitize (c
, base
)) return false;
160 if ((format
& xAdvDevice
) && !get_device (values
++).sanitize (c
, base
)) return false;
161 if ((format
& yAdvDevice
) && !get_device (values
++).sanitize (c
, base
)) return false;
166 static inline OffsetTo
<Device
>& get_device (Value
* value
)
167 { return *CastP
<OffsetTo
<Device
> > (value
); }
168 static inline const OffsetTo
<Device
>& get_device (const Value
* value
)
169 { return *CastP
<OffsetTo
<Device
> > (value
); }
171 static inline const SHORT
& get_short (const Value
* value
)
172 { return *CastP
<SHORT
> (value
); }
176 inline bool has_device (void) const {
177 unsigned int format
= *this;
178 return (format
& devices
) != 0;
181 inline bool sanitize_value (hb_sanitize_context_t
*c
, const void *base
, const Value
*values
) const
183 TRACE_SANITIZE (this);
184 return TRACE_RETURN (c
->check_range (values
, get_size ()) && (!has_device () || sanitize_value_devices (c
, base
, values
)));
187 inline bool sanitize_values (hb_sanitize_context_t
*c
, const void *base
, const Value
*values
, unsigned int count
) const
189 TRACE_SANITIZE (this);
190 unsigned int len
= get_len ();
192 if (!c
->check_array (values
, get_size (), count
)) return TRACE_RETURN (false);
194 if (!has_device ()) return TRACE_RETURN (true);
196 for (unsigned int i
= 0; i
< count
; i
++) {
197 if (!sanitize_value_devices (c
, base
, values
))
198 return TRACE_RETURN (false);
202 return TRACE_RETURN (true);
205 /* Just sanitize referenced Device tables. Doesn't check the values themselves. */
206 inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t
*c
, const void *base
, const Value
*values
, unsigned int count
, unsigned int stride
) const
208 TRACE_SANITIZE (this);
210 if (!has_device ()) return TRACE_RETURN (true);
212 for (unsigned int i
= 0; i
< count
; i
++) {
213 if (!sanitize_value_devices (c
, base
, values
))
214 return TRACE_RETURN (false);
218 return TRACE_RETURN (true);
225 inline void get_anchor (hb_font_t
*font
, hb_codepoint_t glyph_id HB_UNUSED
,
226 hb_position_t
*x
, hb_position_t
*y
) const
228 *x
= font
->em_scale_x (xCoordinate
);
229 *y
= font
->em_scale_y (yCoordinate
);
232 inline bool sanitize (hb_sanitize_context_t
*c
) const
234 TRACE_SANITIZE (this);
235 return TRACE_RETURN (c
->check_struct (this));
239 USHORT format
; /* Format identifier--format = 1 */
240 SHORT xCoordinate
; /* Horizontal value--in design units */
241 SHORT yCoordinate
; /* Vertical value--in design units */
243 DEFINE_SIZE_STATIC (6);
248 inline void get_anchor (hb_font_t
*font
, hb_codepoint_t glyph_id
,
249 hb_position_t
*x
, hb_position_t
*y
) const
251 unsigned int x_ppem
= font
->x_ppem
;
252 unsigned int y_ppem
= font
->y_ppem
;
253 hb_position_t cx
, cy
;
256 ret
= (x_ppem
|| y_ppem
) &&
257 font
->get_glyph_contour_point_for_origin (glyph_id
, anchorPoint
, HB_DIRECTION_LTR
, &cx
, &cy
);
258 *x
= ret
&& x_ppem
? cx
: font
->em_scale_x (xCoordinate
);
259 *y
= ret
&& y_ppem
? cy
: font
->em_scale_y (yCoordinate
);
262 inline bool sanitize (hb_sanitize_context_t
*c
) const
264 TRACE_SANITIZE (this);
265 return TRACE_RETURN (c
->check_struct (this));
269 USHORT format
; /* Format identifier--format = 2 */
270 SHORT xCoordinate
; /* Horizontal value--in design units */
271 SHORT yCoordinate
; /* Vertical value--in design units */
272 USHORT anchorPoint
; /* Index to glyph contour point */
274 DEFINE_SIZE_STATIC (8);
279 inline void get_anchor (hb_font_t
*font
, hb_codepoint_t glyph_id HB_UNUSED
,
280 hb_position_t
*x
, hb_position_t
*y
) const
282 *x
= font
->em_scale_x (xCoordinate
);
283 *y
= font
->em_scale_y (yCoordinate
);
286 *x
+= (this+xDeviceTable
).get_x_delta (font
);
288 *y
+= (this+yDeviceTable
).get_x_delta (font
);
291 inline bool sanitize (hb_sanitize_context_t
*c
) const
293 TRACE_SANITIZE (this);
294 return TRACE_RETURN (c
->check_struct (this) && xDeviceTable
.sanitize (c
, this) && yDeviceTable
.sanitize (c
, this));
298 USHORT format
; /* Format identifier--format = 3 */
299 SHORT xCoordinate
; /* Horizontal value--in design units */
300 SHORT yCoordinate
; /* Vertical value--in design units */
302 xDeviceTable
; /* Offset to Device table for X
303 * coordinate-- from beginning of
304 * Anchor table (may be NULL) */
306 yDeviceTable
; /* Offset to Device table for Y
307 * coordinate-- from beginning of
308 * Anchor table (may be NULL) */
310 DEFINE_SIZE_STATIC (10);
315 inline void get_anchor (hb_font_t
*font
, hb_codepoint_t glyph_id
,
316 hb_position_t
*x
, hb_position_t
*y
) const
320 case 1: u
.format1
.get_anchor (font
, glyph_id
, x
, y
); return;
321 case 2: u
.format2
.get_anchor (font
, glyph_id
, x
, y
); return;
322 case 3: u
.format3
.get_anchor (font
, glyph_id
, x
, y
); return;
327 inline bool sanitize (hb_sanitize_context_t
*c
) const
329 TRACE_SANITIZE (this);
330 if (!u
.format
.sanitize (c
)) return TRACE_RETURN (false);
332 case 1: return TRACE_RETURN (u
.format1
.sanitize (c
));
333 case 2: return TRACE_RETURN (u
.format2
.sanitize (c
));
334 case 3: return TRACE_RETURN (u
.format3
.sanitize (c
));
335 default:return TRACE_RETURN (true);
341 USHORT format
; /* Format identifier */
342 AnchorFormat1 format1
;
343 AnchorFormat2 format2
;
344 AnchorFormat3 format3
;
347 DEFINE_SIZE_UNION (2, format
);
353 inline const Anchor
& get_anchor (unsigned int row
, unsigned int col
, unsigned int cols
, bool *found
) const {
355 if (unlikely (row
>= rows
|| col
>= cols
)) return Null(Anchor
);
356 *found
= !matrixZ
[row
* cols
+ col
].is_null ();
357 return this+matrixZ
[row
* cols
+ col
];
360 inline bool sanitize (hb_sanitize_context_t
*c
, unsigned int cols
) const
362 TRACE_SANITIZE (this);
363 if (!c
->check_struct (this)) return TRACE_RETURN (false);
364 if (unlikely (rows
> 0 && cols
>= ((unsigned int) -1) / rows
)) return TRACE_RETURN (false);
365 unsigned int count
= rows
* cols
;
366 if (!c
->check_array (matrixZ
, matrixZ
[0].static_size
, count
)) return TRACE_RETURN (false);
367 for (unsigned int i
= 0; i
< count
; i
++)
368 if (!matrixZ
[i
].sanitize (c
, this)) return TRACE_RETURN (false);
369 return TRACE_RETURN (true);
372 USHORT rows
; /* Number of rows */
375 matrixZ
[VAR
]; /* Matrix of offsets to Anchor tables--
376 * from beginning of AnchorMatrix table */
378 DEFINE_SIZE_ARRAY (2, matrixZ
);
384 friend struct MarkArray
;
386 inline bool sanitize (hb_sanitize_context_t
*c
, const void *base
) const
388 TRACE_SANITIZE (this);
389 return TRACE_RETURN (c
->check_struct (this) && markAnchor
.sanitize (c
, base
));
393 USHORT klass
; /* Class defined for this mark */
395 markAnchor
; /* Offset to Anchor table--from
396 * beginning of MarkArray table */
398 DEFINE_SIZE_STATIC (4);
401 struct MarkArray
: ArrayOf
<MarkRecord
> /* Array of MarkRecords--in Coverage order */
403 inline bool apply (hb_apply_context_t
*c
,
404 unsigned int mark_index
, unsigned int glyph_index
,
405 const AnchorMatrix
&anchors
, unsigned int class_count
,
406 unsigned int glyph_pos
) const
409 hb_buffer_t
*buffer
= c
->buffer
;
410 const MarkRecord
&record
= ArrayOf
<MarkRecord
>::operator[](mark_index
);
411 unsigned int mark_class
= record
.klass
;
413 const Anchor
& mark_anchor
= this + record
.markAnchor
;
415 const Anchor
& glyph_anchor
= anchors
.get_anchor (glyph_index
, mark_class
, class_count
, &found
);
416 /* If this subtable doesn't have an anchor for this base and this class,
417 * return false such that the subsequent subtables have a chance at it. */
418 if (unlikely (!found
)) return TRACE_RETURN (false);
420 hb_position_t mark_x
, mark_y
, base_x
, base_y
;
422 mark_anchor
.get_anchor (c
->font
, buffer
->cur().codepoint
, &mark_x
, &mark_y
);
423 glyph_anchor
.get_anchor (c
->font
, buffer
->info
[glyph_pos
].codepoint
, &base_x
, &base_y
);
425 hb_glyph_position_t
&o
= buffer
->cur_pos();
426 o
.x_offset
= base_x
- mark_x
;
427 o
.y_offset
= base_y
- mark_y
;
428 o
.attach_lookback() = buffer
->idx
- glyph_pos
;
431 return TRACE_RETURN (true);
434 inline bool sanitize (hb_sanitize_context_t
*c
) const
436 TRACE_SANITIZE (this);
437 return TRACE_RETURN (ArrayOf
<MarkRecord
>::sanitize (c
, this));
444 struct SinglePosFormat1
446 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
448 TRACE_COLLECT_GLYPHS (this);
449 (this+coverage
).add_coverage (c
->input
);
452 inline const Coverage
&get_coverage (void) const
454 return this+coverage
;
457 inline bool apply (hb_apply_context_t
*c
) const
460 hb_buffer_t
*buffer
= c
->buffer
;
461 unsigned int index
= (this+coverage
).get_coverage (buffer
->cur().codepoint
);
462 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
464 valueFormat
.apply_value (c
->font
, c
->direction
, this,
465 values
, buffer
->cur_pos());
468 return TRACE_RETURN (true);
471 inline bool sanitize (hb_sanitize_context_t
*c
) const
473 TRACE_SANITIZE (this);
474 return TRACE_RETURN (c
->check_struct (this)
475 && coverage
.sanitize (c
, this)
476 && valueFormat
.sanitize_value (c
, this, values
));
480 USHORT format
; /* Format identifier--format = 1 */
482 coverage
; /* Offset to Coverage table--from
483 * beginning of subtable */
484 ValueFormat valueFormat
; /* Defines the types of data in the
486 ValueRecord values
; /* Defines positioning
487 * value(s)--applied to all glyphs in
488 * the Coverage table */
490 DEFINE_SIZE_ARRAY (6, values
);
493 struct SinglePosFormat2
495 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
497 TRACE_COLLECT_GLYPHS (this);
498 (this+coverage
).add_coverage (c
->input
);
501 inline const Coverage
&get_coverage (void) const
503 return this+coverage
;
506 inline bool apply (hb_apply_context_t
*c
) const
509 hb_buffer_t
*buffer
= c
->buffer
;
510 unsigned int index
= (this+coverage
).get_coverage (buffer
->cur().codepoint
);
511 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
513 if (likely (index
>= valueCount
)) return TRACE_RETURN (false);
515 valueFormat
.apply_value (c
->font
, c
->direction
, this,
516 &values
[index
* valueFormat
.get_len ()],
520 return TRACE_RETURN (true);
523 inline bool sanitize (hb_sanitize_context_t
*c
) const
525 TRACE_SANITIZE (this);
526 return TRACE_RETURN (c
->check_struct (this)
527 && coverage
.sanitize (c
, this)
528 && valueFormat
.sanitize_values (c
, this, values
, valueCount
));
532 USHORT format
; /* Format identifier--format = 2 */
534 coverage
; /* Offset to Coverage table--from
535 * beginning of subtable */
536 ValueFormat valueFormat
; /* Defines the types of data in the
538 USHORT valueCount
; /* Number of ValueRecords */
539 ValueRecord values
; /* Array of ValueRecords--positioning
540 * values applied to glyphs */
542 DEFINE_SIZE_ARRAY (8, values
);
547 template <typename context_t
>
548 inline typename
context_t::return_t
dispatch (context_t
*c
) const
550 TRACE_DISPATCH (this, u
.format
);
551 if (unlikely (!c
->may_dispatch (this, &u
.format
))) TRACE_RETURN (c
->default_return_value ());
553 case 1: return TRACE_RETURN (c
->dispatch (u
.format1
));
554 case 2: return TRACE_RETURN (c
->dispatch (u
.format2
));
555 default:return TRACE_RETURN (c
->default_return_value ());
561 USHORT format
; /* Format identifier */
562 SinglePosFormat1 format1
;
563 SinglePosFormat2 format2
;
568 struct PairValueRecord
570 friend struct PairSet
;
573 GlyphID secondGlyph
; /* GlyphID of second glyph in the
574 * pair--first glyph is listed in the
576 ValueRecord values
; /* Positioning data for the first glyph
577 * followed by for second glyph */
579 DEFINE_SIZE_ARRAY (2, values
);
584 friend struct PairPosFormat1
;
586 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
,
587 const ValueFormat
*valueFormats
) const
589 TRACE_COLLECT_GLYPHS (this);
590 unsigned int len1
= valueFormats
[0].get_len ();
591 unsigned int len2
= valueFormats
[1].get_len ();
592 unsigned int record_size
= USHORT::static_size
* (1 + len1
+ len2
);
594 const PairValueRecord
*record
= CastP
<PairValueRecord
> (arrayZ
);
595 unsigned int count
= len
;
596 for (unsigned int i
= 0; i
< count
; i
++)
598 c
->input
->add (record
->secondGlyph
);
599 record
= &StructAtOffset
<PairValueRecord
> (record
, record_size
);
603 inline bool apply (hb_apply_context_t
*c
,
604 const ValueFormat
*valueFormats
,
605 unsigned int pos
) const
608 hb_buffer_t
*buffer
= c
->buffer
;
609 unsigned int len1
= valueFormats
[0].get_len ();
610 unsigned int len2
= valueFormats
[1].get_len ();
611 unsigned int record_size
= USHORT::static_size
* (1 + len1
+ len2
);
613 const PairValueRecord
*record_array
= CastP
<PairValueRecord
> (arrayZ
);
614 unsigned int count
= len
;
616 /* Hand-coded bsearch. */
617 if (unlikely (!count
))
618 return TRACE_RETURN (false);
619 hb_codepoint_t x
= buffer
->info
[pos
].codepoint
;
620 int min
= 0, max
= (int) count
- 1;
623 int mid
= (min
+ max
) / 2;
624 const PairValueRecord
*record
= &StructAtOffset
<PairValueRecord
> (record_array
, record_size
* mid
);
625 hb_codepoint_t mid_x
= record
->secondGlyph
;
632 valueFormats
[0].apply_value (c
->font
, c
->direction
, this,
633 &record
->values
[0], buffer
->cur_pos());
634 valueFormats
[1].apply_value (c
->font
, c
->direction
, this,
635 &record
->values
[len1
], buffer
->pos
[pos
]);
639 return TRACE_RETURN (true);
643 return TRACE_RETURN (false);
646 struct sanitize_closure_t
{
648 const ValueFormat
*valueFormats
;
649 unsigned int len1
; /* valueFormats[0].get_len() */
650 unsigned int stride
; /* 1 + len1 + len2 */
653 inline bool sanitize (hb_sanitize_context_t
*c
, const sanitize_closure_t
*closure
) const
655 TRACE_SANITIZE (this);
656 if (!(c
->check_struct (this)
657 && c
->check_array (arrayZ
, USHORT::static_size
* closure
->stride
, len
))) return TRACE_RETURN (false);
659 unsigned int count
= len
;
660 const PairValueRecord
*record
= CastP
<PairValueRecord
> (arrayZ
);
661 return TRACE_RETURN (closure
->valueFormats
[0].sanitize_values_stride_unsafe (c
, closure
->base
, &record
->values
[0], count
, closure
->stride
)
662 && closure
->valueFormats
[1].sanitize_values_stride_unsafe (c
, closure
->base
, &record
->values
[closure
->len1
], count
, closure
->stride
));
666 USHORT len
; /* Number of PairValueRecords */
667 USHORT arrayZ
[VAR
]; /* Array of PairValueRecords--ordered
668 * by GlyphID of the second glyph */
670 DEFINE_SIZE_ARRAY (2, arrayZ
);
673 struct PairPosFormat1
675 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
677 TRACE_COLLECT_GLYPHS (this);
678 (this+coverage
).add_coverage (c
->input
);
679 unsigned int count
= pairSet
.len
;
680 for (unsigned int i
= 0; i
< count
; i
++)
681 (this+pairSet
[i
]).collect_glyphs (c
, &valueFormat1
);
684 inline const Coverage
&get_coverage (void) const
686 return this+coverage
;
689 inline bool apply (hb_apply_context_t
*c
) const
692 hb_buffer_t
*buffer
= c
->buffer
;
693 unsigned int index
= (this+coverage
).get_coverage (buffer
->cur().codepoint
);
694 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
696 hb_apply_context_t::skipping_iterator_t
&skippy_iter
= c
->iter_input
;
697 skippy_iter
.reset (buffer
->idx
, 1);
698 if (!skippy_iter
.next ()) return TRACE_RETURN (false);
700 return TRACE_RETURN ((this+pairSet
[index
]).apply (c
, &valueFormat1
, skippy_iter
.idx
));
703 inline bool sanitize (hb_sanitize_context_t
*c
) const
705 TRACE_SANITIZE (this);
707 unsigned int len1
= valueFormat1
.get_len ();
708 unsigned int len2
= valueFormat2
.get_len ();
709 PairSet::sanitize_closure_t closure
= {
716 return TRACE_RETURN (c
->check_struct (this) && coverage
.sanitize (c
, this) && pairSet
.sanitize (c
, this, &closure
));
720 USHORT format
; /* Format identifier--format = 1 */
722 coverage
; /* Offset to Coverage table--from
723 * beginning of subtable */
724 ValueFormat valueFormat1
; /* Defines the types of data in
725 * ValueRecord1--for the first glyph
726 * in the pair--may be zero (0) */
727 ValueFormat valueFormat2
; /* Defines the types of data in
728 * ValueRecord2--for the second glyph
729 * in the pair--may be zero (0) */
730 OffsetArrayOf
<PairSet
>
731 pairSet
; /* Array of PairSet tables
732 * ordered by Coverage Index */
734 DEFINE_SIZE_ARRAY (10, pairSet
);
737 struct PairPosFormat2
739 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
741 TRACE_COLLECT_GLYPHS (this);
742 /* (this+coverage).add_coverage (c->input); // Don't need this. */
744 unsigned int count1
= class1Count
;
745 const ClassDef
&klass1
= this+classDef1
;
746 for (unsigned int i
= 0; i
< count1
; i
++)
747 klass1
.add_class (c
->input
, i
);
749 unsigned int count2
= class2Count
;
750 const ClassDef
&klass2
= this+classDef2
;
751 for (unsigned int i
= 0; i
< count2
; i
++)
752 klass2
.add_class (c
->input
, i
);
755 inline const Coverage
&get_coverage (void) const
757 return this+coverage
;
760 inline bool apply (hb_apply_context_t
*c
) const
763 hb_buffer_t
*buffer
= c
->buffer
;
764 unsigned int index
= (this+coverage
).get_coverage (buffer
->cur().codepoint
);
765 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
767 hb_apply_context_t::skipping_iterator_t
&skippy_iter
= c
->iter_input
;
768 skippy_iter
.reset (buffer
->idx
, 1);
769 if (!skippy_iter
.next ()) return TRACE_RETURN (false);
771 unsigned int len1
= valueFormat1
.get_len ();
772 unsigned int len2
= valueFormat2
.get_len ();
773 unsigned int record_len
= len1
+ len2
;
775 unsigned int klass1
= (this+classDef1
).get_class (buffer
->cur().codepoint
);
776 unsigned int klass2
= (this+classDef2
).get_class (buffer
->info
[skippy_iter
.idx
].codepoint
);
777 if (unlikely (klass1
>= class1Count
|| klass2
>= class2Count
)) return TRACE_RETURN (false);
779 const Value
*v
= &values
[record_len
* (klass1
* class2Count
+ klass2
)];
780 valueFormat1
.apply_value (c
->font
, c
->direction
, this,
781 v
, buffer
->cur_pos());
782 valueFormat2
.apply_value (c
->font
, c
->direction
, this,
783 v
+ len1
, buffer
->pos
[skippy_iter
.idx
]);
785 buffer
->idx
= skippy_iter
.idx
;
789 return TRACE_RETURN (true);
792 inline bool sanitize (hb_sanitize_context_t
*c
) const
794 TRACE_SANITIZE (this);
795 if (!(c
->check_struct (this)
796 && coverage
.sanitize (c
, this)
797 && classDef1
.sanitize (c
, this)
798 && classDef2
.sanitize (c
, this))) return TRACE_RETURN (false);
800 unsigned int len1
= valueFormat1
.get_len ();
801 unsigned int len2
= valueFormat2
.get_len ();
802 unsigned int stride
= len1
+ len2
;
803 unsigned int record_size
= valueFormat1
.get_size () + valueFormat2
.get_size ();
804 unsigned int count
= (unsigned int) class1Count
* (unsigned int) class2Count
;
805 return TRACE_RETURN (c
->check_array (values
, record_size
, count
) &&
806 valueFormat1
.sanitize_values_stride_unsafe (c
, this, &values
[0], count
, stride
) &&
807 valueFormat2
.sanitize_values_stride_unsafe (c
, this, &values
[len1
], count
, stride
));
811 USHORT format
; /* Format identifier--format = 2 */
813 coverage
; /* Offset to Coverage table--from
814 * beginning of subtable */
815 ValueFormat valueFormat1
; /* ValueRecord definition--for the
816 * first glyph of the pair--may be zero
818 ValueFormat valueFormat2
; /* ValueRecord definition--for the
819 * second glyph of the pair--may be
822 classDef1
; /* Offset to ClassDef table--from
823 * beginning of PairPos subtable--for
824 * the first glyph of the pair */
826 classDef2
; /* Offset to ClassDef table--from
827 * beginning of PairPos subtable--for
828 * the second glyph of the pair */
829 USHORT class1Count
; /* Number of classes in ClassDef1
830 * table--includes Class0 */
831 USHORT class2Count
; /* Number of classes in ClassDef2
832 * table--includes Class0 */
833 ValueRecord values
; /* Matrix of value pairs:
834 * class1-major, class2-minor,
835 * Each entry has value1 and value2 */
837 DEFINE_SIZE_ARRAY (16, values
);
842 template <typename context_t
>
843 inline typename
context_t::return_t
dispatch (context_t
*c
) const
845 TRACE_DISPATCH (this, u
.format
);
846 if (unlikely (!c
->may_dispatch (this, &u
.format
))) TRACE_RETURN (c
->default_return_value ());
848 case 1: return TRACE_RETURN (c
->dispatch (u
.format1
));
849 case 2: return TRACE_RETURN (c
->dispatch (u
.format2
));
850 default:return TRACE_RETURN (c
->default_return_value ());
856 USHORT format
; /* Format identifier */
857 PairPosFormat1 format1
;
858 PairPosFormat2 format2
;
863 struct EntryExitRecord
865 friend struct CursivePosFormat1
;
867 inline bool sanitize (hb_sanitize_context_t
*c
, const void *base
) const
869 TRACE_SANITIZE (this);
870 return TRACE_RETURN (entryAnchor
.sanitize (c
, base
) && exitAnchor
.sanitize (c
, base
));
875 entryAnchor
; /* Offset to EntryAnchor table--from
876 * beginning of CursivePos
877 * subtable--may be NULL */
879 exitAnchor
; /* Offset to ExitAnchor table--from
880 * beginning of CursivePos
881 * subtable--may be NULL */
883 DEFINE_SIZE_STATIC (4);
886 struct CursivePosFormat1
888 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
890 TRACE_COLLECT_GLYPHS (this);
891 (this+coverage
).add_coverage (c
->input
);
894 inline const Coverage
&get_coverage (void) const
896 return this+coverage
;
899 inline bool apply (hb_apply_context_t
*c
) const
902 hb_buffer_t
*buffer
= c
->buffer
;
904 /* We don't handle mark glyphs here. */
905 if (unlikely (_hb_glyph_info_is_mark (&buffer
->cur()))) return TRACE_RETURN (false);
907 const EntryExitRecord
&this_record
= entryExitRecord
[(this+coverage
).get_coverage (buffer
->cur().codepoint
)];
908 if (!this_record
.exitAnchor
) return TRACE_RETURN (false);
910 hb_apply_context_t::skipping_iterator_t
&skippy_iter
= c
->iter_input
;
911 skippy_iter
.reset (buffer
->idx
, 1);
912 if (!skippy_iter
.next ()) return TRACE_RETURN (false);
914 const EntryExitRecord
&next_record
= entryExitRecord
[(this+coverage
).get_coverage (buffer
->info
[skippy_iter
.idx
].codepoint
)];
915 if (!next_record
.entryAnchor
) return TRACE_RETURN (false);
917 unsigned int i
= buffer
->idx
;
918 unsigned int j
= skippy_iter
.idx
;
920 hb_position_t entry_x
, entry_y
, exit_x
, exit_y
;
921 (this+this_record
.exitAnchor
).get_anchor (c
->font
, buffer
->info
[i
].codepoint
, &exit_x
, &exit_y
);
922 (this+next_record
.entryAnchor
).get_anchor (c
->font
, buffer
->info
[j
].codepoint
, &entry_x
, &entry_y
);
924 hb_glyph_position_t
*pos
= buffer
->pos
;
927 /* Main-direction adjustment */
928 switch (c
->direction
) {
929 case HB_DIRECTION_LTR
:
930 pos
[i
].x_advance
= exit_x
+ pos
[i
].x_offset
;
932 d
= entry_x
+ pos
[j
].x_offset
;
933 pos
[j
].x_advance
-= d
;
934 pos
[j
].x_offset
-= d
;
936 case HB_DIRECTION_RTL
:
937 d
= exit_x
+ pos
[i
].x_offset
;
938 pos
[i
].x_advance
-= d
;
939 pos
[i
].x_offset
-= d
;
941 pos
[j
].x_advance
= entry_x
+ pos
[j
].x_offset
;
943 case HB_DIRECTION_TTB
:
944 pos
[i
].y_advance
= exit_y
+ pos
[i
].y_offset
;
946 d
= entry_y
+ pos
[j
].y_offset
;
947 pos
[j
].y_advance
-= d
;
948 pos
[j
].y_offset
-= d
;
950 case HB_DIRECTION_BTT
:
951 d
= exit_y
+ pos
[i
].y_offset
;
952 pos
[i
].y_advance
-= d
;
953 pos
[i
].y_offset
-= d
;
955 pos
[j
].y_advance
= entry_y
;
957 case HB_DIRECTION_INVALID
:
962 /* Cross-direction adjustment */
963 if (c
->lookup_props
& LookupFlag::RightToLeft
) {
964 pos
[i
].cursive_chain() = j
- i
;
965 if (likely (HB_DIRECTION_IS_HORIZONTAL (c
->direction
)))
966 pos
[i
].y_offset
= entry_y
- exit_y
;
968 pos
[i
].x_offset
= entry_x
- exit_x
;
970 pos
[j
].cursive_chain() = i
- j
;
971 if (likely (HB_DIRECTION_IS_HORIZONTAL (c
->direction
)))
972 pos
[j
].y_offset
= exit_y
- entry_y
;
974 pos
[j
].x_offset
= exit_x
- entry_x
;
978 return TRACE_RETURN (true);
981 inline bool sanitize (hb_sanitize_context_t
*c
) const
983 TRACE_SANITIZE (this);
984 return TRACE_RETURN (coverage
.sanitize (c
, this) && entryExitRecord
.sanitize (c
, this));
988 USHORT format
; /* Format identifier--format = 1 */
990 coverage
; /* Offset to Coverage table--from
991 * beginning of subtable */
992 ArrayOf
<EntryExitRecord
>
993 entryExitRecord
; /* Array of EntryExit records--in
994 * Coverage Index order */
996 DEFINE_SIZE_ARRAY (6, entryExitRecord
);
1001 template <typename context_t
>
1002 inline typename
context_t::return_t
dispatch (context_t
*c
) const
1004 TRACE_DISPATCH (this, u
.format
);
1005 if (unlikely (!c
->may_dispatch (this, &u
.format
))) TRACE_RETURN (c
->default_return_value ());
1007 case 1: return TRACE_RETURN (c
->dispatch (u
.format1
));
1008 default:return TRACE_RETURN (c
->default_return_value ());
1014 USHORT format
; /* Format identifier */
1015 CursivePosFormat1 format1
;
1020 typedef AnchorMatrix BaseArray
; /* base-major--
1021 * in order of BaseCoverage Index--,
1023 * ordered by class--zero-based. */
1025 struct MarkBasePosFormat1
1027 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
1029 TRACE_COLLECT_GLYPHS (this);
1030 (this+markCoverage
).add_coverage (c
->input
);
1031 (this+baseCoverage
).add_coverage (c
->input
);
1034 inline const Coverage
&get_coverage (void) const
1036 return this+markCoverage
;
1039 inline bool apply (hb_apply_context_t
*c
) const
1042 hb_buffer_t
*buffer
= c
->buffer
;
1043 unsigned int mark_index
= (this+markCoverage
).get_coverage (buffer
->cur().codepoint
);
1044 if (likely (mark_index
== NOT_COVERED
)) return TRACE_RETURN (false);
1046 /* now we search backwards for a non-mark glyph */
1047 hb_apply_context_t::skipping_iterator_t
&skippy_iter
= c
->iter_input
;
1048 skippy_iter
.reset (buffer
->idx
, 1);
1049 skippy_iter
.set_lookup_props (LookupFlag::IgnoreMarks
);
1051 if (!skippy_iter
.prev ()) return TRACE_RETURN (false);
1052 /* We only want to attach to the first of a MultipleSubst sequence. Reject others. */
1053 if (0 == _hb_glyph_info_get_lig_comp (&buffer
->info
[skippy_iter
.idx
])) break;
1054 skippy_iter
.reject ();
1057 /* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */
1058 if (!_hb_glyph_info_is_base_glyph (&buffer
->info
[skippy_iter
.idx
])) { /*return TRACE_RETURN (false);*/ }
1060 unsigned int base_index
= (this+baseCoverage
).get_coverage (buffer
->info
[skippy_iter
.idx
].codepoint
);
1061 if (base_index
== NOT_COVERED
) return TRACE_RETURN (false);
1063 return TRACE_RETURN ((this+markArray
).apply (c
, mark_index
, base_index
, this+baseArray
, classCount
, skippy_iter
.idx
));
1066 inline bool sanitize (hb_sanitize_context_t
*c
) const
1068 TRACE_SANITIZE (this);
1069 return TRACE_RETURN (c
->check_struct (this) && markCoverage
.sanitize (c
, this) && baseCoverage
.sanitize (c
, this) &&
1070 markArray
.sanitize (c
, this) && baseArray
.sanitize (c
, this, (unsigned int) classCount
));
1074 USHORT format
; /* Format identifier--format = 1 */
1076 markCoverage
; /* Offset to MarkCoverage table--from
1077 * beginning of MarkBasePos subtable */
1079 baseCoverage
; /* Offset to BaseCoverage table--from
1080 * beginning of MarkBasePos subtable */
1081 USHORT classCount
; /* Number of classes defined for marks */
1083 markArray
; /* Offset to MarkArray table--from
1084 * beginning of MarkBasePos subtable */
1086 baseArray
; /* Offset to BaseArray table--from
1087 * beginning of MarkBasePos subtable */
1089 DEFINE_SIZE_STATIC (12);
1094 template <typename context_t
>
1095 inline typename
context_t::return_t
dispatch (context_t
*c
) const
1097 TRACE_DISPATCH (this, u
.format
);
1098 if (unlikely (!c
->may_dispatch (this, &u
.format
))) TRACE_RETURN (c
->default_return_value ());
1100 case 1: return TRACE_RETURN (c
->dispatch (u
.format1
));
1101 default:return TRACE_RETURN (c
->default_return_value ());
1107 USHORT format
; /* Format identifier */
1108 MarkBasePosFormat1 format1
;
1113 typedef AnchorMatrix LigatureAttach
; /* component-major--
1114 * in order of writing direction--,
1116 * ordered by class--zero-based. */
1118 typedef OffsetListOf
<LigatureAttach
> LigatureArray
;
1119 /* Array of LigatureAttach
1121 * LigatureCoverage Index */
1123 struct MarkLigPosFormat1
1125 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
1127 TRACE_COLLECT_GLYPHS (this);
1128 (this+markCoverage
).add_coverage (c
->input
);
1129 (this+ligatureCoverage
).add_coverage (c
->input
);
1132 inline const Coverage
&get_coverage (void) const
1134 return this+markCoverage
;
1137 inline bool apply (hb_apply_context_t
*c
) const
1140 hb_buffer_t
*buffer
= c
->buffer
;
1141 unsigned int mark_index
= (this+markCoverage
).get_coverage (buffer
->cur().codepoint
);
1142 if (likely (mark_index
== NOT_COVERED
)) return TRACE_RETURN (false);
1144 /* now we search backwards for a non-mark glyph */
1145 hb_apply_context_t::skipping_iterator_t
&skippy_iter
= c
->iter_input
;
1146 skippy_iter
.reset (buffer
->idx
, 1);
1147 skippy_iter
.set_lookup_props (LookupFlag::IgnoreMarks
);
1148 if (!skippy_iter
.prev ()) return TRACE_RETURN (false);
1150 /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */
1151 if (!_hb_glyph_info_is_ligature (&buffer
->info
[skippy_iter
.idx
])) { /*return TRACE_RETURN (false);*/ }
1153 unsigned int j
= skippy_iter
.idx
;
1154 unsigned int lig_index
= (this+ligatureCoverage
).get_coverage (buffer
->info
[j
].codepoint
);
1155 if (lig_index
== NOT_COVERED
) return TRACE_RETURN (false);
1157 const LigatureArray
& lig_array
= this+ligatureArray
;
1158 const LigatureAttach
& lig_attach
= lig_array
[lig_index
];
1160 /* Find component to attach to */
1161 unsigned int comp_count
= lig_attach
.rows
;
1162 if (unlikely (!comp_count
)) return TRACE_RETURN (false);
1164 /* We must now check whether the ligature ID of the current mark glyph
1165 * is identical to the ligature ID of the found ligature. If yes, we
1166 * can directly use the component index. If not, we attach the mark
1167 * glyph to the last component of the ligature. */
1168 unsigned int comp_index
;
1169 unsigned int lig_id
= _hb_glyph_info_get_lig_id (&buffer
->info
[j
]);
1170 unsigned int mark_id
= _hb_glyph_info_get_lig_id (&buffer
->cur());
1171 unsigned int mark_comp
= _hb_glyph_info_get_lig_comp (&buffer
->cur());
1172 if (lig_id
&& lig_id
== mark_id
&& mark_comp
> 0)
1173 comp_index
= MIN (comp_count
, _hb_glyph_info_get_lig_comp (&buffer
->cur())) - 1;
1175 comp_index
= comp_count
- 1;
1177 return TRACE_RETURN ((this+markArray
).apply (c
, mark_index
, comp_index
, lig_attach
, classCount
, j
));
1180 inline bool sanitize (hb_sanitize_context_t
*c
) const
1182 TRACE_SANITIZE (this);
1183 return TRACE_RETURN (c
->check_struct (this) && markCoverage
.sanitize (c
, this) && ligatureCoverage
.sanitize (c
, this) &&
1184 markArray
.sanitize (c
, this) && ligatureArray
.sanitize (c
, this, (unsigned int) classCount
));
1188 USHORT format
; /* Format identifier--format = 1 */
1190 markCoverage
; /* Offset to Mark Coverage table--from
1191 * beginning of MarkLigPos subtable */
1193 ligatureCoverage
; /* Offset to Ligature Coverage
1194 * table--from beginning of MarkLigPos
1196 USHORT classCount
; /* Number of defined mark classes */
1198 markArray
; /* Offset to MarkArray table--from
1199 * beginning of MarkLigPos subtable */
1200 OffsetTo
<LigatureArray
>
1201 ligatureArray
; /* Offset to LigatureArray table--from
1202 * beginning of MarkLigPos subtable */
1204 DEFINE_SIZE_STATIC (12);
1209 template <typename context_t
>
1210 inline typename
context_t::return_t
dispatch (context_t
*c
) const
1212 TRACE_DISPATCH (this, u
.format
);
1213 if (unlikely (!c
->may_dispatch (this, &u
.format
))) TRACE_RETURN (c
->default_return_value ());
1215 case 1: return TRACE_RETURN (c
->dispatch (u
.format1
));
1216 default:return TRACE_RETURN (c
->default_return_value ());
1222 USHORT format
; /* Format identifier */
1223 MarkLigPosFormat1 format1
;
1228 typedef AnchorMatrix Mark2Array
; /* mark2-major--
1229 * in order of Mark2Coverage Index--,
1231 * ordered by class--zero-based. */
1233 struct MarkMarkPosFormat1
1235 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
1237 TRACE_COLLECT_GLYPHS (this);
1238 (this+mark1Coverage
).add_coverage (c
->input
);
1239 (this+mark2Coverage
).add_coverage (c
->input
);
1242 inline const Coverage
&get_coverage (void) const
1244 return this+mark1Coverage
;
1247 inline bool apply (hb_apply_context_t
*c
) const
1250 hb_buffer_t
*buffer
= c
->buffer
;
1251 unsigned int mark1_index
= (this+mark1Coverage
).get_coverage (buffer
->cur().codepoint
);
1252 if (likely (mark1_index
== NOT_COVERED
)) return TRACE_RETURN (false);
1254 /* now we search backwards for a suitable mark glyph until a non-mark glyph */
1255 hb_apply_context_t::skipping_iterator_t
&skippy_iter
= c
->iter_input
;
1256 skippy_iter
.reset (buffer
->idx
, 1);
1257 skippy_iter
.set_lookup_props (c
->lookup_props
& ~LookupFlag::IgnoreFlags
);
1258 if (!skippy_iter
.prev ()) return TRACE_RETURN (false);
1260 if (!_hb_glyph_info_is_mark (&buffer
->info
[skippy_iter
.idx
])) { return TRACE_RETURN (false); }
1262 unsigned int j
= skippy_iter
.idx
;
1264 unsigned int id1
= _hb_glyph_info_get_lig_id (&buffer
->cur());
1265 unsigned int id2
= _hb_glyph_info_get_lig_id (&buffer
->info
[j
]);
1266 unsigned int comp1
= _hb_glyph_info_get_lig_comp (&buffer
->cur());
1267 unsigned int comp2
= _hb_glyph_info_get_lig_comp (&buffer
->info
[j
]);
1269 if (likely (id1
== id2
)) {
1270 if (id1
== 0) /* Marks belonging to the same base. */
1272 else if (comp1
== comp2
) /* Marks belonging to the same ligature component. */
1275 /* If ligature ids don't match, it may be the case that one of the marks
1276 * itself is a ligature. In which case match. */
1277 if ((id1
> 0 && !comp1
) || (id2
> 0 && !comp2
))
1282 return TRACE_RETURN (false);
1285 unsigned int mark2_index
= (this+mark2Coverage
).get_coverage (buffer
->info
[j
].codepoint
);
1286 if (mark2_index
== NOT_COVERED
) return TRACE_RETURN (false);
1288 return TRACE_RETURN ((this+mark1Array
).apply (c
, mark1_index
, mark2_index
, this+mark2Array
, classCount
, j
));
1291 inline bool sanitize (hb_sanitize_context_t
*c
) const
1293 TRACE_SANITIZE (this);
1294 return TRACE_RETURN (c
->check_struct (this) && mark1Coverage
.sanitize (c
, this) &&
1295 mark2Coverage
.sanitize (c
, this) && mark1Array
.sanitize (c
, this)
1296 && mark2Array
.sanitize (c
, this, (unsigned int) classCount
));
1300 USHORT format
; /* Format identifier--format = 1 */
1302 mark1Coverage
; /* Offset to Combining Mark1 Coverage
1303 * table--from beginning of MarkMarkPos
1306 mark2Coverage
; /* Offset to Combining Mark2 Coverage
1307 * table--from beginning of MarkMarkPos
1309 USHORT classCount
; /* Number of defined mark classes */
1311 mark1Array
; /* Offset to Mark1Array table--from
1312 * beginning of MarkMarkPos subtable */
1313 OffsetTo
<Mark2Array
>
1314 mark2Array
; /* Offset to Mark2Array table--from
1315 * beginning of MarkMarkPos subtable */
1317 DEFINE_SIZE_STATIC (12);
1322 template <typename context_t
>
1323 inline typename
context_t::return_t
dispatch (context_t
*c
) const
1325 TRACE_DISPATCH (this, u
.format
);
1326 if (unlikely (!c
->may_dispatch (this, &u
.format
))) TRACE_RETURN (c
->default_return_value ());
1328 case 1: return TRACE_RETURN (c
->dispatch (u
.format1
));
1329 default:return TRACE_RETURN (c
->default_return_value ());
1335 USHORT format
; /* Format identifier */
1336 MarkMarkPosFormat1 format1
;
1341 struct ContextPos
: Context
{};
1343 struct ChainContextPos
: ChainContext
{};
1345 struct ExtensionPos
: Extension
<ExtensionPos
>
1347 typedef struct PosLookupSubTable LookupSubTable
;
1357 struct PosLookupSubTable
1359 friend struct PosLookup
;
1373 template <typename context_t
>
1374 inline typename
context_t::return_t
dispatch (context_t
*c
, unsigned int lookup_type
) const
1376 TRACE_DISPATCH (this, lookup_type
);
1377 /* The sub_format passed to may_dispatch is unnecessary but harmless. */
1378 if (unlikely (!c
->may_dispatch (this, &u
.sub_format
))) TRACE_RETURN (c
->default_return_value ());
1379 switch (lookup_type
) {
1380 case Single
: return TRACE_RETURN (u
.single
.dispatch (c
));
1381 case Pair
: return TRACE_RETURN (u
.pair
.dispatch (c
));
1382 case Cursive
: return TRACE_RETURN (u
.cursive
.dispatch (c
));
1383 case MarkBase
: return TRACE_RETURN (u
.markBase
.dispatch (c
));
1384 case MarkLig
: return TRACE_RETURN (u
.markLig
.dispatch (c
));
1385 case MarkMark
: return TRACE_RETURN (u
.markMark
.dispatch (c
));
1386 case Context
: return TRACE_RETURN (u
.context
.dispatch (c
));
1387 case ChainContext
: return TRACE_RETURN (u
.chainContext
.dispatch (c
));
1388 case Extension
: return TRACE_RETURN (u
.extension
.dispatch (c
));
1389 default: return TRACE_RETURN (c
->default_return_value ());
1399 MarkBasePos markBase
;
1401 MarkMarkPos markMark
;
1403 ChainContextPos chainContext
;
1404 ExtensionPos extension
;
1407 DEFINE_SIZE_UNION (2, sub_format
);
1411 struct PosLookup
: Lookup
1413 inline const PosLookupSubTable
& get_subtable (unsigned int i
) const
1414 { return Lookup::get_subtable
<PosLookupSubTable
> (i
); }
1416 inline bool is_reverse (void) const
1421 inline bool apply (hb_apply_context_t
*c
) const
1424 return TRACE_RETURN (dispatch (c
));
1427 inline hb_collect_glyphs_context_t::return_t
collect_glyphs (hb_collect_glyphs_context_t
*c
) const
1429 TRACE_COLLECT_GLYPHS (this);
1430 return TRACE_RETURN (dispatch (c
));
1433 template <typename set_t
>
1434 inline void add_coverage (set_t
*glyphs
) const
1436 hb_add_coverage_context_t
<set_t
> c (glyphs
);
1440 static bool apply_recurse_func (hb_apply_context_t
*c
, unsigned int lookup_index
);
1442 template <typename context_t
>
1443 static inline typename
context_t::return_t
dispatch_recurse_func (context_t
*c
, unsigned int lookup_index
);
1445 template <typename context_t
>
1446 inline typename
context_t::return_t
dispatch (context_t
*c
) const
1447 { return Lookup::dispatch
<PosLookupSubTable
> (c
); }
1449 inline bool sanitize (hb_sanitize_context_t
*c
) const
1451 TRACE_SANITIZE (this);
1452 if (unlikely (!Lookup::sanitize (c
))) return TRACE_RETURN (false);
1453 return TRACE_RETURN (dispatch (c
));
1457 typedef OffsetListOf
<PosLookup
> PosLookupList
;
1460 * GPOS -- The Glyph Positioning Table
1463 struct GPOS
: GSUBGPOS
1465 static const hb_tag_t tableTag
= HB_OT_TAG_GPOS
;
1467 inline const PosLookup
& get_lookup (unsigned int i
) const
1468 { return CastR
<PosLookup
> (GSUBGPOS::get_lookup (i
)); }
1470 static inline void position_start (hb_font_t
*font
, hb_buffer_t
*buffer
);
1471 static inline void position_finish (hb_font_t
*font
, hb_buffer_t
*buffer
);
1473 inline bool sanitize (hb_sanitize_context_t
*c
) const
1475 TRACE_SANITIZE (this);
1476 if (unlikely (!GSUBGPOS::sanitize (c
))) return TRACE_RETURN (false);
1477 const OffsetTo
<PosLookupList
> &list
= CastR
<OffsetTo
<PosLookupList
> > (lookupList
);
1478 return TRACE_RETURN (list
.sanitize (c
, this));
1481 DEFINE_SIZE_STATIC (10);
1486 fix_cursive_minor_offset (hb_glyph_position_t
*pos
, unsigned int i
, hb_direction_t direction
)
1488 unsigned int j
= pos
[i
].cursive_chain();
1494 pos
[i
].cursive_chain() = 0;
1496 fix_cursive_minor_offset (pos
, j
, direction
);
1498 if (HB_DIRECTION_IS_HORIZONTAL (direction
))
1499 pos
[i
].y_offset
+= pos
[j
].y_offset
;
1501 pos
[i
].x_offset
+= pos
[j
].x_offset
;
1505 fix_mark_attachment (hb_glyph_position_t
*pos
, unsigned int i
, hb_direction_t direction
)
1507 if (likely (!(pos
[i
].attach_lookback())))
1510 unsigned int j
= i
- pos
[i
].attach_lookback();
1512 pos
[i
].x_offset
+= pos
[j
].x_offset
;
1513 pos
[i
].y_offset
+= pos
[j
].y_offset
;
1515 if (HB_DIRECTION_IS_FORWARD (direction
))
1516 for (unsigned int k
= j
; k
< i
; k
++) {
1517 pos
[i
].x_offset
-= pos
[k
].x_advance
;
1518 pos
[i
].y_offset
-= pos
[k
].y_advance
;
1521 for (unsigned int k
= j
+ 1; k
< i
+ 1; k
++) {
1522 pos
[i
].x_offset
+= pos
[k
].x_advance
;
1523 pos
[i
].y_offset
+= pos
[k
].y_advance
;
1528 GPOS::position_start (hb_font_t
*font HB_UNUSED
, hb_buffer_t
*buffer
)
1530 buffer
->clear_positions ();
1532 unsigned int count
= buffer
->len
;
1533 for (unsigned int i
= 0; i
< count
; i
++)
1534 buffer
->pos
[i
].attach_lookback() = buffer
->pos
[i
].cursive_chain() = 0;
1538 GPOS::position_finish (hb_font_t
*font HB_UNUSED
, hb_buffer_t
*buffer
)
1540 _hb_buffer_assert_gsubgpos_vars (buffer
);
1543 hb_glyph_position_t
*pos
= hb_buffer_get_glyph_positions (buffer
, &len
);
1544 hb_direction_t direction
= buffer
->props
.direction
;
1546 /* Handle cursive connections */
1547 for (unsigned int i
= 0; i
< len
; i
++)
1548 fix_cursive_minor_offset (pos
, i
, direction
);
1550 /* Handle attachments */
1551 for (unsigned int i
= 0; i
< len
; i
++)
1552 fix_mark_attachment (pos
, i
, direction
);
1556 /* Out-of-class implementation for methods recursing */
1558 template <typename context_t
>
1559 /*static*/ inline typename
context_t::return_t
PosLookup::dispatch_recurse_func (context_t
*c
, unsigned int lookup_index
)
1561 const GPOS
&gpos
= *(hb_ot_layout_from_face (c
->face
)->gpos
);
1562 const PosLookup
&l
= gpos
.get_lookup (lookup_index
);
1563 return l
.dispatch (c
);
1566 /*static*/ inline bool PosLookup::apply_recurse_func (hb_apply_context_t
*c
, unsigned int lookup_index
)
1568 const GPOS
&gpos
= *(hb_ot_layout_from_face (c
->face
)->gpos
);
1569 const PosLookup
&l
= gpos
.get_lookup (lookup_index
);
1570 unsigned int saved_lookup_props
= c
->lookup_props
;
1571 unsigned int saved_lookup_index
= c
->lookup_index
;
1572 c
->set_lookup_index (lookup_index
);
1573 c
->set_lookup_props (l
.get_props ());
1574 bool ret
= l
.dispatch (c
);
1575 c
->set_lookup_index (saved_lookup_index
);
1576 c
->set_lookup_props (saved_lookup_props
);
1581 #undef attach_lookback
1582 #undef cursive_chain
1585 } /* namespace OT */
1588 #endif /* HB_OT_LAYOUT_GPOS_TABLE_HH */