2 * Copyright © 2007,2008,2009,2010 Red Hat, Inc.
3 * Copyright © 2010,2012 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
= 0x0001, /* Includes horizontal adjustment for placement */
53 yPlacement
= 0x0002, /* Includes vertical adjustment for placement */
54 xAdvance
= 0x0004, /* Includes horizontal adjustment for advance */
55 yAdvance
= 0x0008, /* Includes vertical adjustment for advance */
56 xPlaDevice
= 0x0010, /* Includes horizontal Device table for placement */
57 yPlaDevice
= 0x0020, /* Includes vertical Device table for placement */
58 xAdvDevice
= 0x0040, /* Includes horizontal Device table for advance */
59 yAdvDevice
= 0x0080, /* Includes vertical Device table for advance */
60 ignored
= 0x0F00, /* Was used in TrueType Open for MM fonts */
61 reserved
= 0xF000, /* For future use */
63 devices
= 0x00F0 /* Mask for having any Device table */
66 /* All fields are options. Only those available advance the value pointer. */
68 SHORT xPlacement
; /* Horizontal adjustment for
69 * placement--in design units */
70 SHORT yPlacement
; /* Vertical adjustment for
71 * placement--in design units */
72 SHORT xAdvance
; /* Horizontal adjustment for
73 * advance--in design units (only used
74 * for horizontal writing) */
75 SHORT yAdvance
; /* Vertical adjustment for advance--in
76 * design units (only used for vertical
78 Offset xPlaDevice
; /* Offset to Device table for
79 * horizontal placement--measured from
80 * beginning of PosTable (may be NULL) */
81 Offset yPlaDevice
; /* Offset to Device table for vertical
82 * placement--measured from beginning
83 * of PosTable (may be NULL) */
84 Offset xAdvDevice
; /* Offset to Device table for
85 * horizontal advance--measured from
86 * beginning of PosTable (may be NULL) */
87 Offset yAdvDevice
; /* Offset to Device table for vertical
88 * advance--measured from beginning of
89 * PosTable (may be NULL) */
92 inline unsigned int get_len (void) const
93 { return _hb_popcount32 ((unsigned int) *this); }
94 inline unsigned int get_size (void) const
95 { return get_len () * Value::static_size
; }
97 void apply_value (hb_font_t
*font
,
98 hb_direction_t direction
,
101 hb_glyph_position_t
&glyph_pos
) const
103 unsigned int x_ppem
, y_ppem
;
104 unsigned int format
= *this;
105 hb_bool_t horizontal
= HB_DIRECTION_IS_HORIZONTAL (direction
);
109 if (format
& xPlacement
) glyph_pos
.x_offset
+= font
->em_scale_x (get_short (values
++));
110 if (format
& yPlacement
) glyph_pos
.y_offset
+= font
->em_scale_y (get_short (values
++));
111 if (format
& xAdvance
) {
112 if (likely (horizontal
)) glyph_pos
.x_advance
+= font
->em_scale_x (get_short (values
++)); else values
++;
114 /* y_advance values grow downward but font-space grows upward, hence negation */
115 if (format
& yAdvance
) {
116 if (unlikely (!horizontal
)) glyph_pos
.y_advance
-= font
->em_scale_y (get_short (values
++)); else values
++;
119 if (!has_device ()) return;
121 x_ppem
= font
->x_ppem
;
122 y_ppem
= font
->y_ppem
;
124 if (!x_ppem
&& !y_ppem
) return;
126 /* pixel -> fractional pixel */
127 if (format
& xPlaDevice
) {
128 if (x_ppem
) glyph_pos
.x_offset
+= (base
+ get_device (values
++)).get_x_delta (font
); else values
++;
130 if (format
& yPlaDevice
) {
131 if (y_ppem
) glyph_pos
.y_offset
+= (base
+ get_device (values
++)).get_y_delta (font
); else values
++;
133 if (format
& xAdvDevice
) {
134 if (horizontal
&& x_ppem
) glyph_pos
.x_advance
+= (base
+ get_device (values
++)).get_x_delta (font
); else values
++;
136 if (format
& yAdvDevice
) {
137 /* y_advance values grow downward but font-space grows upward, hence negation */
138 if (!horizontal
&& y_ppem
) glyph_pos
.y_advance
-= (base
+ get_device (values
++)).get_y_delta (font
); else values
++;
143 inline bool sanitize_value_devices (hb_sanitize_context_t
*c
, void *base
, Value
*values
) {
144 unsigned int format
= *this;
146 if (format
& xPlacement
) values
++;
147 if (format
& yPlacement
) values
++;
148 if (format
& xAdvance
) values
++;
149 if (format
& yAdvance
) values
++;
151 if ((format
& xPlaDevice
) && !get_device (values
++).sanitize (c
, base
)) return false;
152 if ((format
& yPlaDevice
) && !get_device (values
++).sanitize (c
, base
)) return false;
153 if ((format
& xAdvDevice
) && !get_device (values
++).sanitize (c
, base
)) return false;
154 if ((format
& yAdvDevice
) && !get_device (values
++).sanitize (c
, base
)) return false;
159 static inline OffsetTo
<Device
>& get_device (Value
* value
)
160 { return *CastP
<OffsetTo
<Device
> > (value
); }
161 static inline const OffsetTo
<Device
>& get_device (const Value
* value
)
162 { return *CastP
<OffsetTo
<Device
> > (value
); }
164 static inline const SHORT
& get_short (const Value
* value
)
165 { return *CastP
<SHORT
> (value
); }
169 inline bool has_device (void) const {
170 unsigned int format
= *this;
171 return (format
& devices
) != 0;
174 inline bool sanitize_value (hb_sanitize_context_t
*c
, void *base
, Value
*values
) {
175 TRACE_SANITIZE (this);
176 return TRACE_RETURN (c
->check_range (values
, get_size ()) && (!has_device () || sanitize_value_devices (c
, base
, values
)));
179 inline bool sanitize_values (hb_sanitize_context_t
*c
, void *base
, Value
*values
, unsigned int count
) {
180 TRACE_SANITIZE (this);
181 unsigned int len
= get_len ();
183 if (!c
->check_array (values
, get_size (), count
)) return TRACE_RETURN (false);
185 if (!has_device ()) return TRACE_RETURN (true);
187 for (unsigned int i
= 0; i
< count
; i
++) {
188 if (!sanitize_value_devices (c
, base
, values
))
189 return TRACE_RETURN (false);
193 return TRACE_RETURN (true);
196 /* Just sanitize referenced Device tables. Doesn't check the values themselves. */
197 inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t
*c
, void *base
, Value
*values
, unsigned int count
, unsigned int stride
) {
198 TRACE_SANITIZE (this);
200 if (!has_device ()) return TRACE_RETURN (true);
202 for (unsigned int i
= 0; i
< count
; i
++) {
203 if (!sanitize_value_devices (c
, base
, values
))
204 return TRACE_RETURN (false);
208 return TRACE_RETURN (true);
215 inline void get_anchor (hb_font_t
*font
, hb_codepoint_t glyph_id HB_UNUSED
,
216 hb_position_t
*x
, hb_position_t
*y
) const
218 *x
= font
->em_scale_x (xCoordinate
);
219 *y
= font
->em_scale_y (yCoordinate
);
222 inline bool sanitize (hb_sanitize_context_t
*c
) {
223 TRACE_SANITIZE (this);
224 return TRACE_RETURN (c
->check_struct (this));
228 USHORT format
; /* Format identifier--format = 1 */
229 SHORT xCoordinate
; /* Horizontal value--in design units */
230 SHORT yCoordinate
; /* Vertical value--in design units */
232 DEFINE_SIZE_STATIC (6);
237 inline void get_anchor (hb_font_t
*font
, hb_codepoint_t glyph_id
,
238 hb_position_t
*x
, hb_position_t
*y
) const
240 unsigned int x_ppem
= font
->x_ppem
;
241 unsigned int y_ppem
= font
->y_ppem
;
242 hb_position_t cx
, cy
;
243 hb_bool_t ret
= false;
245 if (x_ppem
|| y_ppem
)
246 ret
= font
->get_glyph_contour_point_for_origin (glyph_id
, anchorPoint
, HB_DIRECTION_LTR
, &cx
, &cy
);
247 *x
= x_ppem
&& ret
? cx
: font
->em_scale_x (xCoordinate
);
248 *y
= y_ppem
&& ret
? cy
: font
->em_scale_y (yCoordinate
);
251 inline bool sanitize (hb_sanitize_context_t
*c
) {
252 TRACE_SANITIZE (this);
253 return TRACE_RETURN (c
->check_struct (this));
257 USHORT format
; /* Format identifier--format = 2 */
258 SHORT xCoordinate
; /* Horizontal value--in design units */
259 SHORT yCoordinate
; /* Vertical value--in design units */
260 USHORT anchorPoint
; /* Index to glyph contour point */
262 DEFINE_SIZE_STATIC (8);
267 inline void get_anchor (hb_font_t
*font
, hb_codepoint_t glyph_id HB_UNUSED
,
268 hb_position_t
*x
, hb_position_t
*y
) const
270 *x
= font
->em_scale_x (xCoordinate
);
271 *y
= font
->em_scale_y (yCoordinate
);
274 *x
+= (this+xDeviceTable
).get_x_delta (font
);
276 *y
+= (this+yDeviceTable
).get_x_delta (font
);
279 inline bool sanitize (hb_sanitize_context_t
*c
) {
280 TRACE_SANITIZE (this);
281 return TRACE_RETURN (c
->check_struct (this) && xDeviceTable
.sanitize (c
, this) && yDeviceTable
.sanitize (c
, this));
285 USHORT format
; /* Format identifier--format = 3 */
286 SHORT xCoordinate
; /* Horizontal value--in design units */
287 SHORT yCoordinate
; /* Vertical value--in design units */
289 xDeviceTable
; /* Offset to Device table for X
290 * coordinate-- from beginning of
291 * Anchor table (may be NULL) */
293 yDeviceTable
; /* Offset to Device table for Y
294 * coordinate-- from beginning of
295 * Anchor table (may be NULL) */
297 DEFINE_SIZE_STATIC (10);
302 inline void get_anchor (hb_font_t
*font
, hb_codepoint_t glyph_id
,
303 hb_position_t
*x
, hb_position_t
*y
) const
307 case 1: u
.format1
.get_anchor (font
, glyph_id
, x
, y
); return;
308 case 2: u
.format2
.get_anchor (font
, glyph_id
, x
, y
); return;
309 case 3: u
.format3
.get_anchor (font
, glyph_id
, x
, y
); return;
314 inline bool sanitize (hb_sanitize_context_t
*c
) {
315 TRACE_SANITIZE (this);
316 if (!u
.format
.sanitize (c
)) return TRACE_RETURN (false);
318 case 1: return TRACE_RETURN (u
.format1
.sanitize (c
));
319 case 2: return TRACE_RETURN (u
.format2
.sanitize (c
));
320 case 3: return TRACE_RETURN (u
.format3
.sanitize (c
));
321 default:return TRACE_RETURN (true);
327 USHORT format
; /* Format identifier */
328 AnchorFormat1 format1
;
329 AnchorFormat2 format2
;
330 AnchorFormat3 format3
;
333 DEFINE_SIZE_UNION (2, format
);
339 inline const Anchor
& get_anchor (unsigned int row
, unsigned int col
, unsigned int cols
, bool *found
) const {
341 if (unlikely (row
>= rows
|| col
>= cols
)) return Null(Anchor
);
342 *found
= !matrix
[row
* cols
+ col
].is_null ();
343 return this+matrix
[row
* cols
+ col
];
346 inline bool sanitize (hb_sanitize_context_t
*c
, unsigned int cols
) {
347 TRACE_SANITIZE (this);
348 if (!c
->check_struct (this)) return TRACE_RETURN (false);
349 if (unlikely (rows
> 0 && cols
>= ((unsigned int) -1) / rows
)) return TRACE_RETURN (false);
350 unsigned int count
= rows
* cols
;
351 if (!c
->check_array (matrix
, matrix
[0].static_size
, count
)) return TRACE_RETURN (false);
352 for (unsigned int i
= 0; i
< count
; i
++)
353 if (!matrix
[i
].sanitize (c
, this)) return TRACE_RETURN (false);
354 return TRACE_RETURN (true);
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
) {
372 TRACE_SANITIZE (this);
373 return TRACE_RETURN (c
->check_struct (this) && markAnchor
.sanitize (c
, base
));
377 USHORT klass
; /* Class defined for this mark */
379 markAnchor
; /* Offset to Anchor table--from
380 * beginning of MarkArray table */
382 DEFINE_SIZE_STATIC (4);
385 struct MarkArray
: ArrayOf
<MarkRecord
> /* Array of MarkRecords--in Coverage order */
387 inline bool apply (hb_apply_context_t
*c
,
388 unsigned int mark_index
, unsigned int glyph_index
,
389 const AnchorMatrix
&anchors
, unsigned int class_count
,
390 unsigned int glyph_pos
) const
393 const MarkRecord
&record
= ArrayOf
<MarkRecord
>::operator[](mark_index
);
394 unsigned int mark_class
= record
.klass
;
396 const Anchor
& mark_anchor
= this + record
.markAnchor
;
398 const Anchor
& glyph_anchor
= anchors
.get_anchor (glyph_index
, mark_class
, class_count
, &found
);
399 /* If this subtable doesn't have an anchor for this base and this class,
400 * return false such that the subsequent subtables have a chance at it. */
401 if (unlikely (!found
)) return TRACE_RETURN (false);
403 hb_position_t mark_x
, mark_y
, base_x
, base_y
;
405 mark_anchor
.get_anchor (c
->font
, c
->buffer
->cur().codepoint
, &mark_x
, &mark_y
);
406 glyph_anchor
.get_anchor (c
->font
, c
->buffer
->info
[glyph_pos
].codepoint
, &base_x
, &base_y
);
408 hb_glyph_position_t
&o
= c
->buffer
->cur_pos();
409 o
.x_offset
= base_x
- mark_x
;
410 o
.y_offset
= base_y
- mark_y
;
411 o
.attach_lookback() = c
->buffer
->idx
- glyph_pos
;
414 return TRACE_RETURN (true);
417 inline bool sanitize (hb_sanitize_context_t
*c
) {
418 TRACE_SANITIZE (this);
419 return TRACE_RETURN (ArrayOf
<MarkRecord
>::sanitize (c
, this));
426 struct SinglePosFormat1
428 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
430 TRACE_COLLECT_GLYPHS (this);
431 (this+coverage
).add_coverage (c
->input
);
434 inline const Coverage
&get_coverage (void) const
436 return this+coverage
;
439 inline bool apply (hb_apply_context_t
*c
) const
442 unsigned int index
= (this+coverage
).get_coverage (c
->buffer
->cur().codepoint
);
443 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
445 valueFormat
.apply_value (c
->font
, c
->direction
, this,
446 values
, c
->buffer
->cur_pos());
449 return TRACE_RETURN (true);
452 inline bool sanitize (hb_sanitize_context_t
*c
) {
453 TRACE_SANITIZE (this);
454 return TRACE_RETURN (c
->check_struct (this) && coverage
.sanitize (c
, this) && valueFormat
.sanitize_value (c
, this, values
));
458 USHORT format
; /* Format identifier--format = 1 */
460 coverage
; /* Offset to Coverage table--from
461 * beginning of subtable */
462 ValueFormat valueFormat
; /* Defines the types of data in the
464 ValueRecord values
; /* Defines positioning
465 * value(s)--applied to all glyphs in
466 * the Coverage table */
468 DEFINE_SIZE_ARRAY (6, values
);
471 struct SinglePosFormat2
473 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
475 TRACE_COLLECT_GLYPHS (this);
476 (this+coverage
).add_coverage (c
->input
);
479 inline const Coverage
&get_coverage (void) const
481 return this+coverage
;
484 inline bool apply (hb_apply_context_t
*c
) const
487 unsigned int index
= (this+coverage
).get_coverage (c
->buffer
->cur().codepoint
);
488 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
490 if (likely (index
>= valueCount
)) return TRACE_RETURN (false);
492 valueFormat
.apply_value (c
->font
, c
->direction
, this,
493 &values
[index
* valueFormat
.get_len ()],
494 c
->buffer
->cur_pos());
497 return TRACE_RETURN (true);
500 inline bool sanitize (hb_sanitize_context_t
*c
) {
501 TRACE_SANITIZE (this);
502 return TRACE_RETURN (c
->check_struct (this) && coverage
.sanitize (c
, this) && valueFormat
.sanitize_values (c
, this, values
, valueCount
));
506 USHORT format
; /* Format identifier--format = 2 */
508 coverage
; /* Offset to Coverage table--from
509 * beginning of subtable */
510 ValueFormat valueFormat
; /* Defines the types of data in the
512 USHORT valueCount
; /* Number of ValueRecords */
513 ValueRecord values
; /* Array of ValueRecords--positioning
514 * values applied to glyphs */
516 DEFINE_SIZE_ARRAY (8, values
);
521 template <typename context_t
>
522 inline typename
context_t::return_t
dispatch (context_t
*c
) const
524 TRACE_DISPATCH (this);
526 case 1: return TRACE_RETURN (c
->dispatch (u
.format1
));
527 case 2: return TRACE_RETURN (c
->dispatch (u
.format2
));
528 default:return TRACE_RETURN (c
->default_return_value ());
532 inline bool sanitize (hb_sanitize_context_t
*c
) {
533 TRACE_SANITIZE (this);
534 if (!u
.format
.sanitize (c
)) return TRACE_RETURN (false);
536 case 1: return TRACE_RETURN (u
.format1
.sanitize (c
));
537 case 2: return TRACE_RETURN (u
.format2
.sanitize (c
));
538 default:return TRACE_RETURN (true);
544 USHORT format
; /* Format identifier */
545 SinglePosFormat1 format1
;
546 SinglePosFormat2 format2
;
551 struct PairValueRecord
553 friend struct PairSet
;
556 GlyphID secondGlyph
; /* GlyphID of second glyph in the
557 * pair--first glyph is listed in the
559 ValueRecord values
; /* Positioning data for the first glyph
560 * followed by for second glyph */
562 DEFINE_SIZE_ARRAY (2, values
);
567 friend struct PairPosFormat1
;
569 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
,
570 const ValueFormat
*valueFormats
) const
572 TRACE_COLLECT_GLYPHS (this);
573 unsigned int len1
= valueFormats
[0].get_len ();
574 unsigned int len2
= valueFormats
[1].get_len ();
575 unsigned int record_size
= USHORT::static_size
* (1 + len1
+ len2
);
577 const PairValueRecord
*record
= CastP
<PairValueRecord
> (array
);
578 unsigned int count
= len
;
579 for (unsigned int i
= 0; i
< count
; i
++)
581 c
->input
->add (record
->secondGlyph
);
582 record
= &StructAtOffset
<PairValueRecord
> (record
, record_size
);
586 inline bool apply (hb_apply_context_t
*c
,
587 const ValueFormat
*valueFormats
,
588 unsigned int pos
) const
591 unsigned int len1
= valueFormats
[0].get_len ();
592 unsigned int len2
= valueFormats
[1].get_len ();
593 unsigned int record_size
= USHORT::static_size
* (1 + len1
+ len2
);
595 const PairValueRecord
*record
= CastP
<PairValueRecord
> (array
);
596 unsigned int count
= len
;
597 for (unsigned int i
= 0; i
< count
; i
++)
600 if (c
->buffer
->info
[pos
].codepoint
== record
->secondGlyph
)
602 valueFormats
[0].apply_value (c
->font
, c
->direction
, this,
603 &record
->values
[0], c
->buffer
->cur_pos());
604 valueFormats
[1].apply_value (c
->font
, c
->direction
, this,
605 &record
->values
[len1
], c
->buffer
->pos
[pos
]);
608 c
->buffer
->idx
= pos
;
609 return TRACE_RETURN (true);
611 record
= &StructAtOffset
<PairValueRecord
> (record
, record_size
);
614 return TRACE_RETURN (false);
617 struct sanitize_closure_t
{
619 ValueFormat
*valueFormats
;
620 unsigned int len1
; /* valueFormats[0].get_len() */
621 unsigned int stride
; /* 1 + len1 + len2 */
624 inline bool sanitize (hb_sanitize_context_t
*c
, const sanitize_closure_t
*closure
) {
625 TRACE_SANITIZE (this);
626 if (!(c
->check_struct (this)
627 && c
->check_array (array
, USHORT::static_size
* closure
->stride
, len
))) return TRACE_RETURN (false);
629 unsigned int count
= len
;
630 PairValueRecord
*record
= CastP
<PairValueRecord
> (array
);
631 return TRACE_RETURN (closure
->valueFormats
[0].sanitize_values_stride_unsafe (c
, closure
->base
, &record
->values
[0], count
, closure
->stride
)
632 && closure
->valueFormats
[1].sanitize_values_stride_unsafe (c
, closure
->base
, &record
->values
[closure
->len1
], count
, closure
->stride
));
636 USHORT len
; /* Number of PairValueRecords */
637 USHORT array
[VAR
]; /* Array of PairValueRecords--ordered
638 * by GlyphID of the second glyph */
640 DEFINE_SIZE_ARRAY (2, array
);
643 struct PairPosFormat1
645 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
647 TRACE_COLLECT_GLYPHS (this);
648 (this+coverage
).add_coverage (c
->input
);
649 unsigned int count
= pairSet
.len
;
650 for (unsigned int i
= 0; i
< count
; i
++)
651 (this+pairSet
[i
]).collect_glyphs (c
, &valueFormat1
);
654 inline const Coverage
&get_coverage (void) const
656 return this+coverage
;
659 inline bool apply (hb_apply_context_t
*c
) const
662 hb_apply_context_t::skipping_forward_iterator_t
skippy_iter (c
, c
->buffer
->idx
, 1);
663 if (skippy_iter
.has_no_chance ()) return TRACE_RETURN (false);
665 unsigned int index
= (this+coverage
).get_coverage (c
->buffer
->cur().codepoint
);
666 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
668 if (!skippy_iter
.next ()) return TRACE_RETURN (false);
670 return TRACE_RETURN ((this+pairSet
[index
]).apply (c
, &valueFormat1
, skippy_iter
.idx
));
673 inline bool sanitize (hb_sanitize_context_t
*c
) {
674 TRACE_SANITIZE (this);
676 unsigned int len1
= valueFormat1
.get_len ();
677 unsigned int len2
= valueFormat2
.get_len ();
678 PairSet::sanitize_closure_t closure
= {
685 return TRACE_RETURN (c
->check_struct (this) && coverage
.sanitize (c
, this) && pairSet
.sanitize (c
, this, &closure
));
689 USHORT format
; /* Format identifier--format = 1 */
691 coverage
; /* Offset to Coverage table--from
692 * beginning of subtable */
693 ValueFormat valueFormat1
; /* Defines the types of data in
694 * ValueRecord1--for the first glyph
695 * in the pair--may be zero (0) */
696 ValueFormat valueFormat2
; /* Defines the types of data in
697 * ValueRecord2--for the second glyph
698 * in the pair--may be zero (0) */
699 OffsetArrayOf
<PairSet
>
700 pairSet
; /* Array of PairSet tables
701 * ordered by Coverage Index */
703 DEFINE_SIZE_ARRAY (10, pairSet
);
706 struct PairPosFormat2
708 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
710 TRACE_COLLECT_GLYPHS (this);
711 /* (this+coverage).add_coverage (c->input); // Don't need this. */
713 unsigned int count1
= class1Count
;
714 const ClassDef
&klass1
= this+classDef1
;
715 for (unsigned int i
= 0; i
< count1
; i
++)
716 klass1
.add_class (c
->input
, i
);
718 unsigned int count2
= class2Count
;
719 const ClassDef
&klass2
= this+classDef2
;
720 for (unsigned int i
= 0; i
< count2
; i
++)
721 klass2
.add_class (c
->input
, i
);
724 inline const Coverage
&get_coverage (void) const
726 return this+coverage
;
729 inline bool apply (hb_apply_context_t
*c
) const
732 hb_apply_context_t::skipping_forward_iterator_t
skippy_iter (c
, c
->buffer
->idx
, 1);
733 if (skippy_iter
.has_no_chance ()) return TRACE_RETURN (false);
735 unsigned int index
= (this+coverage
).get_coverage (c
->buffer
->cur().codepoint
);
736 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
738 if (!skippy_iter
.next ()) return TRACE_RETURN (false);
740 unsigned int len1
= valueFormat1
.get_len ();
741 unsigned int len2
= valueFormat2
.get_len ();
742 unsigned int record_len
= len1
+ len2
;
744 unsigned int klass1
= (this+classDef1
).get_class (c
->buffer
->cur().codepoint
);
745 unsigned int klass2
= (this+classDef2
).get_class (c
->buffer
->info
[skippy_iter
.idx
].codepoint
);
746 if (unlikely (klass1
>= class1Count
|| klass2
>= class2Count
)) return TRACE_RETURN (false);
748 const Value
*v
= &values
[record_len
* (klass1
* class2Count
+ klass2
)];
749 valueFormat1
.apply_value (c
->font
, c
->direction
, this,
750 v
, c
->buffer
->cur_pos());
751 valueFormat2
.apply_value (c
->font
, c
->direction
, this,
752 v
+ len1
, c
->buffer
->pos
[skippy_iter
.idx
]);
754 c
->buffer
->idx
= skippy_iter
.idx
;
758 return TRACE_RETURN (true);
761 inline bool sanitize (hb_sanitize_context_t
*c
) {
762 TRACE_SANITIZE (this);
763 if (!(c
->check_struct (this)
764 && coverage
.sanitize (c
, this)
765 && classDef1
.sanitize (c
, this)
766 && classDef2
.sanitize (c
, this))) return TRACE_RETURN (false);
768 unsigned int len1
= valueFormat1
.get_len ();
769 unsigned int len2
= valueFormat2
.get_len ();
770 unsigned int stride
= len1
+ len2
;
771 unsigned int record_size
= valueFormat1
.get_size () + valueFormat2
.get_size ();
772 unsigned int count
= (unsigned int) class1Count
* (unsigned int) class2Count
;
773 return TRACE_RETURN (c
->check_array (values
, record_size
, count
) &&
774 valueFormat1
.sanitize_values_stride_unsafe (c
, this, &values
[0], count
, stride
) &&
775 valueFormat2
.sanitize_values_stride_unsafe (c
, this, &values
[len1
], count
, stride
));
779 USHORT format
; /* Format identifier--format = 2 */
781 coverage
; /* Offset to Coverage table--from
782 * beginning of subtable */
783 ValueFormat valueFormat1
; /* ValueRecord definition--for the
784 * first glyph of the pair--may be zero
786 ValueFormat valueFormat2
; /* ValueRecord definition--for the
787 * second glyph of the pair--may be
790 classDef1
; /* Offset to ClassDef table--from
791 * beginning of PairPos subtable--for
792 * the first glyph of the pair */
794 classDef2
; /* Offset to ClassDef table--from
795 * beginning of PairPos subtable--for
796 * the second glyph of the pair */
797 USHORT class1Count
; /* Number of classes in ClassDef1
798 * table--includes Class0 */
799 USHORT class2Count
; /* Number of classes in ClassDef2
800 * table--includes Class0 */
801 ValueRecord values
; /* Matrix of value pairs:
802 * class1-major, class2-minor,
803 * Each entry has value1 and value2 */
805 DEFINE_SIZE_ARRAY (16, values
);
810 template <typename context_t
>
811 inline typename
context_t::return_t
dispatch (context_t
*c
) const
813 TRACE_DISPATCH (this);
815 case 1: return TRACE_RETURN (c
->dispatch (u
.format1
));
816 case 2: return TRACE_RETURN (c
->dispatch (u
.format2
));
817 default:return TRACE_RETURN (c
->default_return_value ());
821 inline bool sanitize (hb_sanitize_context_t
*c
) {
822 TRACE_SANITIZE (this);
823 if (!u
.format
.sanitize (c
)) return TRACE_RETURN (false);
825 case 1: return TRACE_RETURN (u
.format1
.sanitize (c
));
826 case 2: return TRACE_RETURN (u
.format2
.sanitize (c
));
827 default:return TRACE_RETURN (true);
833 USHORT format
; /* Format identifier */
834 PairPosFormat1 format1
;
835 PairPosFormat2 format2
;
840 struct EntryExitRecord
842 friend struct CursivePosFormat1
;
844 inline bool sanitize (hb_sanitize_context_t
*c
, void *base
) {
845 TRACE_SANITIZE (this);
846 return TRACE_RETURN (entryAnchor
.sanitize (c
, base
) && exitAnchor
.sanitize (c
, base
));
851 entryAnchor
; /* Offset to EntryAnchor table--from
852 * beginning of CursivePos
853 * subtable--may be NULL */
855 exitAnchor
; /* Offset to ExitAnchor table--from
856 * beginning of CursivePos
857 * subtable--may be NULL */
859 DEFINE_SIZE_STATIC (4);
862 struct CursivePosFormat1
864 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
866 TRACE_COLLECT_GLYPHS (this);
867 (this+coverage
).add_coverage (c
->input
);
870 inline const Coverage
&get_coverage (void) const
872 return this+coverage
;
875 inline bool apply (hb_apply_context_t
*c
) const
879 /* We don't handle mark glyphs here. */
880 if (c
->buffer
->cur().glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK
) return TRACE_RETURN (false);
882 hb_apply_context_t::skipping_forward_iterator_t
skippy_iter (c
, c
->buffer
->idx
, 1);
883 if (skippy_iter
.has_no_chance ()) return TRACE_RETURN (false);
885 const EntryExitRecord
&this_record
= entryExitRecord
[(this+coverage
).get_coverage (c
->buffer
->cur().codepoint
)];
886 if (!this_record
.exitAnchor
) return TRACE_RETURN (false);
888 if (!skippy_iter
.next ()) return TRACE_RETURN (false);
890 const EntryExitRecord
&next_record
= entryExitRecord
[(this+coverage
).get_coverage (c
->buffer
->info
[skippy_iter
.idx
].codepoint
)];
891 if (!next_record
.entryAnchor
) return TRACE_RETURN (false);
893 unsigned int i
= c
->buffer
->idx
;
894 unsigned int j
= skippy_iter
.idx
;
896 hb_position_t entry_x
, entry_y
, exit_x
, exit_y
;
897 (this+this_record
.exitAnchor
).get_anchor (c
->font
, c
->buffer
->info
[i
].codepoint
, &exit_x
, &exit_y
);
898 (this+next_record
.entryAnchor
).get_anchor (c
->font
, c
->buffer
->info
[j
].codepoint
, &entry_x
, &entry_y
);
900 hb_glyph_position_t
*pos
= c
->buffer
->pos
;
903 /* Main-direction adjustment */
904 switch (c
->direction
) {
905 case HB_DIRECTION_LTR
:
906 pos
[i
].x_advance
= exit_x
+ pos
[i
].x_offset
;
908 d
= entry_x
+ pos
[j
].x_offset
;
909 pos
[j
].x_advance
-= d
;
910 pos
[j
].x_offset
-= d
;
912 case HB_DIRECTION_RTL
:
913 d
= exit_x
+ pos
[i
].x_offset
;
914 pos
[i
].x_advance
-= d
;
915 pos
[i
].x_offset
-= d
;
917 pos
[j
].x_advance
= entry_x
+ pos
[j
].x_offset
;
919 case HB_DIRECTION_TTB
:
920 pos
[i
].y_advance
= exit_y
+ pos
[i
].y_offset
;
922 d
= entry_y
+ pos
[j
].y_offset
;
923 pos
[j
].y_advance
-= d
;
924 pos
[j
].y_offset
-= d
;
926 case HB_DIRECTION_BTT
:
927 d
= exit_y
+ pos
[i
].y_offset
;
928 pos
[i
].y_advance
-= d
;
929 pos
[i
].y_offset
-= d
;
931 pos
[j
].y_advance
= entry_y
;
933 case HB_DIRECTION_INVALID
:
938 /* Cross-direction adjustment */
939 if (c
->lookup_props
& LookupFlag::RightToLeft
) {
940 pos
[i
].cursive_chain() = j
- i
;
941 if (likely (HB_DIRECTION_IS_HORIZONTAL (c
->direction
)))
942 pos
[i
].y_offset
= entry_y
- exit_y
;
944 pos
[i
].x_offset
= entry_x
- exit_x
;
946 pos
[j
].cursive_chain() = i
- j
;
947 if (likely (HB_DIRECTION_IS_HORIZONTAL (c
->direction
)))
948 pos
[j
].y_offset
= exit_y
- entry_y
;
950 pos
[j
].x_offset
= exit_x
- entry_x
;
954 return TRACE_RETURN (true);
957 inline bool sanitize (hb_sanitize_context_t
*c
) {
958 TRACE_SANITIZE (this);
959 return TRACE_RETURN (coverage
.sanitize (c
, this) && entryExitRecord
.sanitize (c
, this));
963 USHORT format
; /* Format identifier--format = 1 */
965 coverage
; /* Offset to Coverage table--from
966 * beginning of subtable */
967 ArrayOf
<EntryExitRecord
>
968 entryExitRecord
; /* Array of EntryExit records--in
969 * Coverage Index order */
971 DEFINE_SIZE_ARRAY (6, entryExitRecord
);
976 template <typename context_t
>
977 inline typename
context_t::return_t
dispatch (context_t
*c
) const
979 TRACE_DISPATCH (this);
981 case 1: return TRACE_RETURN (c
->dispatch (u
.format1
));
982 default:return TRACE_RETURN (c
->default_return_value ());
986 inline bool sanitize (hb_sanitize_context_t
*c
) {
987 TRACE_SANITIZE (this);
988 if (!u
.format
.sanitize (c
)) return TRACE_RETURN (false);
990 case 1: return TRACE_RETURN (u
.format1
.sanitize (c
));
991 default:return TRACE_RETURN (true);
997 USHORT format
; /* Format identifier */
998 CursivePosFormat1 format1
;
1003 typedef AnchorMatrix BaseArray
; /* base-major--
1004 * in order of BaseCoverage Index--,
1006 * ordered by class--zero-based. */
1008 struct MarkBasePosFormat1
1010 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
1012 TRACE_COLLECT_GLYPHS (this);
1013 (this+markCoverage
).add_coverage (c
->input
);
1014 (this+baseCoverage
).add_coverage (c
->input
);
1017 inline const Coverage
&get_coverage (void) const
1019 return this+markCoverage
;
1022 inline bool apply (hb_apply_context_t
*c
) const
1025 unsigned int mark_index
= (this+markCoverage
).get_coverage (c
->buffer
->cur().codepoint
);
1026 if (likely (mark_index
== NOT_COVERED
)) return TRACE_RETURN (false);
1028 /* now we search backwards for a non-mark glyph */
1029 hb_apply_context_t::skipping_backward_iterator_t
skippy_iter (c
, c
->buffer
->idx
, 1);
1030 skippy_iter
.set_lookup_props (LookupFlag::IgnoreMarks
);
1032 if (!skippy_iter
.prev ()) return TRACE_RETURN (false);
1033 /* We only want to attach to the first of a MultipleSubst sequence. Reject others. */
1034 if (0 == get_lig_comp (c
->buffer
->info
[skippy_iter
.idx
])) break;
1035 skippy_iter
.reject ();
1038 /* The following assertion is too strong, so we've disabled it. */
1039 if (!(c
->buffer
->info
[skippy_iter
.idx
].glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH
)) {/*return TRACE_RETURN (false);*/}
1041 unsigned int base_index
= (this+baseCoverage
).get_coverage (c
->buffer
->info
[skippy_iter
.idx
].codepoint
);
1042 if (base_index
== NOT_COVERED
) return TRACE_RETURN (false);
1044 return TRACE_RETURN ((this+markArray
).apply (c
, mark_index
, base_index
, this+baseArray
, classCount
, skippy_iter
.idx
));
1047 inline bool sanitize (hb_sanitize_context_t
*c
) {
1048 TRACE_SANITIZE (this);
1049 return TRACE_RETURN (c
->check_struct (this) && markCoverage
.sanitize (c
, this) && baseCoverage
.sanitize (c
, this) &&
1050 markArray
.sanitize (c
, this) && baseArray
.sanitize (c
, this, (unsigned int) classCount
));
1054 USHORT format
; /* Format identifier--format = 1 */
1056 markCoverage
; /* Offset to MarkCoverage table--from
1057 * beginning of MarkBasePos subtable */
1059 baseCoverage
; /* Offset to BaseCoverage table--from
1060 * beginning of MarkBasePos subtable */
1061 USHORT classCount
; /* Number of classes defined for marks */
1063 markArray
; /* Offset to MarkArray table--from
1064 * beginning of MarkBasePos subtable */
1066 baseArray
; /* Offset to BaseArray table--from
1067 * beginning of MarkBasePos subtable */
1069 DEFINE_SIZE_STATIC (12);
1074 template <typename context_t
>
1075 inline typename
context_t::return_t
dispatch (context_t
*c
) const
1077 TRACE_DISPATCH (this);
1079 case 1: return TRACE_RETURN (c
->dispatch (u
.format1
));
1080 default:return TRACE_RETURN (c
->default_return_value ());
1084 inline bool sanitize (hb_sanitize_context_t
*c
) {
1085 TRACE_SANITIZE (this);
1086 if (!u
.format
.sanitize (c
)) return TRACE_RETURN (false);
1088 case 1: return TRACE_RETURN (u
.format1
.sanitize (c
));
1089 default:return TRACE_RETURN (true);
1095 USHORT format
; /* Format identifier */
1096 MarkBasePosFormat1 format1
;
1101 typedef AnchorMatrix LigatureAttach
; /* component-major--
1102 * in order of writing direction--,
1104 * ordered by class--zero-based. */
1106 typedef OffsetListOf
<LigatureAttach
> LigatureArray
;
1107 /* Array of LigatureAttach
1109 * LigatureCoverage Index */
1111 struct MarkLigPosFormat1
1113 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
1115 TRACE_COLLECT_GLYPHS (this);
1116 (this+markCoverage
).add_coverage (c
->input
);
1117 (this+ligatureCoverage
).add_coverage (c
->input
);
1120 inline const Coverage
&get_coverage (void) const
1122 return this+markCoverage
;
1125 inline bool apply (hb_apply_context_t
*c
) const
1128 unsigned int mark_index
= (this+markCoverage
).get_coverage (c
->buffer
->cur().codepoint
);
1129 if (likely (mark_index
== NOT_COVERED
)) return TRACE_RETURN (false);
1131 /* now we search backwards for a non-mark glyph */
1132 hb_apply_context_t::skipping_backward_iterator_t
skippy_iter (c
, c
->buffer
->idx
, 1);
1133 skippy_iter
.set_lookup_props (LookupFlag::IgnoreMarks
);
1134 if (!skippy_iter
.prev ()) return TRACE_RETURN (false);
1136 /* The following assertion is too strong, so we've disabled it. */
1137 if (!(c
->buffer
->info
[skippy_iter
.idx
].glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE
)) {/*return TRACE_RETURN (false);*/}
1139 unsigned int j
= skippy_iter
.idx
;
1140 unsigned int lig_index
= (this+ligatureCoverage
).get_coverage (c
->buffer
->info
[j
].codepoint
);
1141 if (lig_index
== NOT_COVERED
) return TRACE_RETURN (false);
1143 const LigatureArray
& lig_array
= this+ligatureArray
;
1144 const LigatureAttach
& lig_attach
= lig_array
[lig_index
];
1146 /* Find component to attach to */
1147 unsigned int comp_count
= lig_attach
.rows
;
1148 if (unlikely (!comp_count
)) return TRACE_RETURN (false);
1150 /* We must now check whether the ligature ID of the current mark glyph
1151 * is identical to the ligature ID of the found ligature. If yes, we
1152 * can directly use the component index. If not, we attach the mark
1153 * glyph to the last component of the ligature. */
1154 unsigned int comp_index
;
1155 unsigned int lig_id
= get_lig_id (c
->buffer
->info
[j
]);
1156 unsigned int mark_id
= get_lig_id (c
->buffer
->cur());
1157 unsigned int mark_comp
= get_lig_comp (c
->buffer
->cur());
1158 if (lig_id
&& lig_id
== mark_id
&& mark_comp
> 0)
1159 comp_index
= MIN (comp_count
, get_lig_comp (c
->buffer
->cur())) - 1;
1161 comp_index
= comp_count
- 1;
1163 return TRACE_RETURN ((this+markArray
).apply (c
, mark_index
, comp_index
, lig_attach
, classCount
, j
));
1166 inline bool sanitize (hb_sanitize_context_t
*c
) {
1167 TRACE_SANITIZE (this);
1168 return TRACE_RETURN (c
->check_struct (this) && markCoverage
.sanitize (c
, this) && ligatureCoverage
.sanitize (c
, this) &&
1169 markArray
.sanitize (c
, this) && ligatureArray
.sanitize (c
, this, (unsigned int) classCount
));
1173 USHORT format
; /* Format identifier--format = 1 */
1175 markCoverage
; /* Offset to Mark Coverage table--from
1176 * beginning of MarkLigPos subtable */
1178 ligatureCoverage
; /* Offset to Ligature Coverage
1179 * table--from beginning of MarkLigPos
1181 USHORT classCount
; /* Number of defined mark classes */
1183 markArray
; /* Offset to MarkArray table--from
1184 * beginning of MarkLigPos subtable */
1185 OffsetTo
<LigatureArray
>
1186 ligatureArray
; /* Offset to LigatureArray table--from
1187 * beginning of MarkLigPos subtable */
1189 DEFINE_SIZE_STATIC (12);
1194 template <typename context_t
>
1195 inline typename
context_t::return_t
dispatch (context_t
*c
) const
1197 TRACE_DISPATCH (this);
1199 case 1: return TRACE_RETURN (c
->dispatch (u
.format1
));
1200 default:return TRACE_RETURN (c
->default_return_value ());
1204 inline bool sanitize (hb_sanitize_context_t
*c
) {
1205 TRACE_SANITIZE (this);
1206 if (!u
.format
.sanitize (c
)) return TRACE_RETURN (false);
1208 case 1: return TRACE_RETURN (u
.format1
.sanitize (c
));
1209 default:return TRACE_RETURN (true);
1215 USHORT format
; /* Format identifier */
1216 MarkLigPosFormat1 format1
;
1221 typedef AnchorMatrix Mark2Array
; /* mark2-major--
1222 * in order of Mark2Coverage Index--,
1224 * ordered by class--zero-based. */
1226 struct MarkMarkPosFormat1
1228 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
1230 TRACE_COLLECT_GLYPHS (this);
1231 (this+mark1Coverage
).add_coverage (c
->input
);
1232 (this+mark2Coverage
).add_coverage (c
->input
);
1235 inline const Coverage
&get_coverage (void) const
1237 return this+mark1Coverage
;
1240 inline bool apply (hb_apply_context_t
*c
) const
1243 unsigned int mark1_index
= (this+mark1Coverage
).get_coverage (c
->buffer
->cur().codepoint
);
1244 if (likely (mark1_index
== NOT_COVERED
)) return TRACE_RETURN (false);
1246 /* now we search backwards for a suitable mark glyph until a non-mark glyph */
1247 hb_apply_context_t::skipping_backward_iterator_t
skippy_iter (c
, c
->buffer
->idx
, 1);
1248 skippy_iter
.set_lookup_props (c
->lookup_props
& ~LookupFlag::IgnoreFlags
);
1249 if (!skippy_iter
.prev ()) return TRACE_RETURN (false);
1251 if (!(c
->buffer
->info
[skippy_iter
.idx
].glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK
)) { return TRACE_RETURN (false); }
1253 unsigned int j
= skippy_iter
.idx
;
1255 unsigned int id1
= get_lig_id (c
->buffer
->cur());
1256 unsigned int id2
= get_lig_id (c
->buffer
->info
[j
]);
1257 unsigned int comp1
= get_lig_comp (c
->buffer
->cur());
1258 unsigned int comp2
= get_lig_comp (c
->buffer
->info
[j
]);
1260 if (likely (id1
== id2
)) {
1261 if (id1
== 0) /* Marks belonging to the same base. */
1263 else if (comp1
== comp2
) /* Marks belonging to the same ligature component. */
1266 /* If ligature ids don't match, it may be the case that one of the marks
1267 * itself is a ligature. In which case match. */
1268 if ((id1
> 0 && !comp1
) || (id2
> 0 && !comp2
))
1273 return TRACE_RETURN (false);
1276 unsigned int mark2_index
= (this+mark2Coverage
).get_coverage (c
->buffer
->info
[j
].codepoint
);
1277 if (mark2_index
== NOT_COVERED
) return TRACE_RETURN (false);
1279 return TRACE_RETURN ((this+mark1Array
).apply (c
, mark1_index
, mark2_index
, this+mark2Array
, classCount
, j
));
1282 inline bool sanitize (hb_sanitize_context_t
*c
) {
1283 TRACE_SANITIZE (this);
1284 return TRACE_RETURN (c
->check_struct (this) && mark1Coverage
.sanitize (c
, this) &&
1285 mark2Coverage
.sanitize (c
, this) && mark1Array
.sanitize (c
, this)
1286 && mark2Array
.sanitize (c
, this, (unsigned int) classCount
));
1290 USHORT format
; /* Format identifier--format = 1 */
1292 mark1Coverage
; /* Offset to Combining Mark1 Coverage
1293 * table--from beginning of MarkMarkPos
1296 mark2Coverage
; /* Offset to Combining Mark2 Coverage
1297 * table--from beginning of MarkMarkPos
1299 USHORT classCount
; /* Number of defined mark classes */
1301 mark1Array
; /* Offset to Mark1Array table--from
1302 * beginning of MarkMarkPos subtable */
1303 OffsetTo
<Mark2Array
>
1304 mark2Array
; /* Offset to Mark2Array table--from
1305 * beginning of MarkMarkPos subtable */
1307 DEFINE_SIZE_STATIC (12);
1312 template <typename context_t
>
1313 inline typename
context_t::return_t
dispatch (context_t
*c
) const
1315 TRACE_DISPATCH (this);
1317 case 1: return TRACE_RETURN (c
->dispatch (u
.format1
));
1318 default:return TRACE_RETURN (c
->default_return_value ());
1322 inline bool sanitize (hb_sanitize_context_t
*c
) {
1323 TRACE_SANITIZE (this);
1324 if (!u
.format
.sanitize (c
)) return TRACE_RETURN (false);
1326 case 1: return TRACE_RETURN (u
.format1
.sanitize (c
));
1327 default:return TRACE_RETURN (true);
1333 USHORT format
; /* Format identifier */
1334 MarkMarkPosFormat1 format1
;
1339 struct ContextPos
: Context
{};
1341 struct ChainContextPos
: ChainContext
{};
1343 struct ExtensionPos
: Extension
<ExtensionPos
>
1345 typedef struct PosLookupSubTable LookupSubTable
;
1355 struct PosLookupSubTable
1357 friend struct PosLookup
;
1371 template <typename context_t
>
1372 inline typename
context_t::return_t
dispatch (context_t
*c
, unsigned int lookup_type
) const
1374 TRACE_DISPATCH (this);
1375 switch (lookup_type
) {
1376 case Single
: return TRACE_RETURN (u
.single
.dispatch (c
));
1377 case Pair
: return TRACE_RETURN (u
.pair
.dispatch (c
));
1378 case Cursive
: return TRACE_RETURN (u
.cursive
.dispatch (c
));
1379 case MarkBase
: return TRACE_RETURN (u
.markBase
.dispatch (c
));
1380 case MarkLig
: return TRACE_RETURN (u
.markLig
.dispatch (c
));
1381 case MarkMark
: return TRACE_RETURN (u
.markMark
.dispatch (c
));
1382 case Context
: return TRACE_RETURN (u
.context
.dispatch (c
));
1383 case ChainContext
: return TRACE_RETURN (u
.chainContext
.dispatch (c
));
1384 case Extension
: return TRACE_RETURN (u
.extension
.dispatch (c
));
1385 default: return TRACE_RETURN (c
->default_return_value ());
1389 inline bool sanitize (hb_sanitize_context_t
*c
, unsigned int lookup_type
) {
1390 TRACE_SANITIZE (this);
1391 if (!u
.header
.sub_format
.sanitize (c
))
1392 return TRACE_RETURN (false);
1393 switch (lookup_type
) {
1394 case Single
: return TRACE_RETURN (u
.single
.sanitize (c
));
1395 case Pair
: return TRACE_RETURN (u
.pair
.sanitize (c
));
1396 case Cursive
: return TRACE_RETURN (u
.cursive
.sanitize (c
));
1397 case MarkBase
: return TRACE_RETURN (u
.markBase
.sanitize (c
));
1398 case MarkLig
: return TRACE_RETURN (u
.markLig
.sanitize (c
));
1399 case MarkMark
: return TRACE_RETURN (u
.markMark
.sanitize (c
));
1400 case Context
: return TRACE_RETURN (u
.context
.sanitize (c
));
1401 case ChainContext
: return TRACE_RETURN (u
.chainContext
.sanitize (c
));
1402 case Extension
: return TRACE_RETURN (u
.extension
.sanitize (c
));
1403 default: return TRACE_RETURN (true);
1415 MarkBasePos markBase
;
1417 MarkMarkPos markMark
;
1419 ChainContextPos chainContext
;
1420 ExtensionPos extension
;
1423 DEFINE_SIZE_UNION (2, header
.sub_format
);
1427 struct PosLookup
: Lookup
1429 inline const PosLookupSubTable
& get_subtable (unsigned int i
) const
1430 { return this+CastR
<OffsetArrayOf
<PosLookupSubTable
> > (subTable
)[i
]; }
1432 inline hb_collect_glyphs_context_t::return_t
collect_glyphs_lookup (hb_collect_glyphs_context_t
*c
) const
1434 TRACE_COLLECT_GLYPHS (this);
1435 c
->set_recurse_func (NULL
);
1436 return TRACE_RETURN (dispatch (c
));
1439 template <typename set_t
>
1440 inline void add_coverage (set_t
*glyphs
) const
1442 hb_get_coverage_context_t c
;
1443 const Coverage
*last
= NULL
;
1444 unsigned int count
= get_subtable_count ();
1445 for (unsigned int i
= 0; i
< count
; i
++) {
1446 const Coverage
*coverage
= &get_subtable (i
).dispatch (&c
, get_type ());
1447 if (coverage
!= last
) {
1448 coverage
->add_coverage (glyphs
);
1454 inline bool apply_once (hb_apply_context_t
*c
) const
1457 if (!c
->check_glyph_property (&c
->buffer
->cur(), c
->lookup_props
))
1458 return TRACE_RETURN (false);
1459 return TRACE_RETURN (dispatch (c
));
1462 static bool apply_recurse_func (hb_apply_context_t
*c
, unsigned int lookup_index
);
1464 inline bool apply_string (hb_apply_context_t
*c
, const hb_set_digest_t
*digest
) const
1468 if (unlikely (!c
->buffer
->len
|| !c
->lookup_mask
))
1471 c
->set_recurse_func (apply_recurse_func
);
1472 c
->set_lookup (*this);
1476 while (c
->buffer
->idx
< c
->buffer
->len
)
1478 if (digest
->may_have (c
->buffer
->cur().codepoint
) &&
1479 (c
->buffer
->cur().mask
& c
->lookup_mask
) &&
1489 template <typename context_t
>
1490 static inline typename
context_t::return_t
dispatch_recurse_func (context_t
*c
, unsigned int lookup_index
);
1492 template <typename context_t
>
1493 inline typename
context_t::return_t
dispatch (context_t
*c
) const
1495 TRACE_DISPATCH (this);
1496 unsigned int lookup_type
= get_type ();
1497 unsigned int count
= get_subtable_count ();
1498 for (unsigned int i
= 0; i
< count
; i
++) {
1499 typename
context_t::return_t r
= get_subtable (i
).dispatch (c
, lookup_type
);
1500 if (c
->stop_sublookup_iteration (r
))
1501 return TRACE_RETURN (r
);
1503 return TRACE_RETURN (c
->default_return_value ());
1506 inline bool sanitize (hb_sanitize_context_t
*c
) {
1507 TRACE_SANITIZE (this);
1508 if (unlikely (!Lookup::sanitize (c
))) return TRACE_RETURN (false);
1509 OffsetArrayOf
<PosLookupSubTable
> &list
= CastR
<OffsetArrayOf
<PosLookupSubTable
> > (subTable
);
1510 return TRACE_RETURN (list
.sanitize (c
, this, get_type ()));
1514 typedef OffsetListOf
<PosLookup
> PosLookupList
;
1517 * GPOS -- The Glyph Positioning Table
1520 struct GPOS
: GSUBGPOS
1522 static const hb_tag_t Tag
= HB_OT_TAG_GPOS
;
1524 inline const PosLookup
& get_lookup (unsigned int i
) const
1525 { return CastR
<PosLookup
> (GSUBGPOS::get_lookup (i
)); }
1527 static inline void position_start (hb_font_t
*font
, hb_buffer_t
*buffer
);
1528 static inline void position_finish (hb_font_t
*font
, hb_buffer_t
*buffer
);
1530 inline bool sanitize (hb_sanitize_context_t
*c
) {
1531 TRACE_SANITIZE (this);
1532 if (unlikely (!GSUBGPOS::sanitize (c
))) return TRACE_RETURN (false);
1533 OffsetTo
<PosLookupList
> &list
= CastR
<OffsetTo
<PosLookupList
> > (lookupList
);
1534 return TRACE_RETURN (list
.sanitize (c
, this));
1537 DEFINE_SIZE_STATIC (10);
1542 fix_cursive_minor_offset (hb_glyph_position_t
*pos
, unsigned int i
, hb_direction_t direction
)
1544 unsigned int j
= pos
[i
].cursive_chain();
1550 pos
[i
].cursive_chain() = 0;
1552 fix_cursive_minor_offset (pos
, j
, direction
);
1554 if (HB_DIRECTION_IS_HORIZONTAL (direction
))
1555 pos
[i
].y_offset
+= pos
[j
].y_offset
;
1557 pos
[i
].x_offset
+= pos
[j
].x_offset
;
1561 fix_mark_attachment (hb_glyph_position_t
*pos
, unsigned int i
, hb_direction_t direction
)
1563 if (likely (!(pos
[i
].attach_lookback())))
1566 unsigned int j
= i
- pos
[i
].attach_lookback();
1568 pos
[i
].x_offset
+= pos
[j
].x_offset
;
1569 pos
[i
].y_offset
+= pos
[j
].y_offset
;
1571 if (HB_DIRECTION_IS_FORWARD (direction
))
1572 for (unsigned int k
= j
; k
< i
; k
++) {
1573 pos
[i
].x_offset
-= pos
[k
].x_advance
;
1574 pos
[i
].y_offset
-= pos
[k
].y_advance
;
1577 for (unsigned int k
= j
+ 1; k
< i
+ 1; k
++) {
1578 pos
[i
].x_offset
+= pos
[k
].x_advance
;
1579 pos
[i
].y_offset
+= pos
[k
].y_advance
;
1584 GPOS::position_start (hb_font_t
*font HB_UNUSED
, hb_buffer_t
*buffer
)
1586 buffer
->clear_positions ();
1588 unsigned int count
= buffer
->len
;
1589 for (unsigned int i
= 0; i
< count
; i
++)
1590 buffer
->pos
[i
].attach_lookback() = buffer
->pos
[i
].cursive_chain() = 0;
1594 GPOS::position_finish (hb_font_t
*font HB_UNUSED
, hb_buffer_t
*buffer
)
1597 hb_glyph_position_t
*pos
= hb_buffer_get_glyph_positions (buffer
, &len
);
1598 hb_direction_t direction
= buffer
->props
.direction
;
1600 /* Handle cursive connections */
1601 for (unsigned int i
= 0; i
< len
; i
++)
1602 fix_cursive_minor_offset (pos
, i
, direction
);
1604 /* Handle attachments */
1605 for (unsigned int i
= 0; i
< len
; i
++)
1606 fix_mark_attachment (pos
, i
, direction
);
1608 HB_BUFFER_DEALLOCATE_VAR (buffer
, syllable
);
1609 HB_BUFFER_DEALLOCATE_VAR (buffer
, lig_props
);
1610 HB_BUFFER_DEALLOCATE_VAR (buffer
, glyph_props
);
1614 /* Out-of-class implementation for methods recursing */
1616 template <typename context_t
>
1617 inline typename
context_t::return_t
PosLookup::dispatch_recurse_func (context_t
*c
, unsigned int lookup_index
)
1619 const GPOS
&gpos
= *(hb_ot_layout_from_face (c
->face
)->gpos
);
1620 const PosLookup
&l
= gpos
.get_lookup (lookup_index
);
1621 return l
.dispatch (c
);
1624 inline bool PosLookup::apply_recurse_func (hb_apply_context_t
*c
, unsigned int lookup_index
)
1626 const GPOS
&gpos
= *(hb_ot_layout_from_face (c
->face
)->gpos
);
1627 const PosLookup
&l
= gpos
.get_lookup (lookup_index
);
1628 unsigned int saved_lookup_props
= c
->lookup_props
;
1630 bool ret
= l
.apply_once (c
);
1631 c
->lookup_props
= saved_lookup_props
;
1636 #undef attach_lookback
1637 #undef cursive_chain
1640 } /* namespace OT */
1643 #endif /* HB_OT_LAYOUT_GPOS_TABLE_HH */