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_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
= c
->buffer
->cur().glyph_props() &
276 HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE
? 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 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 unsigned int end_offset
= 0;
630 bool is_mark_ligature
= false;
631 unsigned int total_component_count
= 0;
633 if (likely (!match_input (c
, count
,
639 &total_component_count
)))
640 return TRACE_RETURN (false);
642 /* Deal, we are forming the ligature. */
643 c
->buffer
->merge_clusters (c
->buffer
->idx
, c
->buffer
->idx
+ end_offset
);
652 total_component_count
);
654 return TRACE_RETURN (true);
657 inline bool serialize (hb_serialize_context_t
*c
,
659 Supplier
<GlyphID
> &components
, /* Starting from second */
660 unsigned int num_components
/* Including first component */)
662 TRACE_SERIALIZE (this);
663 if (unlikely (!c
->extend_min (*this))) return TRACE_RETURN (false);
665 if (unlikely (!component
.serialize (c
, components
, num_components
))) return TRACE_RETURN (false);
666 return TRACE_RETURN (true);
670 inline bool sanitize (hb_sanitize_context_t
*c
) {
671 TRACE_SANITIZE (this);
672 return TRACE_RETURN (ligGlyph
.sanitize (c
) && component
.sanitize (c
));
676 GlyphID ligGlyph
; /* GlyphID of ligature to substitute */
677 HeadlessArrayOf
<GlyphID
>
678 component
; /* Array of component GlyphIDs--start
679 * with the second component--ordered
680 * in writing direction */
682 DEFINE_SIZE_ARRAY (4, component
);
687 inline void closure (hb_closure_context_t
*c
) const
689 TRACE_CLOSURE (this);
690 unsigned int num_ligs
= ligature
.len
;
691 for (unsigned int i
= 0; i
< num_ligs
; i
++)
692 (this+ligature
[i
]).closure (c
);
695 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
697 TRACE_COLLECT_GLYPHS (this);
698 unsigned int num_ligs
= ligature
.len
;
699 for (unsigned int i
= 0; i
< num_ligs
; i
++)
700 (this+ligature
[i
]).collect_glyphs (c
);
703 inline bool would_apply (hb_would_apply_context_t
*c
) const
705 TRACE_WOULD_APPLY (this);
706 unsigned int num_ligs
= ligature
.len
;
707 for (unsigned int i
= 0; i
< num_ligs
; i
++)
709 const Ligature
&lig
= this+ligature
[i
];
710 if (lig
.would_apply (c
))
711 return TRACE_RETURN (true);
713 return TRACE_RETURN (false);
716 inline bool apply (hb_apply_context_t
*c
) const
719 unsigned int num_ligs
= ligature
.len
;
720 for (unsigned int i
= 0; i
< num_ligs
; i
++)
722 const Ligature
&lig
= this+ligature
[i
];
723 if (lig
.apply (c
)) return TRACE_RETURN (true);
726 return TRACE_RETURN (false);
729 inline bool serialize (hb_serialize_context_t
*c
,
730 Supplier
<GlyphID
> &ligatures
,
731 Supplier
<unsigned int> &component_count_list
,
732 unsigned int num_ligatures
,
733 Supplier
<GlyphID
> &component_list
/* Starting from second for each ligature */)
735 TRACE_SERIALIZE (this);
736 if (unlikely (!c
->extend_min (*this))) return TRACE_RETURN (false);
737 if (unlikely (!ligature
.serialize (c
, num_ligatures
))) return TRACE_RETURN (false);
738 for (unsigned int i
= 0; i
< num_ligatures
; i
++)
739 if (unlikely (!ligature
[i
].serialize (c
, this).serialize (c
,
742 component_count_list
[i
]))) return TRACE_RETURN (false);
743 ligatures
.advance (num_ligatures
);
744 component_count_list
.advance (num_ligatures
);
745 return TRACE_RETURN (true);
748 inline bool sanitize (hb_sanitize_context_t
*c
) {
749 TRACE_SANITIZE (this);
750 return TRACE_RETURN (ligature
.sanitize (c
, this));
754 OffsetArrayOf
<Ligature
>
755 ligature
; /* Array LigatureSet tables
756 * ordered by preference */
758 DEFINE_SIZE_ARRAY (2, ligature
);
761 struct LigatureSubstFormat1
763 inline void closure (hb_closure_context_t
*c
) const
765 TRACE_CLOSURE (this);
767 for (iter
.init (this+coverage
); iter
.more (); iter
.next ()) {
768 if (c
->glyphs
->has (iter
.get_glyph ()))
769 (this+ligatureSet
[iter
.get_coverage ()]).closure (c
);
773 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
775 TRACE_COLLECT_GLYPHS (this);
777 for (iter
.init (this+coverage
); iter
.more (); iter
.next ()) {
778 c
->input
->add (iter
.get_glyph ());
779 (this+ligatureSet
[iter
.get_coverage ()]).collect_glyphs (c
);
783 inline const Coverage
&get_coverage (void) const
785 return this+coverage
;
788 inline bool would_apply (hb_would_apply_context_t
*c
) const
790 TRACE_WOULD_APPLY (this);
791 unsigned int index
= (this+coverage
).get_coverage (c
->glyphs
[0]);
792 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
794 const LigatureSet
&lig_set
= this+ligatureSet
[index
];
795 return TRACE_RETURN (lig_set
.would_apply (c
));
798 inline bool apply (hb_apply_context_t
*c
) const
801 hb_codepoint_t glyph_id
= c
->buffer
->cur().codepoint
;
803 unsigned int index
= (this+coverage
).get_coverage (glyph_id
);
804 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
806 const LigatureSet
&lig_set
= this+ligatureSet
[index
];
807 return TRACE_RETURN (lig_set
.apply (c
));
810 inline bool serialize (hb_serialize_context_t
*c
,
811 Supplier
<GlyphID
> &first_glyphs
,
812 Supplier
<unsigned int> &ligature_per_first_glyph_count_list
,
813 unsigned int num_first_glyphs
,
814 Supplier
<GlyphID
> &ligatures_list
,
815 Supplier
<unsigned int> &component_count_list
,
816 Supplier
<GlyphID
> &component_list
/* Starting from second for each ligature */)
818 TRACE_SERIALIZE (this);
819 if (unlikely (!c
->extend_min (*this))) return TRACE_RETURN (false);
820 if (unlikely (!ligatureSet
.serialize (c
, num_first_glyphs
))) return TRACE_RETURN (false);
821 for (unsigned int i
= 0; i
< num_first_glyphs
; i
++)
822 if (unlikely (!ligatureSet
[i
].serialize (c
, this).serialize (c
,
824 component_count_list
,
825 ligature_per_first_glyph_count_list
[i
],
826 component_list
))) return TRACE_RETURN (false);
827 ligature_per_first_glyph_count_list
.advance (num_first_glyphs
);
828 if (unlikely (!coverage
.serialize (c
, this).serialize (c
, first_glyphs
, num_first_glyphs
))) return TRACE_RETURN (false);
829 return TRACE_RETURN (true);
832 inline bool sanitize (hb_sanitize_context_t
*c
) {
833 TRACE_SANITIZE (this);
834 return TRACE_RETURN (coverage
.sanitize (c
, this) && ligatureSet
.sanitize (c
, this));
838 USHORT format
; /* Format identifier--format = 1 */
840 coverage
; /* Offset to Coverage table--from
841 * beginning of Substitution table */
842 OffsetArrayOf
<LigatureSet
>
843 ligatureSet
; /* Array LigatureSet tables
844 * ordered by Coverage Index */
846 DEFINE_SIZE_ARRAY (6, ligatureSet
);
851 inline bool serialize (hb_serialize_context_t
*c
,
852 Supplier
<GlyphID
> &first_glyphs
,
853 Supplier
<unsigned int> &ligature_per_first_glyph_count_list
,
854 unsigned int num_first_glyphs
,
855 Supplier
<GlyphID
> &ligatures_list
,
856 Supplier
<unsigned int> &component_count_list
,
857 Supplier
<GlyphID
> &component_list
/* Starting from second for each ligature */)
859 TRACE_SERIALIZE (this);
860 if (unlikely (!c
->extend_min (u
.format
))) return TRACE_RETURN (false);
861 unsigned int format
= 1;
862 u
.format
.set (format
);
864 case 1: return TRACE_RETURN (u
.format1
.serialize (c
, first_glyphs
, ligature_per_first_glyph_count_list
, num_first_glyphs
,
865 ligatures_list
, component_count_list
, component_list
));
866 default:return TRACE_RETURN (false);
870 template <typename context_t
>
871 inline typename
context_t::return_t
dispatch (context_t
*c
) const
873 TRACE_DISPATCH (this);
875 case 1: return TRACE_RETURN (c
->dispatch (u
.format1
));
876 default:return TRACE_RETURN (c
->default_return_value ());
880 inline bool sanitize (hb_sanitize_context_t
*c
) {
881 TRACE_SANITIZE (this);
882 if (!u
.format
.sanitize (c
)) return TRACE_RETURN (false);
884 case 1: return TRACE_RETURN (u
.format1
.sanitize (c
));
885 default:return TRACE_RETURN (true);
891 USHORT format
; /* Format identifier */
892 LigatureSubstFormat1 format1
;
897 struct ContextSubst
: Context
{};
899 struct ChainContextSubst
: ChainContext
{};
901 struct ExtensionSubst
: Extension
<ExtensionSubst
>
903 typedef struct SubstLookupSubTable LookupSubTable
;
905 inline bool is_reverse (void) const;
909 struct ReverseChainSingleSubstFormat1
911 inline void closure (hb_closure_context_t
*c
) const
913 TRACE_CLOSURE (this);
914 const OffsetArrayOf
<Coverage
> &lookahead
= StructAfter
<OffsetArrayOf
<Coverage
> > (backtrack
);
918 count
= backtrack
.len
;
919 for (unsigned int i
= 0; i
< count
; i
++)
920 if (!(this+backtrack
[i
]).intersects (c
->glyphs
))
923 count
= lookahead
.len
;
924 for (unsigned int i
= 0; i
< count
; i
++)
925 if (!(this+lookahead
[i
]).intersects (c
->glyphs
))
928 const ArrayOf
<GlyphID
> &substitute
= StructAfter
<ArrayOf
<GlyphID
> > (lookahead
);
930 for (iter
.init (this+coverage
); iter
.more (); iter
.next ()) {
931 if (c
->glyphs
->has (iter
.get_glyph ()))
932 c
->glyphs
->add (substitute
[iter
.get_coverage ()]);
936 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
938 TRACE_COLLECT_GLYPHS (this);
940 const OffsetArrayOf
<Coverage
> &lookahead
= StructAfter
<OffsetArrayOf
<Coverage
> > (backtrack
);
944 (this+coverage
).add_coverage (c
->input
);
946 count
= backtrack
.len
;
947 for (unsigned int i
= 0; i
< count
; i
++)
948 (this+backtrack
[i
]).add_coverage (c
->before
);
950 count
= lookahead
.len
;
951 for (unsigned int i
= 0; i
< count
; i
++)
952 (this+lookahead
[i
]).add_coverage (c
->after
);
954 const ArrayOf
<GlyphID
> &substitute
= StructAfter
<ArrayOf
<GlyphID
> > (lookahead
);
955 count
= substitute
.len
;
956 for (unsigned int i
= 0; i
< count
; i
++)
957 c
->output
->add (substitute
[i
]);
960 inline const Coverage
&get_coverage (void) const
962 return this+coverage
;
965 inline bool would_apply (hb_would_apply_context_t
*c
) const
967 TRACE_WOULD_APPLY (this);
968 return TRACE_RETURN (c
->len
== 1 && (this+coverage
).get_coverage (c
->glyphs
[0]) != NOT_COVERED
);
971 inline bool apply (hb_apply_context_t
*c
) const
974 if (unlikely (c
->nesting_level_left
!= MAX_NESTING_LEVEL
))
975 return TRACE_RETURN (false); /* No chaining to this type */
977 unsigned int index
= (this+coverage
).get_coverage (c
->buffer
->cur().codepoint
);
978 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
980 const OffsetArrayOf
<Coverage
> &lookahead
= StructAfter
<OffsetArrayOf
<Coverage
> > (backtrack
);
981 const ArrayOf
<GlyphID
> &substitute
= StructAfter
<ArrayOf
<GlyphID
> > (lookahead
);
983 if (match_backtrack (c
,
984 backtrack
.len
, (USHORT
*) backtrack
.array
,
985 match_coverage
, this) &&
987 lookahead
.len
, (USHORT
*) lookahead
.array
,
988 match_coverage
, this,
991 c
->replace_glyph_inplace (substitute
[index
]);
992 c
->buffer
->idx
--; /* Reverse! */
993 return TRACE_RETURN (true);
996 return TRACE_RETURN (false);
999 inline bool sanitize (hb_sanitize_context_t
*c
) {
1000 TRACE_SANITIZE (this);
1001 if (!(coverage
.sanitize (c
, this) && backtrack
.sanitize (c
, this)))
1002 return TRACE_RETURN (false);
1003 OffsetArrayOf
<Coverage
> &lookahead
= StructAfter
<OffsetArrayOf
<Coverage
> > (backtrack
);
1004 if (!lookahead
.sanitize (c
, this))
1005 return TRACE_RETURN (false);
1006 ArrayOf
<GlyphID
> &substitute
= StructAfter
<ArrayOf
<GlyphID
> > (lookahead
);
1007 return TRACE_RETURN (substitute
.sanitize (c
));
1011 USHORT format
; /* Format identifier--format = 1 */
1013 coverage
; /* Offset to Coverage table--from
1014 * beginning of table */
1015 OffsetArrayOf
<Coverage
>
1016 backtrack
; /* Array of coverage tables
1017 * in backtracking sequence, in glyph
1019 OffsetArrayOf
<Coverage
>
1020 lookaheadX
; /* Array of coverage tables
1021 * in lookahead sequence, in glyph
1024 substituteX
; /* Array of substitute
1025 * GlyphIDs--ordered by Coverage Index */
1027 DEFINE_SIZE_MIN (10);
1030 struct ReverseChainSingleSubst
1032 template <typename context_t
>
1033 inline typename
context_t::return_t
dispatch (context_t
*c
) const
1035 TRACE_DISPATCH (this);
1037 case 1: return TRACE_RETURN (c
->dispatch (u
.format1
));
1038 default:return TRACE_RETURN (c
->default_return_value ());
1042 inline bool sanitize (hb_sanitize_context_t
*c
) {
1043 TRACE_SANITIZE (this);
1044 if (!u
.format
.sanitize (c
)) return TRACE_RETURN (false);
1046 case 1: return TRACE_RETURN (u
.format1
.sanitize (c
));
1047 default:return TRACE_RETURN (true);
1053 USHORT format
; /* Format identifier */
1054 ReverseChainSingleSubstFormat1 format1
;
1064 struct SubstLookupSubTable
1066 friend struct SubstLookup
;
1076 ReverseChainSingle
= 8
1079 template <typename context_t
>
1080 inline typename
context_t::return_t
dispatch (context_t
*c
, unsigned int lookup_type
) const
1082 TRACE_DISPATCH (this);
1083 switch (lookup_type
) {
1084 case Single
: return TRACE_RETURN (u
.single
.dispatch (c
));
1085 case Multiple
: return TRACE_RETURN (u
.multiple
.dispatch (c
));
1086 case Alternate
: return TRACE_RETURN (u
.alternate
.dispatch (c
));
1087 case Ligature
: return TRACE_RETURN (u
.ligature
.dispatch (c
));
1088 case Context
: return TRACE_RETURN (u
.context
.dispatch (c
));
1089 case ChainContext
: return TRACE_RETURN (u
.chainContext
.dispatch (c
));
1090 case Extension
: return TRACE_RETURN (u
.extension
.dispatch (c
));
1091 case ReverseChainSingle
: return TRACE_RETURN (u
.reverseChainContextSingle
.dispatch (c
));
1092 default: return TRACE_RETURN (c
->default_return_value ());
1096 inline bool sanitize (hb_sanitize_context_t
*c
, unsigned int lookup_type
) {
1097 TRACE_SANITIZE (this);
1098 if (!u
.header
.sub_format
.sanitize (c
))
1099 return TRACE_RETURN (false);
1100 switch (lookup_type
) {
1101 case Single
: return TRACE_RETURN (u
.single
.sanitize (c
));
1102 case Multiple
: return TRACE_RETURN (u
.multiple
.sanitize (c
));
1103 case Alternate
: return TRACE_RETURN (u
.alternate
.sanitize (c
));
1104 case Ligature
: return TRACE_RETURN (u
.ligature
.sanitize (c
));
1105 case Context
: return TRACE_RETURN (u
.context
.sanitize (c
));
1106 case ChainContext
: return TRACE_RETURN (u
.chainContext
.sanitize (c
));
1107 case Extension
: return TRACE_RETURN (u
.extension
.sanitize (c
));
1108 case ReverseChainSingle
: return TRACE_RETURN (u
.reverseChainContextSingle
.sanitize (c
));
1109 default: return TRACE_RETURN (true);
1119 MultipleSubst multiple
;
1120 AlternateSubst alternate
;
1121 LigatureSubst ligature
;
1122 ContextSubst context
;
1123 ChainContextSubst chainContext
;
1124 ExtensionSubst extension
;
1125 ReverseChainSingleSubst reverseChainContextSingle
;
1128 DEFINE_SIZE_UNION (2, header
.sub_format
);
1132 struct SubstLookup
: Lookup
1134 inline const SubstLookupSubTable
& get_subtable (unsigned int i
) const
1135 { return this+CastR
<OffsetArrayOf
<SubstLookupSubTable
> > (subTable
)[i
]; }
1137 inline static bool lookup_type_is_reverse (unsigned int lookup_type
)
1138 { return lookup_type
== SubstLookupSubTable::ReverseChainSingle
; }
1140 inline bool is_reverse (void) const
1142 unsigned int type
= get_type ();
1143 if (unlikely (type
== SubstLookupSubTable::Extension
))
1144 return CastR
<ExtensionSubst
> (get_subtable(0)).is_reverse ();
1145 return lookup_type_is_reverse (type
);
1148 inline hb_closure_context_t::return_t
closure (hb_closure_context_t
*c
) const
1150 TRACE_CLOSURE (this);
1151 c
->set_recurse_func (dispatch_recurse_func
<hb_closure_context_t
>);
1152 return TRACE_RETURN (dispatch (c
));
1155 inline hb_collect_glyphs_context_t::return_t
collect_glyphs_lookup (hb_collect_glyphs_context_t
*c
) const
1157 TRACE_COLLECT_GLYPHS (this);
1158 c
->set_recurse_func (dispatch_recurse_func
<hb_collect_glyphs_context_t
>);
1159 return TRACE_RETURN (dispatch (c
));
1162 template <typename set_t
>
1163 inline void add_coverage (set_t
*glyphs
) const
1165 hb_get_coverage_context_t c
;
1166 const Coverage
*last
= NULL
;
1167 unsigned int count
= get_subtable_count ();
1168 for (unsigned int i
= 0; i
< count
; i
++) {
1169 const Coverage
*coverage
= &get_subtable (i
).dispatch (&c
, get_type ());
1170 if (coverage
!= last
) {
1171 coverage
->add_coverage (glyphs
);
1177 inline bool would_apply (hb_would_apply_context_t
*c
, const hb_set_digest_t
*digest
) const
1179 TRACE_WOULD_APPLY (this);
1180 if (unlikely (!c
->len
)) return TRACE_RETURN (false);
1181 if (!digest
->may_have (c
->glyphs
[0])) return TRACE_RETURN (false);
1182 return TRACE_RETURN (dispatch (c
));
1185 inline bool apply_once (hb_apply_context_t
*c
) const
1188 if (!c
->check_glyph_property (&c
->buffer
->cur(), c
->lookup_props
))
1189 return TRACE_RETURN (false);
1190 return TRACE_RETURN (dispatch (c
));
1193 static bool apply_recurse_func (hb_apply_context_t
*c
, unsigned int lookup_index
);
1194 inline bool apply_string (hb_apply_context_t
*c
, const hb_set_digest_t
*digest
) const
1198 if (unlikely (!c
->buffer
->len
|| !c
->lookup_mask
))
1201 c
->set_recurse_func (apply_recurse_func
);
1202 c
->set_lookup (*this);
1204 if (likely (!is_reverse ()))
1206 /* in/out forward substitution */
1207 c
->buffer
->clear_output ();
1210 while (c
->buffer
->idx
< c
->buffer
->len
)
1212 if (digest
->may_have (c
->buffer
->cur().codepoint
) &&
1213 (c
->buffer
->cur().mask
& c
->lookup_mask
) &&
1217 c
->buffer
->next_glyph ();
1220 c
->buffer
->swap_buffers ();
1224 /* in-place backward substitution */
1225 c
->buffer
->remove_output ();
1226 c
->buffer
->idx
= c
->buffer
->len
- 1;
1229 if (digest
->may_have (c
->buffer
->cur().codepoint
) &&
1230 (c
->buffer
->cur().mask
& c
->lookup_mask
) &&
1237 while ((int) c
->buffer
->idx
>= 0);
1243 inline SubstLookupSubTable
& serialize_subtable (hb_serialize_context_t
*c
,
1245 { return CastR
<OffsetArrayOf
<SubstLookupSubTable
> > (subTable
)[i
].serialize (c
, this); }
1247 inline bool serialize_single (hb_serialize_context_t
*c
,
1248 uint32_t lookup_props
,
1249 Supplier
<GlyphID
> &glyphs
,
1250 Supplier
<GlyphID
> &substitutes
,
1251 unsigned int num_glyphs
)
1253 TRACE_SERIALIZE (this);
1254 if (unlikely (!Lookup::serialize (c
, SubstLookupSubTable::Single
, lookup_props
, 1))) return TRACE_RETURN (false);
1255 return TRACE_RETURN (serialize_subtable (c
, 0).u
.single
.serialize (c
, glyphs
, substitutes
, num_glyphs
));
1258 inline bool serialize_multiple (hb_serialize_context_t
*c
,
1259 uint32_t lookup_props
,
1260 Supplier
<GlyphID
> &glyphs
,
1261 Supplier
<unsigned int> &substitute_len_list
,
1262 unsigned int num_glyphs
,
1263 Supplier
<GlyphID
> &substitute_glyphs_list
)
1265 TRACE_SERIALIZE (this);
1266 if (unlikely (!Lookup::serialize (c
, SubstLookupSubTable::Multiple
, lookup_props
, 1))) return TRACE_RETURN (false);
1267 return TRACE_RETURN (serialize_subtable (c
, 0).u
.multiple
.serialize (c
, glyphs
, substitute_len_list
, num_glyphs
,
1268 substitute_glyphs_list
));
1271 inline bool serialize_alternate (hb_serialize_context_t
*c
,
1272 uint32_t lookup_props
,
1273 Supplier
<GlyphID
> &glyphs
,
1274 Supplier
<unsigned int> &alternate_len_list
,
1275 unsigned int num_glyphs
,
1276 Supplier
<GlyphID
> &alternate_glyphs_list
)
1278 TRACE_SERIALIZE (this);
1279 if (unlikely (!Lookup::serialize (c
, SubstLookupSubTable::Alternate
, lookup_props
, 1))) return TRACE_RETURN (false);
1280 return TRACE_RETURN (serialize_subtable (c
, 0).u
.alternate
.serialize (c
, glyphs
, alternate_len_list
, num_glyphs
,
1281 alternate_glyphs_list
));
1284 inline bool serialize_ligature (hb_serialize_context_t
*c
,
1285 uint32_t lookup_props
,
1286 Supplier
<GlyphID
> &first_glyphs
,
1287 Supplier
<unsigned int> &ligature_per_first_glyph_count_list
,
1288 unsigned int num_first_glyphs
,
1289 Supplier
<GlyphID
> &ligatures_list
,
1290 Supplier
<unsigned int> &component_count_list
,
1291 Supplier
<GlyphID
> &component_list
/* Starting from second for each ligature */)
1293 TRACE_SERIALIZE (this);
1294 if (unlikely (!Lookup::serialize (c
, SubstLookupSubTable::Ligature
, lookup_props
, 1))) return TRACE_RETURN (false);
1295 return TRACE_RETURN (serialize_subtable (c
, 0).u
.ligature
.serialize (c
, first_glyphs
, ligature_per_first_glyph_count_list
, num_first_glyphs
,
1296 ligatures_list
, component_count_list
, component_list
));
1299 template <typename context_t
>
1300 static inline typename
context_t::return_t
dispatch_recurse_func (context_t
*c
, unsigned int lookup_index
);
1302 template <typename context_t
>
1303 inline typename
context_t::return_t
dispatch (context_t
*c
) const
1305 TRACE_DISPATCH (this);
1306 unsigned int lookup_type
= get_type ();
1307 unsigned int count
= get_subtable_count ();
1308 for (unsigned int i
= 0; i
< count
; i
++) {
1309 typename
context_t::return_t r
= get_subtable (i
).dispatch (c
, lookup_type
);
1310 if (c
->stop_sublookup_iteration (r
))
1311 return TRACE_RETURN (r
);
1313 return TRACE_RETURN (c
->default_return_value ());
1316 inline bool sanitize (hb_sanitize_context_t
*c
)
1318 TRACE_SANITIZE (this);
1319 if (unlikely (!Lookup::sanitize (c
))) return TRACE_RETURN (false);
1320 OffsetArrayOf
<SubstLookupSubTable
> &list
= CastR
<OffsetArrayOf
<SubstLookupSubTable
> > (subTable
);
1321 if (unlikely (!list
.sanitize (c
, this, get_type ()))) return TRACE_RETURN (false);
1323 if (unlikely (get_type () == SubstLookupSubTable::Extension
))
1325 /* The spec says all subtables of an Extension lookup should
1326 * have the same type. This is specially important if one has
1327 * a reverse type! */
1328 unsigned int type
= get_subtable (0).u
.extension
.get_type ();
1329 unsigned int count
= get_subtable_count ();
1330 for (unsigned int i
= 1; i
< count
; i
++)
1331 if (get_subtable (i
).u
.extension
.get_type () != type
)
1332 return TRACE_RETURN (false);
1334 return TRACE_RETURN (true);
1338 typedef OffsetListOf
<SubstLookup
> SubstLookupList
;
1341 * GSUB -- The Glyph Substitution Table
1344 struct GSUB
: GSUBGPOS
1346 static const hb_tag_t Tag
= HB_OT_TAG_GSUB
;
1348 inline const SubstLookup
& get_lookup (unsigned int i
) const
1349 { return CastR
<SubstLookup
> (GSUBGPOS::get_lookup (i
)); }
1351 static inline void substitute_start (hb_font_t
*font
, hb_buffer_t
*buffer
);
1352 static inline void substitute_finish (hb_font_t
*font
, hb_buffer_t
*buffer
);
1354 inline bool sanitize (hb_sanitize_context_t
*c
) {
1355 TRACE_SANITIZE (this);
1356 if (unlikely (!GSUBGPOS::sanitize (c
))) return TRACE_RETURN (false);
1357 OffsetTo
<SubstLookupList
> &list
= CastR
<OffsetTo
<SubstLookupList
> > (lookupList
);
1358 return TRACE_RETURN (list
.sanitize (c
, this));
1361 DEFINE_SIZE_STATIC (10);
1366 GSUB::substitute_start (hb_font_t
*font
, hb_buffer_t
*buffer
)
1368 HB_BUFFER_ALLOCATE_VAR (buffer
, glyph_props
);
1369 HB_BUFFER_ALLOCATE_VAR (buffer
, lig_props
);
1370 HB_BUFFER_ALLOCATE_VAR (buffer
, syllable
);
1372 const GDEF
&gdef
= *hb_ot_layout_from_face (font
->face
)->gdef
;
1373 unsigned int count
= buffer
->len
;
1374 for (unsigned int i
= 0; i
< count
; i
++) {
1375 buffer
->info
[i
].lig_props() = buffer
->info
[i
].syllable() = 0;
1376 buffer
->info
[i
].glyph_props() = gdef
.get_glyph_props (buffer
->info
[i
].codepoint
);
1381 GSUB::substitute_finish (hb_font_t
*font HB_UNUSED
, hb_buffer_t
*buffer HB_UNUSED
)
1386 /* Out-of-class implementation for methods recursing */
1388 inline bool ExtensionSubst::is_reverse (void) const
1390 unsigned int type
= get_type ();
1391 if (unlikely (type
== SubstLookupSubTable::Extension
))
1392 return CastR
<ExtensionSubst
> (get_subtable
<SubstLookupSubTable
>()).is_reverse ();
1393 return SubstLookup::lookup_type_is_reverse (type
);
1396 template <typename context_t
>
1397 inline typename
context_t::return_t
SubstLookup::dispatch_recurse_func (context_t
*c
, unsigned int lookup_index
)
1399 const GSUB
&gsub
= *(hb_ot_layout_from_face (c
->face
)->gsub
);
1400 const SubstLookup
&l
= gsub
.get_lookup (lookup_index
);
1401 return l
.dispatch (c
);
1404 inline bool SubstLookup::apply_recurse_func (hb_apply_context_t
*c
, unsigned int lookup_index
)
1406 const GSUB
&gsub
= *(hb_ot_layout_from_face (c
->face
)->gsub
);
1407 const SubstLookup
&l
= gsub
.get_lookup (lookup_index
);
1408 unsigned int saved_lookup_props
= c
->lookup_props
;
1410 bool ret
= l
.apply_once (c
);
1411 c
->lookup_props
= saved_lookup_props
;
1416 } /* namespace OT */
1419 #endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */