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_GSUB_TABLE_HH
30 #define HB_OT_LAYOUT_GSUB_TABLE_HH
32 #include "hb-ot-layout-gsubgpos-private.hh"
38 struct SingleSubstFormat1
40 inline void closure (hb_closure_context_t
*c
) const
44 for (iter
.init (this+coverage
); iter
.more (); iter
.next ()) {
45 hb_codepoint_t glyph_id
= iter
.get_glyph ();
46 if (c
->glyphs
->has (glyph_id
))
47 c
->glyphs
->add ((glyph_id
+ deltaGlyphID
) & 0xFFFF);
51 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
53 TRACE_COLLECT_GLYPHS (this);
55 for (iter
.init (this+coverage
); iter
.more (); iter
.next ()) {
56 hb_codepoint_t glyph_id
= iter
.get_glyph ();
57 c
->input
->add (glyph_id
);
58 c
->output
->add ((glyph_id
+ deltaGlyphID
) & 0xFFFF);
62 inline const Coverage
&get_coverage (void) const
67 inline bool would_apply (hb_would_apply_context_t
*c
) const
69 TRACE_WOULD_APPLY (this);
70 return TRACE_RETURN (c
->len
== 1 && (this+coverage
).get_coverage (c
->glyphs
[0]) != NOT_COVERED
);
73 inline bool apply (hb_apply_context_t
*c
) const
76 hb_codepoint_t glyph_id
= c
->buffer
->cur().codepoint
;
77 unsigned int index
= (this+coverage
).get_coverage (glyph_id
);
78 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
80 /* According to the Adobe Annotated OpenType Suite, result is always
81 * limited to 16bit. */
82 glyph_id
= (glyph_id
+ deltaGlyphID
) & 0xFFFF;
83 c
->replace_glyph (glyph_id
);
85 return TRACE_RETURN (true);
88 inline bool serialize (hb_serialize_context_t
*c
,
89 Supplier
<GlyphID
> &glyphs
,
90 unsigned int num_glyphs
,
93 TRACE_SERIALIZE (this);
94 if (unlikely (!c
->extend_min (*this))) return TRACE_RETURN (false);
95 if (unlikely (!coverage
.serialize (c
, this).serialize (c
, glyphs
, num_glyphs
))) return TRACE_RETURN (false);
96 deltaGlyphID
.set (delta
); /* TODO(serilaize) overflow? */
97 return TRACE_RETURN (true);
100 inline bool sanitize (hb_sanitize_context_t
*c
) {
101 TRACE_SANITIZE (this);
102 return TRACE_RETURN (coverage
.sanitize (c
, this) && deltaGlyphID
.sanitize (c
));
106 USHORT format
; /* Format identifier--format = 1 */
108 coverage
; /* Offset to Coverage table--from
109 * beginning of Substitution table */
110 SHORT deltaGlyphID
; /* Add to original GlyphID to get
111 * substitute GlyphID */
113 DEFINE_SIZE_STATIC (6);
116 struct SingleSubstFormat2
118 inline void closure (hb_closure_context_t
*c
) const
120 TRACE_CLOSURE (this);
122 for (iter
.init (this+coverage
); iter
.more (); iter
.next ()) {
123 if (c
->glyphs
->has (iter
.get_glyph ()))
124 c
->glyphs
->add (substitute
[iter
.get_coverage ()]);
128 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
130 TRACE_COLLECT_GLYPHS (this);
132 for (iter
.init (this+coverage
); iter
.more (); iter
.next ()) {
133 c
->input
->add (iter
.get_glyph ());
134 c
->output
->add (substitute
[iter
.get_coverage ()]);
138 inline const Coverage
&get_coverage (void) const
140 return this+coverage
;
143 inline bool would_apply (hb_would_apply_context_t
*c
) const
145 TRACE_WOULD_APPLY (this);
146 return TRACE_RETURN (c
->len
== 1 && (this+coverage
).get_coverage (c
->glyphs
[0]) != NOT_COVERED
);
149 inline bool apply (hb_apply_context_t
*c
) const
152 hb_codepoint_t glyph_id
= c
->buffer
->cur().codepoint
;
153 unsigned int index
= (this+coverage
).get_coverage (glyph_id
);
154 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
156 if (unlikely (index
>= substitute
.len
)) return TRACE_RETURN (false);
158 glyph_id
= substitute
[index
];
159 c
->replace_glyph (glyph_id
);
161 return TRACE_RETURN (true);
164 inline bool serialize (hb_serialize_context_t
*c
,
165 Supplier
<GlyphID
> &glyphs
,
166 Supplier
<GlyphID
> &substitutes
,
167 unsigned int num_glyphs
)
169 TRACE_SERIALIZE (this);
170 if (unlikely (!c
->extend_min (*this))) return TRACE_RETURN (false);
171 if (unlikely (!substitute
.serialize (c
, substitutes
, num_glyphs
))) return TRACE_RETURN (false);
172 if (unlikely (!coverage
.serialize (c
, this).serialize (c
, glyphs
, num_glyphs
))) return TRACE_RETURN (false);
173 return TRACE_RETURN (true);
176 inline bool sanitize (hb_sanitize_context_t
*c
) {
177 TRACE_SANITIZE (this);
178 return TRACE_RETURN (coverage
.sanitize (c
, this) && substitute
.sanitize (c
));
182 USHORT format
; /* Format identifier--format = 2 */
184 coverage
; /* Offset to Coverage table--from
185 * beginning of Substitution table */
187 substitute
; /* Array of substitute
188 * GlyphIDs--ordered by Coverage Index */
190 DEFINE_SIZE_ARRAY (6, substitute
);
195 inline bool serialize (hb_serialize_context_t
*c
,
196 Supplier
<GlyphID
> &glyphs
,
197 Supplier
<GlyphID
> &substitutes
,
198 unsigned int num_glyphs
)
200 TRACE_SERIALIZE (this);
201 if (unlikely (!c
->extend_min (u
.format
))) return TRACE_RETURN (false);
202 unsigned int format
= 2;
206 /* TODO(serialize) check for wrap-around */
207 delta
= substitutes
[0] - glyphs
[0];
208 for (unsigned int i
= 1; i
< num_glyphs
; i
++)
209 if (delta
!= substitutes
[i
] - glyphs
[i
]) {
214 u
.format
.set (format
);
216 case 1: return TRACE_RETURN (u
.format1
.serialize (c
, glyphs
, num_glyphs
, delta
));
217 case 2: return TRACE_RETURN (u
.format2
.serialize (c
, glyphs
, substitutes
, num_glyphs
));
218 default:return TRACE_RETURN (false);
222 template <typename context_t
>
223 inline typename
context_t::return_t
dispatch (context_t
*c
) const
225 TRACE_DISPATCH (this);
227 case 1: return TRACE_RETURN (c
->dispatch (u
.format1
));
228 case 2: return TRACE_RETURN (c
->dispatch (u
.format2
));
229 default:return TRACE_RETURN (c
->default_return_value ());
233 inline bool sanitize (hb_sanitize_context_t
*c
) {
234 TRACE_SANITIZE (this);
235 if (!u
.format
.sanitize (c
)) return TRACE_RETURN (false);
237 case 1: return TRACE_RETURN (u
.format1
.sanitize (c
));
238 case 2: return TRACE_RETURN (u
.format2
.sanitize (c
));
239 default:return TRACE_RETURN (true);
245 USHORT format
; /* Format identifier */
246 SingleSubstFormat1 format1
;
247 SingleSubstFormat2 format2
;
254 inline void closure (hb_closure_context_t
*c
) const
256 TRACE_CLOSURE (this);
257 unsigned int count
= substitute
.len
;
258 for (unsigned int i
= 0; i
< count
; i
++)
259 c
->glyphs
->add (substitute
[i
]);
262 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
264 TRACE_COLLECT_GLYPHS (this);
265 unsigned int count
= substitute
.len
;
266 for (unsigned int i
= 0; i
< count
; i
++)
267 c
->output
->add (substitute
[i
]);
270 inline bool apply (hb_apply_context_t
*c
) const
273 if (unlikely (!substitute
.len
)) return TRACE_RETURN (false);
275 unsigned int klass
= _hb_glyph_info_is_ligature (&c
->buffer
->cur()) ?
276 HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH
: 0;
277 unsigned int count
= substitute
.len
;
278 if (count
== 1) /* Special-case to make it in-place. */
280 c
->replace_glyph (substitute
.array
[0]);
284 for (unsigned int i
= 0; i
< count
; i
++) {
285 _hb_glyph_info_set_lig_props_for_component (&c
->buffer
->cur(), i
);
286 c
->output_glyph (substitute
.array
[i
], klass
);
288 c
->buffer
->skip_glyph ();
291 return TRACE_RETURN (true);
294 inline bool serialize (hb_serialize_context_t
*c
,
295 Supplier
<GlyphID
> &glyphs
,
296 unsigned int num_glyphs
)
298 TRACE_SERIALIZE (this);
299 if (unlikely (!c
->extend_min (*this))) return TRACE_RETURN (false);
300 if (unlikely (!substitute
.serialize (c
, glyphs
, num_glyphs
))) return TRACE_RETURN (false);
301 return TRACE_RETURN (true);
304 inline bool sanitize (hb_sanitize_context_t
*c
) {
305 TRACE_SANITIZE (this);
306 return TRACE_RETURN (substitute
.sanitize (c
));
311 substitute
; /* String of GlyphIDs to substitute */
313 DEFINE_SIZE_ARRAY (2, substitute
);
316 struct MultipleSubstFormat1
318 inline void closure (hb_closure_context_t
*c
) const
320 TRACE_CLOSURE (this);
322 for (iter
.init (this+coverage
); iter
.more (); iter
.next ()) {
323 if (c
->glyphs
->has (iter
.get_glyph ()))
324 (this+sequence
[iter
.get_coverage ()]).closure (c
);
328 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
330 TRACE_COLLECT_GLYPHS (this);
331 (this+coverage
).add_coverage (c
->input
);
332 unsigned int count
= sequence
.len
;
333 for (unsigned int i
= 0; i
< count
; i
++)
334 (this+sequence
[i
]).collect_glyphs (c
);
337 inline const Coverage
&get_coverage (void) const
339 return this+coverage
;
342 inline bool would_apply (hb_would_apply_context_t
*c
) const
344 TRACE_WOULD_APPLY (this);
345 return TRACE_RETURN (c
->len
== 1 && (this+coverage
).get_coverage (c
->glyphs
[0]) != NOT_COVERED
);
348 inline bool apply (hb_apply_context_t
*c
) const
352 unsigned int index
= (this+coverage
).get_coverage (c
->buffer
->cur().codepoint
);
353 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
355 return TRACE_RETURN ((this+sequence
[index
]).apply (c
));
358 inline bool serialize (hb_serialize_context_t
*c
,
359 Supplier
<GlyphID
> &glyphs
,
360 Supplier
<unsigned int> &substitute_len_list
,
361 unsigned int num_glyphs
,
362 Supplier
<GlyphID
> &substitute_glyphs_list
)
364 TRACE_SERIALIZE (this);
365 if (unlikely (!c
->extend_min (*this))) return TRACE_RETURN (false);
366 if (unlikely (!sequence
.serialize (c
, num_glyphs
))) return TRACE_RETURN (false);
367 for (unsigned int i
= 0; i
< num_glyphs
; i
++)
368 if (unlikely (!sequence
[i
].serialize (c
, this).serialize (c
,
369 substitute_glyphs_list
,
370 substitute_len_list
[i
]))) return TRACE_RETURN (false);
371 substitute_len_list
.advance (num_glyphs
);
372 if (unlikely (!coverage
.serialize (c
, this).serialize (c
, glyphs
, num_glyphs
))) return TRACE_RETURN (false);
373 return TRACE_RETURN (true);
376 inline bool sanitize (hb_sanitize_context_t
*c
) {
377 TRACE_SANITIZE (this);
378 return TRACE_RETURN (coverage
.sanitize (c
, this) && sequence
.sanitize (c
, this));
382 USHORT format
; /* Format identifier--format = 1 */
384 coverage
; /* Offset to Coverage table--from
385 * beginning of Substitution table */
386 OffsetArrayOf
<Sequence
>
387 sequence
; /* Array of Sequence tables
388 * ordered by Coverage Index */
390 DEFINE_SIZE_ARRAY (6, sequence
);
395 inline bool serialize (hb_serialize_context_t
*c
,
396 Supplier
<GlyphID
> &glyphs
,
397 Supplier
<unsigned int> &substitute_len_list
,
398 unsigned int num_glyphs
,
399 Supplier
<GlyphID
> &substitute_glyphs_list
)
401 TRACE_SERIALIZE (this);
402 if (unlikely (!c
->extend_min (u
.format
))) return TRACE_RETURN (false);
403 unsigned int format
= 1;
404 u
.format
.set (format
);
406 case 1: return TRACE_RETURN (u
.format1
.serialize (c
, glyphs
, substitute_len_list
, num_glyphs
, substitute_glyphs_list
));
407 default:return TRACE_RETURN (false);
411 template <typename context_t
>
412 inline typename
context_t::return_t
dispatch (context_t
*c
) const
414 TRACE_DISPATCH (this);
416 case 1: return TRACE_RETURN (c
->dispatch (u
.format1
));
417 default:return TRACE_RETURN (c
->default_return_value ());
421 inline bool sanitize (hb_sanitize_context_t
*c
) {
422 TRACE_SANITIZE (this);
423 if (!u
.format
.sanitize (c
)) return TRACE_RETURN (false);
425 case 1: return TRACE_RETURN (u
.format1
.sanitize (c
));
426 default:return TRACE_RETURN (true);
432 USHORT format
; /* Format identifier */
433 MultipleSubstFormat1 format1
;
438 typedef ArrayOf
<GlyphID
> AlternateSet
; /* Array of alternate GlyphIDs--in
441 struct AlternateSubstFormat1
443 inline void closure (hb_closure_context_t
*c
) const
445 TRACE_CLOSURE (this);
447 for (iter
.init (this+coverage
); iter
.more (); iter
.next ()) {
448 if (c
->glyphs
->has (iter
.get_glyph ())) {
449 const AlternateSet
&alt_set
= this+alternateSet
[iter
.get_coverage ()];
450 unsigned int count
= alt_set
.len
;
451 for (unsigned int i
= 0; i
< count
; i
++)
452 c
->glyphs
->add (alt_set
[i
]);
457 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
459 TRACE_COLLECT_GLYPHS (this);
461 for (iter
.init (this+coverage
); iter
.more (); iter
.next ()) {
462 c
->input
->add (iter
.get_glyph ());
463 const AlternateSet
&alt_set
= this+alternateSet
[iter
.get_coverage ()];
464 unsigned int count
= alt_set
.len
;
465 for (unsigned int i
= 0; i
< count
; i
++)
466 c
->output
->add (alt_set
[i
]);
470 inline const Coverage
&get_coverage (void) const
472 return this+coverage
;
475 inline bool would_apply (hb_would_apply_context_t
*c
) const
477 TRACE_WOULD_APPLY (this);
478 return TRACE_RETURN (c
->len
== 1 && (this+coverage
).get_coverage (c
->glyphs
[0]) != NOT_COVERED
);
481 inline bool apply (hb_apply_context_t
*c
) const
484 hb_codepoint_t glyph_id
= c
->buffer
->cur().codepoint
;
486 unsigned int index
= (this+coverage
).get_coverage (glyph_id
);
487 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
489 const AlternateSet
&alt_set
= this+alternateSet
[index
];
491 if (unlikely (!alt_set
.len
)) return TRACE_RETURN (false);
493 hb_mask_t glyph_mask
= c
->buffer
->cur().mask
;
494 hb_mask_t lookup_mask
= c
->lookup_mask
;
496 /* Note: This breaks badly if two features enabled this lookup together. */
497 unsigned int shift
= _hb_ctz (lookup_mask
);
498 unsigned int alt_index
= ((lookup_mask
& glyph_mask
) >> shift
);
500 if (unlikely (alt_index
> alt_set
.len
|| alt_index
== 0)) return TRACE_RETURN (false);
502 glyph_id
= alt_set
[alt_index
- 1];
504 c
->replace_glyph (glyph_id
);
506 return TRACE_RETURN (true);
509 inline bool serialize (hb_serialize_context_t
*c
,
510 Supplier
<GlyphID
> &glyphs
,
511 Supplier
<unsigned int> &alternate_len_list
,
512 unsigned int num_glyphs
,
513 Supplier
<GlyphID
> &alternate_glyphs_list
)
515 TRACE_SERIALIZE (this);
516 if (unlikely (!c
->extend_min (*this))) return TRACE_RETURN (false);
517 if (unlikely (!alternateSet
.serialize (c
, num_glyphs
))) return TRACE_RETURN (false);
518 for (unsigned int i
= 0; i
< num_glyphs
; i
++)
519 if (unlikely (!alternateSet
[i
].serialize (c
, this).serialize (c
,
520 alternate_glyphs_list
,
521 alternate_len_list
[i
]))) return TRACE_RETURN (false);
522 alternate_len_list
.advance (num_glyphs
);
523 if (unlikely (!coverage
.serialize (c
, this).serialize (c
, glyphs
, num_glyphs
))) return TRACE_RETURN (false);
524 return TRACE_RETURN (true);
527 inline bool sanitize (hb_sanitize_context_t
*c
) {
528 TRACE_SANITIZE (this);
529 return TRACE_RETURN (coverage
.sanitize (c
, this) && alternateSet
.sanitize (c
, this));
533 USHORT format
; /* Format identifier--format = 1 */
535 coverage
; /* Offset to Coverage table--from
536 * beginning of Substitution table */
537 OffsetArrayOf
<AlternateSet
>
538 alternateSet
; /* Array of AlternateSet tables
539 * ordered by Coverage Index */
541 DEFINE_SIZE_ARRAY (6, alternateSet
);
544 struct AlternateSubst
546 inline bool serialize (hb_serialize_context_t
*c
,
547 Supplier
<GlyphID
> &glyphs
,
548 Supplier
<unsigned int> &alternate_len_list
,
549 unsigned int num_glyphs
,
550 Supplier
<GlyphID
> &alternate_glyphs_list
)
552 TRACE_SERIALIZE (this);
553 if (unlikely (!c
->extend_min (u
.format
))) return TRACE_RETURN (false);
554 unsigned int format
= 1;
555 u
.format
.set (format
);
557 case 1: return TRACE_RETURN (u
.format1
.serialize (c
, glyphs
, alternate_len_list
, num_glyphs
, alternate_glyphs_list
));
558 default:return TRACE_RETURN (false);
562 template <typename context_t
>
563 inline typename
context_t::return_t
dispatch (context_t
*c
) const
565 TRACE_DISPATCH (this);
567 case 1: return TRACE_RETURN (c
->dispatch (u
.format1
));
568 default:return TRACE_RETURN (c
->default_return_value ());
572 inline bool sanitize (hb_sanitize_context_t
*c
) {
573 TRACE_SANITIZE (this);
574 if (!u
.format
.sanitize (c
)) return TRACE_RETURN (false);
576 case 1: return TRACE_RETURN (u
.format1
.sanitize (c
));
577 default:return TRACE_RETURN (true);
583 USHORT format
; /* Format identifier */
584 AlternateSubstFormat1 format1
;
591 inline void closure (hb_closure_context_t
*c
) const
593 TRACE_CLOSURE (this);
594 unsigned int count
= component
.len
;
595 for (unsigned int i
= 1; i
< count
; i
++)
596 if (!c
->glyphs
->has (component
[i
]))
598 c
->glyphs
->add (ligGlyph
);
601 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
603 TRACE_COLLECT_GLYPHS (this);
604 unsigned int count
= component
.len
;
605 for (unsigned int i
= 1; i
< count
; i
++)
606 c
->input
->add (component
[i
]);
607 c
->output
->add (ligGlyph
);
610 inline bool would_apply (hb_would_apply_context_t
*c
) const
612 TRACE_WOULD_APPLY (this);
613 if (c
->len
!= component
.len
)
614 return TRACE_RETURN (false);
616 for (unsigned int i
= 1; i
< c
->len
; i
++)
617 if (likely (c
->glyphs
[i
] != component
[i
]))
618 return TRACE_RETURN (false);
620 return TRACE_RETURN (true);
623 inline bool apply (hb_apply_context_t
*c
) const
626 unsigned int count
= component
.len
;
627 if (unlikely (count
< 1)) return TRACE_RETURN (false);
629 bool is_mark_ligature
= false;
630 unsigned int total_component_count
= 0;
632 unsigned int match_length
= 0;
633 unsigned int match_positions
[MAX_CONTEXT_LENGTH
];
635 if (likely (!match_input (c
, count
,
642 &total_component_count
)))
643 return TRACE_RETURN (false);
651 total_component_count
);
653 return TRACE_RETURN (true);
656 inline bool serialize (hb_serialize_context_t
*c
,
658 Supplier
<GlyphID
> &components
, /* Starting from second */
659 unsigned int num_components
/* Including first component */)
661 TRACE_SERIALIZE (this);
662 if (unlikely (!c
->extend_min (*this))) return TRACE_RETURN (false);
664 if (unlikely (!component
.serialize (c
, components
, num_components
))) return TRACE_RETURN (false);
665 return TRACE_RETURN (true);
669 inline bool sanitize (hb_sanitize_context_t
*c
) {
670 TRACE_SANITIZE (this);
671 return TRACE_RETURN (ligGlyph
.sanitize (c
) && component
.sanitize (c
));
675 GlyphID ligGlyph
; /* GlyphID of ligature to substitute */
676 HeadlessArrayOf
<GlyphID
>
677 component
; /* Array of component GlyphIDs--start
678 * with the second component--ordered
679 * in writing direction */
681 DEFINE_SIZE_ARRAY (4, component
);
686 inline void closure (hb_closure_context_t
*c
) const
688 TRACE_CLOSURE (this);
689 unsigned int num_ligs
= ligature
.len
;
690 for (unsigned int i
= 0; i
< num_ligs
; i
++)
691 (this+ligature
[i
]).closure (c
);
694 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
696 TRACE_COLLECT_GLYPHS (this);
697 unsigned int num_ligs
= ligature
.len
;
698 for (unsigned int i
= 0; i
< num_ligs
; i
++)
699 (this+ligature
[i
]).collect_glyphs (c
);
702 inline bool would_apply (hb_would_apply_context_t
*c
) const
704 TRACE_WOULD_APPLY (this);
705 unsigned int num_ligs
= ligature
.len
;
706 for (unsigned int i
= 0; i
< num_ligs
; i
++)
708 const Ligature
&lig
= this+ligature
[i
];
709 if (lig
.would_apply (c
))
710 return TRACE_RETURN (true);
712 return TRACE_RETURN (false);
715 inline bool apply (hb_apply_context_t
*c
) const
718 unsigned int num_ligs
= ligature
.len
;
719 for (unsigned int i
= 0; i
< num_ligs
; i
++)
721 const Ligature
&lig
= this+ligature
[i
];
722 if (lig
.apply (c
)) return TRACE_RETURN (true);
725 return TRACE_RETURN (false);
728 inline bool serialize (hb_serialize_context_t
*c
,
729 Supplier
<GlyphID
> &ligatures
,
730 Supplier
<unsigned int> &component_count_list
,
731 unsigned int num_ligatures
,
732 Supplier
<GlyphID
> &component_list
/* Starting from second for each ligature */)
734 TRACE_SERIALIZE (this);
735 if (unlikely (!c
->extend_min (*this))) return TRACE_RETURN (false);
736 if (unlikely (!ligature
.serialize (c
, num_ligatures
))) return TRACE_RETURN (false);
737 for (unsigned int i
= 0; i
< num_ligatures
; i
++)
738 if (unlikely (!ligature
[i
].serialize (c
, this).serialize (c
,
741 component_count_list
[i
]))) return TRACE_RETURN (false);
742 ligatures
.advance (num_ligatures
);
743 component_count_list
.advance (num_ligatures
);
744 return TRACE_RETURN (true);
747 inline bool sanitize (hb_sanitize_context_t
*c
) {
748 TRACE_SANITIZE (this);
749 return TRACE_RETURN (ligature
.sanitize (c
, this));
753 OffsetArrayOf
<Ligature
>
754 ligature
; /* Array LigatureSet tables
755 * ordered by preference */
757 DEFINE_SIZE_ARRAY (2, ligature
);
760 struct LigatureSubstFormat1
762 inline void closure (hb_closure_context_t
*c
) const
764 TRACE_CLOSURE (this);
766 for (iter
.init (this+coverage
); iter
.more (); iter
.next ()) {
767 if (c
->glyphs
->has (iter
.get_glyph ()))
768 (this+ligatureSet
[iter
.get_coverage ()]).closure (c
);
772 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
774 TRACE_COLLECT_GLYPHS (this);
776 for (iter
.init (this+coverage
); iter
.more (); iter
.next ()) {
777 c
->input
->add (iter
.get_glyph ());
778 (this+ligatureSet
[iter
.get_coverage ()]).collect_glyphs (c
);
782 inline const Coverage
&get_coverage (void) const
784 return this+coverage
;
787 inline bool would_apply (hb_would_apply_context_t
*c
) const
789 TRACE_WOULD_APPLY (this);
790 unsigned int index
= (this+coverage
).get_coverage (c
->glyphs
[0]);
791 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
793 const LigatureSet
&lig_set
= this+ligatureSet
[index
];
794 return TRACE_RETURN (lig_set
.would_apply (c
));
797 inline bool apply (hb_apply_context_t
*c
) const
800 hb_codepoint_t glyph_id
= c
->buffer
->cur().codepoint
;
802 unsigned int index
= (this+coverage
).get_coverage (glyph_id
);
803 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
805 const LigatureSet
&lig_set
= this+ligatureSet
[index
];
806 return TRACE_RETURN (lig_set
.apply (c
));
809 inline bool serialize (hb_serialize_context_t
*c
,
810 Supplier
<GlyphID
> &first_glyphs
,
811 Supplier
<unsigned int> &ligature_per_first_glyph_count_list
,
812 unsigned int num_first_glyphs
,
813 Supplier
<GlyphID
> &ligatures_list
,
814 Supplier
<unsigned int> &component_count_list
,
815 Supplier
<GlyphID
> &component_list
/* Starting from second for each ligature */)
817 TRACE_SERIALIZE (this);
818 if (unlikely (!c
->extend_min (*this))) return TRACE_RETURN (false);
819 if (unlikely (!ligatureSet
.serialize (c
, num_first_glyphs
))) return TRACE_RETURN (false);
820 for (unsigned int i
= 0; i
< num_first_glyphs
; i
++)
821 if (unlikely (!ligatureSet
[i
].serialize (c
, this).serialize (c
,
823 component_count_list
,
824 ligature_per_first_glyph_count_list
[i
],
825 component_list
))) return TRACE_RETURN (false);
826 ligature_per_first_glyph_count_list
.advance (num_first_glyphs
);
827 if (unlikely (!coverage
.serialize (c
, this).serialize (c
, first_glyphs
, num_first_glyphs
))) return TRACE_RETURN (false);
828 return TRACE_RETURN (true);
831 inline bool sanitize (hb_sanitize_context_t
*c
) {
832 TRACE_SANITIZE (this);
833 return TRACE_RETURN (coverage
.sanitize (c
, this) && ligatureSet
.sanitize (c
, this));
837 USHORT format
; /* Format identifier--format = 1 */
839 coverage
; /* Offset to Coverage table--from
840 * beginning of Substitution table */
841 OffsetArrayOf
<LigatureSet
>
842 ligatureSet
; /* Array LigatureSet tables
843 * ordered by Coverage Index */
845 DEFINE_SIZE_ARRAY (6, ligatureSet
);
850 inline bool serialize (hb_serialize_context_t
*c
,
851 Supplier
<GlyphID
> &first_glyphs
,
852 Supplier
<unsigned int> &ligature_per_first_glyph_count_list
,
853 unsigned int num_first_glyphs
,
854 Supplier
<GlyphID
> &ligatures_list
,
855 Supplier
<unsigned int> &component_count_list
,
856 Supplier
<GlyphID
> &component_list
/* Starting from second for each ligature */)
858 TRACE_SERIALIZE (this);
859 if (unlikely (!c
->extend_min (u
.format
))) return TRACE_RETURN (false);
860 unsigned int format
= 1;
861 u
.format
.set (format
);
863 case 1: return TRACE_RETURN (u
.format1
.serialize (c
, first_glyphs
, ligature_per_first_glyph_count_list
, num_first_glyphs
,
864 ligatures_list
, component_count_list
, component_list
));
865 default:return TRACE_RETURN (false);
869 template <typename context_t
>
870 inline typename
context_t::return_t
dispatch (context_t
*c
) const
872 TRACE_DISPATCH (this);
874 case 1: return TRACE_RETURN (c
->dispatch (u
.format1
));
875 default:return TRACE_RETURN (c
->default_return_value ());
879 inline bool sanitize (hb_sanitize_context_t
*c
) {
880 TRACE_SANITIZE (this);
881 if (!u
.format
.sanitize (c
)) return TRACE_RETURN (false);
883 case 1: return TRACE_RETURN (u
.format1
.sanitize (c
));
884 default:return TRACE_RETURN (true);
890 USHORT format
; /* Format identifier */
891 LigatureSubstFormat1 format1
;
896 struct ContextSubst
: Context
{};
898 struct ChainContextSubst
: ChainContext
{};
900 struct ExtensionSubst
: Extension
<ExtensionSubst
>
902 typedef struct SubstLookupSubTable LookupSubTable
;
904 inline bool is_reverse (void) const;
908 struct ReverseChainSingleSubstFormat1
910 inline void closure (hb_closure_context_t
*c
) const
912 TRACE_CLOSURE (this);
913 const OffsetArrayOf
<Coverage
> &lookahead
= StructAfter
<OffsetArrayOf
<Coverage
> > (backtrack
);
917 count
= backtrack
.len
;
918 for (unsigned int i
= 0; i
< count
; i
++)
919 if (!(this+backtrack
[i
]).intersects (c
->glyphs
))
922 count
= lookahead
.len
;
923 for (unsigned int i
= 0; i
< count
; i
++)
924 if (!(this+lookahead
[i
]).intersects (c
->glyphs
))
927 const ArrayOf
<GlyphID
> &substitute
= StructAfter
<ArrayOf
<GlyphID
> > (lookahead
);
929 for (iter
.init (this+coverage
); iter
.more (); iter
.next ()) {
930 if (c
->glyphs
->has (iter
.get_glyph ()))
931 c
->glyphs
->add (substitute
[iter
.get_coverage ()]);
935 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
937 TRACE_COLLECT_GLYPHS (this);
939 const OffsetArrayOf
<Coverage
> &lookahead
= StructAfter
<OffsetArrayOf
<Coverage
> > (backtrack
);
943 (this+coverage
).add_coverage (c
->input
);
945 count
= backtrack
.len
;
946 for (unsigned int i
= 0; i
< count
; i
++)
947 (this+backtrack
[i
]).add_coverage (c
->before
);
949 count
= lookahead
.len
;
950 for (unsigned int i
= 0; i
< count
; i
++)
951 (this+lookahead
[i
]).add_coverage (c
->after
);
953 const ArrayOf
<GlyphID
> &substitute
= StructAfter
<ArrayOf
<GlyphID
> > (lookahead
);
954 count
= substitute
.len
;
955 for (unsigned int i
= 0; i
< count
; i
++)
956 c
->output
->add (substitute
[i
]);
959 inline const Coverage
&get_coverage (void) const
961 return this+coverage
;
964 inline bool would_apply (hb_would_apply_context_t
*c
) const
966 TRACE_WOULD_APPLY (this);
967 return TRACE_RETURN (c
->len
== 1 && (this+coverage
).get_coverage (c
->glyphs
[0]) != NOT_COVERED
);
970 inline bool apply (hb_apply_context_t
*c
) const
973 if (unlikely (c
->nesting_level_left
!= MAX_NESTING_LEVEL
))
974 return TRACE_RETURN (false); /* No chaining to this type */
976 unsigned int index
= (this+coverage
).get_coverage (c
->buffer
->cur().codepoint
);
977 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
979 const OffsetArrayOf
<Coverage
> &lookahead
= StructAfter
<OffsetArrayOf
<Coverage
> > (backtrack
);
980 const ArrayOf
<GlyphID
> &substitute
= StructAfter
<ArrayOf
<GlyphID
> > (lookahead
);
982 if (match_backtrack (c
,
983 backtrack
.len
, (USHORT
*) backtrack
.array
,
984 match_coverage
, this) &&
986 lookahead
.len
, (USHORT
*) lookahead
.array
,
987 match_coverage
, this,
990 c
->replace_glyph_inplace (substitute
[index
]);
991 /* Note: We DON'T decrease buffer->idx. The main loop does it
992 * for us. This is useful for preventing surprises if someone
993 * calls us through a Context lookup. */
994 return TRACE_RETURN (true);
997 return TRACE_RETURN (false);
1000 inline bool sanitize (hb_sanitize_context_t
*c
) {
1001 TRACE_SANITIZE (this);
1002 if (!(coverage
.sanitize (c
, this) && backtrack
.sanitize (c
, this)))
1003 return TRACE_RETURN (false);
1004 OffsetArrayOf
<Coverage
> &lookahead
= StructAfter
<OffsetArrayOf
<Coverage
> > (backtrack
);
1005 if (!lookahead
.sanitize (c
, this))
1006 return TRACE_RETURN (false);
1007 ArrayOf
<GlyphID
> &substitute
= StructAfter
<ArrayOf
<GlyphID
> > (lookahead
);
1008 return TRACE_RETURN (substitute
.sanitize (c
));
1012 USHORT format
; /* Format identifier--format = 1 */
1014 coverage
; /* Offset to Coverage table--from
1015 * beginning of table */
1016 OffsetArrayOf
<Coverage
>
1017 backtrack
; /* Array of coverage tables
1018 * in backtracking sequence, in glyph
1020 OffsetArrayOf
<Coverage
>
1021 lookaheadX
; /* Array of coverage tables
1022 * in lookahead sequence, in glyph
1025 substituteX
; /* Array of substitute
1026 * GlyphIDs--ordered by Coverage Index */
1028 DEFINE_SIZE_MIN (10);
1031 struct ReverseChainSingleSubst
1033 template <typename context_t
>
1034 inline typename
context_t::return_t
dispatch (context_t
*c
) const
1036 TRACE_DISPATCH (this);
1038 case 1: return TRACE_RETURN (c
->dispatch (u
.format1
));
1039 default:return TRACE_RETURN (c
->default_return_value ());
1043 inline bool sanitize (hb_sanitize_context_t
*c
) {
1044 TRACE_SANITIZE (this);
1045 if (!u
.format
.sanitize (c
)) return TRACE_RETURN (false);
1047 case 1: return TRACE_RETURN (u
.format1
.sanitize (c
));
1048 default:return TRACE_RETURN (true);
1054 USHORT format
; /* Format identifier */
1055 ReverseChainSingleSubstFormat1 format1
;
1065 struct SubstLookupSubTable
1067 friend struct SubstLookup
;
1077 ReverseChainSingle
= 8
1080 template <typename context_t
>
1081 inline typename
context_t::return_t
dispatch (context_t
*c
, unsigned int lookup_type
) const
1083 TRACE_DISPATCH (this);
1084 switch (lookup_type
) {
1085 case Single
: return TRACE_RETURN (u
.single
.dispatch (c
));
1086 case Multiple
: return TRACE_RETURN (u
.multiple
.dispatch (c
));
1087 case Alternate
: return TRACE_RETURN (u
.alternate
.dispatch (c
));
1088 case Ligature
: return TRACE_RETURN (u
.ligature
.dispatch (c
));
1089 case Context
: return TRACE_RETURN (u
.context
.dispatch (c
));
1090 case ChainContext
: return TRACE_RETURN (u
.chainContext
.dispatch (c
));
1091 case Extension
: return TRACE_RETURN (u
.extension
.dispatch (c
));
1092 case ReverseChainSingle
: return TRACE_RETURN (u
.reverseChainContextSingle
.dispatch (c
));
1093 default: return TRACE_RETURN (c
->default_return_value ());
1097 inline bool sanitize (hb_sanitize_context_t
*c
, unsigned int lookup_type
) {
1098 TRACE_SANITIZE (this);
1099 if (!u
.header
.sub_format
.sanitize (c
))
1100 return TRACE_RETURN (false);
1101 switch (lookup_type
) {
1102 case Single
: return TRACE_RETURN (u
.single
.sanitize (c
));
1103 case Multiple
: return TRACE_RETURN (u
.multiple
.sanitize (c
));
1104 case Alternate
: return TRACE_RETURN (u
.alternate
.sanitize (c
));
1105 case Ligature
: return TRACE_RETURN (u
.ligature
.sanitize (c
));
1106 case Context
: return TRACE_RETURN (u
.context
.sanitize (c
));
1107 case ChainContext
: return TRACE_RETURN (u
.chainContext
.sanitize (c
));
1108 case Extension
: return TRACE_RETURN (u
.extension
.sanitize (c
));
1109 case ReverseChainSingle
: return TRACE_RETURN (u
.reverseChainContextSingle
.sanitize (c
));
1110 default: return TRACE_RETURN (true);
1120 MultipleSubst multiple
;
1121 AlternateSubst alternate
;
1122 LigatureSubst ligature
;
1123 ContextSubst context
;
1124 ChainContextSubst chainContext
;
1125 ExtensionSubst extension
;
1126 ReverseChainSingleSubst reverseChainContextSingle
;
1129 DEFINE_SIZE_UNION (2, header
.sub_format
);
1133 struct SubstLookup
: Lookup
1135 inline const SubstLookupSubTable
& get_subtable (unsigned int i
) const
1136 { return this+CastR
<OffsetArrayOf
<SubstLookupSubTable
> > (subTable
)[i
]; }
1138 inline static bool lookup_type_is_reverse (unsigned int lookup_type
)
1139 { return lookup_type
== SubstLookupSubTable::ReverseChainSingle
; }
1141 inline bool is_reverse (void) const
1143 unsigned int type
= get_type ();
1144 if (unlikely (type
== SubstLookupSubTable::Extension
))
1145 return CastR
<ExtensionSubst
> (get_subtable(0)).is_reverse ();
1146 return lookup_type_is_reverse (type
);
1149 inline hb_closure_context_t::return_t
closure (hb_closure_context_t
*c
) const
1151 TRACE_CLOSURE (this);
1152 c
->set_recurse_func (dispatch_recurse_func
<hb_closure_context_t
>);
1153 return TRACE_RETURN (dispatch (c
));
1156 inline hb_collect_glyphs_context_t::return_t
collect_glyphs (hb_collect_glyphs_context_t
*c
) const
1158 TRACE_COLLECT_GLYPHS (this);
1159 c
->set_recurse_func (dispatch_recurse_func
<hb_collect_glyphs_context_t
>);
1160 return TRACE_RETURN (dispatch (c
));
1163 template <typename set_t
>
1164 inline void add_coverage (set_t
*glyphs
) const
1166 hb_get_coverage_context_t c
;
1167 const Coverage
*last
= NULL
;
1168 unsigned int count
= get_subtable_count ();
1169 for (unsigned int i
= 0; i
< count
; i
++) {
1170 const Coverage
*coverage
= &get_subtable (i
).dispatch (&c
, get_type ());
1171 if (coverage
!= last
) {
1172 coverage
->add_coverage (glyphs
);
1178 inline bool would_apply (hb_would_apply_context_t
*c
, const hb_set_digest_t
*digest
) const
1180 TRACE_WOULD_APPLY (this);
1181 if (unlikely (!c
->len
)) return TRACE_RETURN (false);
1182 if (!digest
->may_have (c
->glyphs
[0])) return TRACE_RETURN (false);
1183 return TRACE_RETURN (dispatch (c
));
1186 inline bool apply_once (hb_apply_context_t
*c
) const
1189 if (!c
->check_glyph_property (&c
->buffer
->cur(), c
->lookup_props
))
1190 return TRACE_RETURN (false);
1191 return TRACE_RETURN (dispatch (c
));
1194 static bool apply_recurse_func (hb_apply_context_t
*c
, unsigned int lookup_index
);
1196 inline SubstLookupSubTable
& serialize_subtable (hb_serialize_context_t
*c
,
1198 { return CastR
<OffsetArrayOf
<SubstLookupSubTable
> > (subTable
)[i
].serialize (c
, this); }
1200 inline bool serialize_single (hb_serialize_context_t
*c
,
1201 uint32_t lookup_props
,
1202 Supplier
<GlyphID
> &glyphs
,
1203 Supplier
<GlyphID
> &substitutes
,
1204 unsigned int num_glyphs
)
1206 TRACE_SERIALIZE (this);
1207 if (unlikely (!Lookup::serialize (c
, SubstLookupSubTable::Single
, lookup_props
, 1))) return TRACE_RETURN (false);
1208 return TRACE_RETURN (serialize_subtable (c
, 0).u
.single
.serialize (c
, glyphs
, substitutes
, num_glyphs
));
1211 inline bool serialize_multiple (hb_serialize_context_t
*c
,
1212 uint32_t lookup_props
,
1213 Supplier
<GlyphID
> &glyphs
,
1214 Supplier
<unsigned int> &substitute_len_list
,
1215 unsigned int num_glyphs
,
1216 Supplier
<GlyphID
> &substitute_glyphs_list
)
1218 TRACE_SERIALIZE (this);
1219 if (unlikely (!Lookup::serialize (c
, SubstLookupSubTable::Multiple
, lookup_props
, 1))) return TRACE_RETURN (false);
1220 return TRACE_RETURN (serialize_subtable (c
, 0).u
.multiple
.serialize (c
, glyphs
, substitute_len_list
, num_glyphs
,
1221 substitute_glyphs_list
));
1224 inline bool serialize_alternate (hb_serialize_context_t
*c
,
1225 uint32_t lookup_props
,
1226 Supplier
<GlyphID
> &glyphs
,
1227 Supplier
<unsigned int> &alternate_len_list
,
1228 unsigned int num_glyphs
,
1229 Supplier
<GlyphID
> &alternate_glyphs_list
)
1231 TRACE_SERIALIZE (this);
1232 if (unlikely (!Lookup::serialize (c
, SubstLookupSubTable::Alternate
, lookup_props
, 1))) return TRACE_RETURN (false);
1233 return TRACE_RETURN (serialize_subtable (c
, 0).u
.alternate
.serialize (c
, glyphs
, alternate_len_list
, num_glyphs
,
1234 alternate_glyphs_list
));
1237 inline bool serialize_ligature (hb_serialize_context_t
*c
,
1238 uint32_t lookup_props
,
1239 Supplier
<GlyphID
> &first_glyphs
,
1240 Supplier
<unsigned int> &ligature_per_first_glyph_count_list
,
1241 unsigned int num_first_glyphs
,
1242 Supplier
<GlyphID
> &ligatures_list
,
1243 Supplier
<unsigned int> &component_count_list
,
1244 Supplier
<GlyphID
> &component_list
/* Starting from second for each ligature */)
1246 TRACE_SERIALIZE (this);
1247 if (unlikely (!Lookup::serialize (c
, SubstLookupSubTable::Ligature
, lookup_props
, 1))) return TRACE_RETURN (false);
1248 return TRACE_RETURN (serialize_subtable (c
, 0).u
.ligature
.serialize (c
, first_glyphs
, ligature_per_first_glyph_count_list
, num_first_glyphs
,
1249 ligatures_list
, component_count_list
, component_list
));
1252 template <typename context_t
>
1253 static inline typename
context_t::return_t
dispatch_recurse_func (context_t
*c
, unsigned int lookup_index
);
1255 template <typename context_t
>
1256 inline typename
context_t::return_t
dispatch (context_t
*c
) const
1258 TRACE_DISPATCH (this);
1259 unsigned int lookup_type
= get_type ();
1260 unsigned int count
= get_subtable_count ();
1261 for (unsigned int i
= 0; i
< count
; i
++) {
1262 typename
context_t::return_t r
= get_subtable (i
).dispatch (c
, lookup_type
);
1263 if (c
->stop_sublookup_iteration (r
))
1264 return TRACE_RETURN (r
);
1266 return TRACE_RETURN (c
->default_return_value ());
1269 inline bool sanitize (hb_sanitize_context_t
*c
)
1271 TRACE_SANITIZE (this);
1272 if (unlikely (!Lookup::sanitize (c
))) return TRACE_RETURN (false);
1273 OffsetArrayOf
<SubstLookupSubTable
> &list
= CastR
<OffsetArrayOf
<SubstLookupSubTable
> > (subTable
);
1274 if (unlikely (!list
.sanitize (c
, this, get_type ()))) return TRACE_RETURN (false);
1276 if (unlikely (get_type () == SubstLookupSubTable::Extension
))
1278 /* The spec says all subtables of an Extension lookup should
1279 * have the same type. This is specially important if one has
1280 * a reverse type! */
1281 unsigned int type
= get_subtable (0).u
.extension
.get_type ();
1282 unsigned int count
= get_subtable_count ();
1283 for (unsigned int i
= 1; i
< count
; i
++)
1284 if (get_subtable (i
).u
.extension
.get_type () != type
)
1285 return TRACE_RETURN (false);
1287 return TRACE_RETURN (true);
1291 typedef OffsetListOf
<SubstLookup
> SubstLookupList
;
1294 * GSUB -- The Glyph Substitution Table
1297 struct GSUB
: GSUBGPOS
1299 static const hb_tag_t tableTag
= HB_OT_TAG_GSUB
;
1301 inline const SubstLookup
& get_lookup (unsigned int i
) const
1302 { return CastR
<SubstLookup
> (GSUBGPOS::get_lookup (i
)); }
1304 static inline void substitute_start (hb_font_t
*font
, hb_buffer_t
*buffer
);
1305 static inline void substitute_finish (hb_font_t
*font
, hb_buffer_t
*buffer
);
1307 inline bool sanitize (hb_sanitize_context_t
*c
) {
1308 TRACE_SANITIZE (this);
1309 if (unlikely (!GSUBGPOS::sanitize (c
))) return TRACE_RETURN (false);
1310 OffsetTo
<SubstLookupList
> &list
= CastR
<OffsetTo
<SubstLookupList
> > (lookupList
);
1311 return TRACE_RETURN (list
.sanitize (c
, this));
1314 DEFINE_SIZE_STATIC (10);
1319 GSUB::substitute_start (hb_font_t
*font
, hb_buffer_t
*buffer
)
1321 _hb_buffer_allocate_gsubgpos_vars (buffer
);
1323 const GDEF
&gdef
= *hb_ot_layout_from_face (font
->face
)->gdef
;
1324 unsigned int count
= buffer
->len
;
1325 for (unsigned int i
= 0; i
< count
; i
++)
1327 _hb_glyph_info_set_glyph_props (&buffer
->info
[i
], gdef
.get_glyph_props (buffer
->info
[i
].codepoint
));
1328 _hb_glyph_info_clear_lig_props (&buffer
->info
[i
]);
1329 buffer
->info
[i
].syllable() = 0;
1334 GSUB::substitute_finish (hb_font_t
*font HB_UNUSED
, hb_buffer_t
*buffer HB_UNUSED
)
1339 /* Out-of-class implementation for methods recursing */
1341 inline bool ExtensionSubst::is_reverse (void) const
1343 unsigned int type
= get_type ();
1344 if (unlikely (type
== SubstLookupSubTable::Extension
))
1345 return CastR
<ExtensionSubst
> (get_subtable
<SubstLookupSubTable
>()).is_reverse ();
1346 return SubstLookup::lookup_type_is_reverse (type
);
1349 template <typename context_t
>
1350 inline typename
context_t::return_t
SubstLookup::dispatch_recurse_func (context_t
*c
, unsigned int lookup_index
)
1352 const GSUB
&gsub
= *(hb_ot_layout_from_face (c
->face
)->gsub
);
1353 const SubstLookup
&l
= gsub
.get_lookup (lookup_index
);
1354 return l
.dispatch (c
);
1357 inline bool SubstLookup::apply_recurse_func (hb_apply_context_t
*c
, unsigned int lookup_index
)
1359 const GSUB
&gsub
= *(hb_ot_layout_from_face (c
->face
)->gsub
);
1360 const SubstLookup
&l
= gsub
.get_lookup (lookup_index
);
1361 unsigned int saved_lookup_props
= c
->lookup_props
;
1363 bool ret
= l
.apply_once (c
);
1364 c
->lookup_props
= saved_lookup_props
;
1369 } /* namespace OT */
1372 #endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */