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
) & 0xFFFFu
);
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
) & 0xFFFFu
);
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
) & 0xFFFFu
;
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, u
.format
);
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 unsigned int count
= substitute
.len
;
276 * Testing shows that Uniscribe actually allows zero-len susbstitute,
277 * which essentially deletes a glyph. We don't allow for now. It
278 * can be confusing to the client since the cluster from the deleted
279 * glyph won't be merged with any output cluster... Also, currently
280 * buffer->move_to() makes assumptions about this too. Perhaps fix
281 * in the future after figuring out what to do with the clusters.
283 if (unlikely (!count
)) return TRACE_RETURN (false);
285 /* Special-case to make it in-place and not consider this
286 * as a "multiplied" substitution. */
287 if (unlikely (count
== 1))
289 c
->replace_glyph (substitute
.array
[0]);
290 return TRACE_RETURN (true);
293 unsigned int klass
= _hb_glyph_info_is_ligature (&c
->buffer
->cur()) ?
294 HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH
: 0;
296 for (unsigned int i
= 0; i
< count
; i
++) {
297 _hb_glyph_info_set_lig_props_for_component (&c
->buffer
->cur(), i
);
298 c
->output_glyph_for_component (substitute
.array
[i
], klass
);
300 c
->buffer
->skip_glyph ();
302 return TRACE_RETURN (true);
305 inline bool serialize (hb_serialize_context_t
*c
,
306 Supplier
<GlyphID
> &glyphs
,
307 unsigned int num_glyphs
)
309 TRACE_SERIALIZE (this);
310 if (unlikely (!c
->extend_min (*this))) return TRACE_RETURN (false);
311 if (unlikely (!substitute
.serialize (c
, glyphs
, num_glyphs
))) return TRACE_RETURN (false);
312 return TRACE_RETURN (true);
315 inline bool sanitize (hb_sanitize_context_t
*c
) {
316 TRACE_SANITIZE (this);
317 return TRACE_RETURN (substitute
.sanitize (c
));
322 substitute
; /* String of GlyphIDs to substitute */
324 DEFINE_SIZE_ARRAY (2, substitute
);
327 struct MultipleSubstFormat1
329 inline void closure (hb_closure_context_t
*c
) const
331 TRACE_CLOSURE (this);
333 for (iter
.init (this+coverage
); iter
.more (); iter
.next ()) {
334 if (c
->glyphs
->has (iter
.get_glyph ()))
335 (this+sequence
[iter
.get_coverage ()]).closure (c
);
339 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
341 TRACE_COLLECT_GLYPHS (this);
342 (this+coverage
).add_coverage (c
->input
);
343 unsigned int count
= sequence
.len
;
344 for (unsigned int i
= 0; i
< count
; i
++)
345 (this+sequence
[i
]).collect_glyphs (c
);
348 inline const Coverage
&get_coverage (void) const
350 return this+coverage
;
353 inline bool would_apply (hb_would_apply_context_t
*c
) const
355 TRACE_WOULD_APPLY (this);
356 return TRACE_RETURN (c
->len
== 1 && (this+coverage
).get_coverage (c
->glyphs
[0]) != NOT_COVERED
);
359 inline bool apply (hb_apply_context_t
*c
) const
363 unsigned int index
= (this+coverage
).get_coverage (c
->buffer
->cur().codepoint
);
364 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
366 return TRACE_RETURN ((this+sequence
[index
]).apply (c
));
369 inline bool serialize (hb_serialize_context_t
*c
,
370 Supplier
<GlyphID
> &glyphs
,
371 Supplier
<unsigned int> &substitute_len_list
,
372 unsigned int num_glyphs
,
373 Supplier
<GlyphID
> &substitute_glyphs_list
)
375 TRACE_SERIALIZE (this);
376 if (unlikely (!c
->extend_min (*this))) return TRACE_RETURN (false);
377 if (unlikely (!sequence
.serialize (c
, num_glyphs
))) return TRACE_RETURN (false);
378 for (unsigned int i
= 0; i
< num_glyphs
; i
++)
379 if (unlikely (!sequence
[i
].serialize (c
, this).serialize (c
,
380 substitute_glyphs_list
,
381 substitute_len_list
[i
]))) return TRACE_RETURN (false);
382 substitute_len_list
.advance (num_glyphs
);
383 if (unlikely (!coverage
.serialize (c
, this).serialize (c
, glyphs
, num_glyphs
))) return TRACE_RETURN (false);
384 return TRACE_RETURN (true);
387 inline bool sanitize (hb_sanitize_context_t
*c
) {
388 TRACE_SANITIZE (this);
389 return TRACE_RETURN (coverage
.sanitize (c
, this) && sequence
.sanitize (c
, this));
393 USHORT format
; /* Format identifier--format = 1 */
395 coverage
; /* Offset to Coverage table--from
396 * beginning of Substitution table */
397 OffsetArrayOf
<Sequence
>
398 sequence
; /* Array of Sequence tables
399 * ordered by Coverage Index */
401 DEFINE_SIZE_ARRAY (6, sequence
);
406 inline bool serialize (hb_serialize_context_t
*c
,
407 Supplier
<GlyphID
> &glyphs
,
408 Supplier
<unsigned int> &substitute_len_list
,
409 unsigned int num_glyphs
,
410 Supplier
<GlyphID
> &substitute_glyphs_list
)
412 TRACE_SERIALIZE (this);
413 if (unlikely (!c
->extend_min (u
.format
))) return TRACE_RETURN (false);
414 unsigned int format
= 1;
415 u
.format
.set (format
);
417 case 1: return TRACE_RETURN (u
.format1
.serialize (c
, glyphs
, substitute_len_list
, num_glyphs
, substitute_glyphs_list
));
418 default:return TRACE_RETURN (false);
422 template <typename context_t
>
423 inline typename
context_t::return_t
dispatch (context_t
*c
) const
425 TRACE_DISPATCH (this, u
.format
);
427 case 1: return TRACE_RETURN (c
->dispatch (u
.format1
));
428 default:return TRACE_RETURN (c
->default_return_value ());
432 inline bool sanitize (hb_sanitize_context_t
*c
) {
433 TRACE_SANITIZE (this);
434 if (!u
.format
.sanitize (c
)) return TRACE_RETURN (false);
436 case 1: return TRACE_RETURN (u
.format1
.sanitize (c
));
437 default:return TRACE_RETURN (true);
443 USHORT format
; /* Format identifier */
444 MultipleSubstFormat1 format1
;
449 typedef ArrayOf
<GlyphID
> AlternateSet
; /* Array of alternate GlyphIDs--in
452 struct AlternateSubstFormat1
454 inline void closure (hb_closure_context_t
*c
) const
456 TRACE_CLOSURE (this);
458 for (iter
.init (this+coverage
); iter
.more (); iter
.next ()) {
459 if (c
->glyphs
->has (iter
.get_glyph ())) {
460 const AlternateSet
&alt_set
= this+alternateSet
[iter
.get_coverage ()];
461 unsigned int count
= alt_set
.len
;
462 for (unsigned int i
= 0; i
< count
; i
++)
463 c
->glyphs
->add (alt_set
[i
]);
468 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
470 TRACE_COLLECT_GLYPHS (this);
472 for (iter
.init (this+coverage
); iter
.more (); iter
.next ()) {
473 c
->input
->add (iter
.get_glyph ());
474 const AlternateSet
&alt_set
= this+alternateSet
[iter
.get_coverage ()];
475 unsigned int count
= alt_set
.len
;
476 for (unsigned int i
= 0; i
< count
; i
++)
477 c
->output
->add (alt_set
[i
]);
481 inline const Coverage
&get_coverage (void) const
483 return this+coverage
;
486 inline bool would_apply (hb_would_apply_context_t
*c
) const
488 TRACE_WOULD_APPLY (this);
489 return TRACE_RETURN (c
->len
== 1 && (this+coverage
).get_coverage (c
->glyphs
[0]) != NOT_COVERED
);
492 inline bool apply (hb_apply_context_t
*c
) const
495 hb_codepoint_t glyph_id
= c
->buffer
->cur().codepoint
;
497 unsigned int index
= (this+coverage
).get_coverage (glyph_id
);
498 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
500 const AlternateSet
&alt_set
= this+alternateSet
[index
];
502 if (unlikely (!alt_set
.len
)) return TRACE_RETURN (false);
504 hb_mask_t glyph_mask
= c
->buffer
->cur().mask
;
505 hb_mask_t lookup_mask
= c
->lookup_mask
;
507 /* Note: This breaks badly if two features enabled this lookup together. */
508 unsigned int shift
= _hb_ctz (lookup_mask
);
509 unsigned int alt_index
= ((lookup_mask
& glyph_mask
) >> shift
);
511 if (unlikely (alt_index
> alt_set
.len
|| alt_index
== 0)) return TRACE_RETURN (false);
513 glyph_id
= alt_set
[alt_index
- 1];
515 c
->replace_glyph (glyph_id
);
517 return TRACE_RETURN (true);
520 inline bool serialize (hb_serialize_context_t
*c
,
521 Supplier
<GlyphID
> &glyphs
,
522 Supplier
<unsigned int> &alternate_len_list
,
523 unsigned int num_glyphs
,
524 Supplier
<GlyphID
> &alternate_glyphs_list
)
526 TRACE_SERIALIZE (this);
527 if (unlikely (!c
->extend_min (*this))) return TRACE_RETURN (false);
528 if (unlikely (!alternateSet
.serialize (c
, num_glyphs
))) return TRACE_RETURN (false);
529 for (unsigned int i
= 0; i
< num_glyphs
; i
++)
530 if (unlikely (!alternateSet
[i
].serialize (c
, this).serialize (c
,
531 alternate_glyphs_list
,
532 alternate_len_list
[i
]))) return TRACE_RETURN (false);
533 alternate_len_list
.advance (num_glyphs
);
534 if (unlikely (!coverage
.serialize (c
, this).serialize (c
, glyphs
, num_glyphs
))) return TRACE_RETURN (false);
535 return TRACE_RETURN (true);
538 inline bool sanitize (hb_sanitize_context_t
*c
) {
539 TRACE_SANITIZE (this);
540 return TRACE_RETURN (coverage
.sanitize (c
, this) && alternateSet
.sanitize (c
, this));
544 USHORT format
; /* Format identifier--format = 1 */
546 coverage
; /* Offset to Coverage table--from
547 * beginning of Substitution table */
548 OffsetArrayOf
<AlternateSet
>
549 alternateSet
; /* Array of AlternateSet tables
550 * ordered by Coverage Index */
552 DEFINE_SIZE_ARRAY (6, alternateSet
);
555 struct AlternateSubst
557 inline bool serialize (hb_serialize_context_t
*c
,
558 Supplier
<GlyphID
> &glyphs
,
559 Supplier
<unsigned int> &alternate_len_list
,
560 unsigned int num_glyphs
,
561 Supplier
<GlyphID
> &alternate_glyphs_list
)
563 TRACE_SERIALIZE (this);
564 if (unlikely (!c
->extend_min (u
.format
))) return TRACE_RETURN (false);
565 unsigned int format
= 1;
566 u
.format
.set (format
);
568 case 1: return TRACE_RETURN (u
.format1
.serialize (c
, glyphs
, alternate_len_list
, num_glyphs
, alternate_glyphs_list
));
569 default:return TRACE_RETURN (false);
573 template <typename context_t
>
574 inline typename
context_t::return_t
dispatch (context_t
*c
) const
576 TRACE_DISPATCH (this, u
.format
);
578 case 1: return TRACE_RETURN (c
->dispatch (u
.format1
));
579 default:return TRACE_RETURN (c
->default_return_value ());
583 inline bool sanitize (hb_sanitize_context_t
*c
) {
584 TRACE_SANITIZE (this);
585 if (!u
.format
.sanitize (c
)) return TRACE_RETURN (false);
587 case 1: return TRACE_RETURN (u
.format1
.sanitize (c
));
588 default:return TRACE_RETURN (true);
594 USHORT format
; /* Format identifier */
595 AlternateSubstFormat1 format1
;
602 inline void closure (hb_closure_context_t
*c
) const
604 TRACE_CLOSURE (this);
605 unsigned int count
= component
.len
;
606 for (unsigned int i
= 1; i
< count
; i
++)
607 if (!c
->glyphs
->has (component
[i
]))
609 c
->glyphs
->add (ligGlyph
);
612 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
614 TRACE_COLLECT_GLYPHS (this);
615 unsigned int count
= component
.len
;
616 for (unsigned int i
= 1; i
< count
; i
++)
617 c
->input
->add (component
[i
]);
618 c
->output
->add (ligGlyph
);
621 inline bool would_apply (hb_would_apply_context_t
*c
) const
623 TRACE_WOULD_APPLY (this);
624 if (c
->len
!= component
.len
)
625 return TRACE_RETURN (false);
627 for (unsigned int i
= 1; i
< c
->len
; i
++)
628 if (likely (c
->glyphs
[i
] != component
[i
]))
629 return TRACE_RETURN (false);
631 return TRACE_RETURN (true);
634 inline bool apply (hb_apply_context_t
*c
) const
637 unsigned int count
= component
.len
;
639 if (unlikely (!count
)) return TRACE_RETURN (false);
641 /* Special-case to make it in-place and not consider this
642 * as a "ligated" substitution. */
643 if (unlikely (count
== 1))
645 c
->replace_glyph (ligGlyph
);
646 return TRACE_RETURN (true);
649 bool is_mark_ligature
= false;
650 unsigned int total_component_count
= 0;
652 unsigned int match_length
= 0;
653 unsigned int match_positions
[MAX_CONTEXT_LENGTH
];
655 if (likely (!match_input (c
, count
,
662 &total_component_count
)))
663 return TRACE_RETURN (false);
671 total_component_count
);
673 return TRACE_RETURN (true);
676 inline bool serialize (hb_serialize_context_t
*c
,
678 Supplier
<GlyphID
> &components
, /* Starting from second */
679 unsigned int num_components
/* Including first component */)
681 TRACE_SERIALIZE (this);
682 if (unlikely (!c
->extend_min (*this))) return TRACE_RETURN (false);
684 if (unlikely (!component
.serialize (c
, components
, num_components
))) return TRACE_RETURN (false);
685 return TRACE_RETURN (true);
689 inline bool sanitize (hb_sanitize_context_t
*c
) {
690 TRACE_SANITIZE (this);
691 return TRACE_RETURN (ligGlyph
.sanitize (c
) && component
.sanitize (c
));
695 GlyphID ligGlyph
; /* GlyphID of ligature to substitute */
696 HeadlessArrayOf
<GlyphID
>
697 component
; /* Array of component GlyphIDs--start
698 * with the second component--ordered
699 * in writing direction */
701 DEFINE_SIZE_ARRAY (4, component
);
706 inline void closure (hb_closure_context_t
*c
) const
708 TRACE_CLOSURE (this);
709 unsigned int num_ligs
= ligature
.len
;
710 for (unsigned int i
= 0; i
< num_ligs
; i
++)
711 (this+ligature
[i
]).closure (c
);
714 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
716 TRACE_COLLECT_GLYPHS (this);
717 unsigned int num_ligs
= ligature
.len
;
718 for (unsigned int i
= 0; i
< num_ligs
; i
++)
719 (this+ligature
[i
]).collect_glyphs (c
);
722 inline bool would_apply (hb_would_apply_context_t
*c
) const
724 TRACE_WOULD_APPLY (this);
725 unsigned int num_ligs
= ligature
.len
;
726 for (unsigned int i
= 0; i
< num_ligs
; i
++)
728 const Ligature
&lig
= this+ligature
[i
];
729 if (lig
.would_apply (c
))
730 return TRACE_RETURN (true);
732 return TRACE_RETURN (false);
735 inline bool apply (hb_apply_context_t
*c
) const
738 unsigned int num_ligs
= ligature
.len
;
739 for (unsigned int i
= 0; i
< num_ligs
; i
++)
741 const Ligature
&lig
= this+ligature
[i
];
742 if (lig
.apply (c
)) return TRACE_RETURN (true);
745 return TRACE_RETURN (false);
748 inline bool serialize (hb_serialize_context_t
*c
,
749 Supplier
<GlyphID
> &ligatures
,
750 Supplier
<unsigned int> &component_count_list
,
751 unsigned int num_ligatures
,
752 Supplier
<GlyphID
> &component_list
/* Starting from second for each ligature */)
754 TRACE_SERIALIZE (this);
755 if (unlikely (!c
->extend_min (*this))) return TRACE_RETURN (false);
756 if (unlikely (!ligature
.serialize (c
, num_ligatures
))) return TRACE_RETURN (false);
757 for (unsigned int i
= 0; i
< num_ligatures
; i
++)
758 if (unlikely (!ligature
[i
].serialize (c
, this).serialize (c
,
761 component_count_list
[i
]))) return TRACE_RETURN (false);
762 ligatures
.advance (num_ligatures
);
763 component_count_list
.advance (num_ligatures
);
764 return TRACE_RETURN (true);
767 inline bool sanitize (hb_sanitize_context_t
*c
) {
768 TRACE_SANITIZE (this);
769 return TRACE_RETURN (ligature
.sanitize (c
, this));
773 OffsetArrayOf
<Ligature
>
774 ligature
; /* Array LigatureSet tables
775 * ordered by preference */
777 DEFINE_SIZE_ARRAY (2, ligature
);
780 struct LigatureSubstFormat1
782 inline void closure (hb_closure_context_t
*c
) const
784 TRACE_CLOSURE (this);
786 for (iter
.init (this+coverage
); iter
.more (); iter
.next ()) {
787 if (c
->glyphs
->has (iter
.get_glyph ()))
788 (this+ligatureSet
[iter
.get_coverage ()]).closure (c
);
792 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
794 TRACE_COLLECT_GLYPHS (this);
796 for (iter
.init (this+coverage
); iter
.more (); iter
.next ()) {
797 c
->input
->add (iter
.get_glyph ());
798 (this+ligatureSet
[iter
.get_coverage ()]).collect_glyphs (c
);
802 inline const Coverage
&get_coverage (void) const
804 return this+coverage
;
807 inline bool would_apply (hb_would_apply_context_t
*c
) const
809 TRACE_WOULD_APPLY (this);
810 unsigned int index
= (this+coverage
).get_coverage (c
->glyphs
[0]);
811 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
813 const LigatureSet
&lig_set
= this+ligatureSet
[index
];
814 return TRACE_RETURN (lig_set
.would_apply (c
));
817 inline bool apply (hb_apply_context_t
*c
) const
820 hb_codepoint_t glyph_id
= c
->buffer
->cur().codepoint
;
822 unsigned int index
= (this+coverage
).get_coverage (glyph_id
);
823 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
825 const LigatureSet
&lig_set
= this+ligatureSet
[index
];
826 return TRACE_RETURN (lig_set
.apply (c
));
829 inline bool serialize (hb_serialize_context_t
*c
,
830 Supplier
<GlyphID
> &first_glyphs
,
831 Supplier
<unsigned int> &ligature_per_first_glyph_count_list
,
832 unsigned int num_first_glyphs
,
833 Supplier
<GlyphID
> &ligatures_list
,
834 Supplier
<unsigned int> &component_count_list
,
835 Supplier
<GlyphID
> &component_list
/* Starting from second for each ligature */)
837 TRACE_SERIALIZE (this);
838 if (unlikely (!c
->extend_min (*this))) return TRACE_RETURN (false);
839 if (unlikely (!ligatureSet
.serialize (c
, num_first_glyphs
))) return TRACE_RETURN (false);
840 for (unsigned int i
= 0; i
< num_first_glyphs
; i
++)
841 if (unlikely (!ligatureSet
[i
].serialize (c
, this).serialize (c
,
843 component_count_list
,
844 ligature_per_first_glyph_count_list
[i
],
845 component_list
))) return TRACE_RETURN (false);
846 ligature_per_first_glyph_count_list
.advance (num_first_glyphs
);
847 if (unlikely (!coverage
.serialize (c
, this).serialize (c
, first_glyphs
, num_first_glyphs
))) return TRACE_RETURN (false);
848 return TRACE_RETURN (true);
851 inline bool sanitize (hb_sanitize_context_t
*c
) {
852 TRACE_SANITIZE (this);
853 return TRACE_RETURN (coverage
.sanitize (c
, this) && ligatureSet
.sanitize (c
, this));
857 USHORT format
; /* Format identifier--format = 1 */
859 coverage
; /* Offset to Coverage table--from
860 * beginning of Substitution table */
861 OffsetArrayOf
<LigatureSet
>
862 ligatureSet
; /* Array LigatureSet tables
863 * ordered by Coverage Index */
865 DEFINE_SIZE_ARRAY (6, ligatureSet
);
870 inline bool serialize (hb_serialize_context_t
*c
,
871 Supplier
<GlyphID
> &first_glyphs
,
872 Supplier
<unsigned int> &ligature_per_first_glyph_count_list
,
873 unsigned int num_first_glyphs
,
874 Supplier
<GlyphID
> &ligatures_list
,
875 Supplier
<unsigned int> &component_count_list
,
876 Supplier
<GlyphID
> &component_list
/* Starting from second for each ligature */)
878 TRACE_SERIALIZE (this);
879 if (unlikely (!c
->extend_min (u
.format
))) return TRACE_RETURN (false);
880 unsigned int format
= 1;
881 u
.format
.set (format
);
883 case 1: return TRACE_RETURN (u
.format1
.serialize (c
, first_glyphs
, ligature_per_first_glyph_count_list
, num_first_glyphs
,
884 ligatures_list
, component_count_list
, component_list
));
885 default:return TRACE_RETURN (false);
889 template <typename context_t
>
890 inline typename
context_t::return_t
dispatch (context_t
*c
) const
892 TRACE_DISPATCH (this, u
.format
);
894 case 1: return TRACE_RETURN (c
->dispatch (u
.format1
));
895 default:return TRACE_RETURN (c
->default_return_value ());
899 inline bool sanitize (hb_sanitize_context_t
*c
) {
900 TRACE_SANITIZE (this);
901 if (!u
.format
.sanitize (c
)) return TRACE_RETURN (false);
903 case 1: return TRACE_RETURN (u
.format1
.sanitize (c
));
904 default:return TRACE_RETURN (true);
910 USHORT format
; /* Format identifier */
911 LigatureSubstFormat1 format1
;
916 struct ContextSubst
: Context
{};
918 struct ChainContextSubst
: ChainContext
{};
920 struct ExtensionSubst
: Extension
<ExtensionSubst
>
922 typedef struct SubstLookupSubTable LookupSubTable
;
924 inline bool is_reverse (void) const;
928 struct ReverseChainSingleSubstFormat1
930 inline void closure (hb_closure_context_t
*c
) const
932 TRACE_CLOSURE (this);
933 const OffsetArrayOf
<Coverage
> &lookahead
= StructAfter
<OffsetArrayOf
<Coverage
> > (backtrack
);
937 count
= backtrack
.len
;
938 for (unsigned int i
= 0; i
< count
; i
++)
939 if (!(this+backtrack
[i
]).intersects (c
->glyphs
))
942 count
= lookahead
.len
;
943 for (unsigned int i
= 0; i
< count
; i
++)
944 if (!(this+lookahead
[i
]).intersects (c
->glyphs
))
947 const ArrayOf
<GlyphID
> &substitute
= StructAfter
<ArrayOf
<GlyphID
> > (lookahead
);
949 for (iter
.init (this+coverage
); iter
.more (); iter
.next ()) {
950 if (c
->glyphs
->has (iter
.get_glyph ()))
951 c
->glyphs
->add (substitute
[iter
.get_coverage ()]);
955 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
957 TRACE_COLLECT_GLYPHS (this);
959 const OffsetArrayOf
<Coverage
> &lookahead
= StructAfter
<OffsetArrayOf
<Coverage
> > (backtrack
);
963 (this+coverage
).add_coverage (c
->input
);
965 count
= backtrack
.len
;
966 for (unsigned int i
= 0; i
< count
; i
++)
967 (this+backtrack
[i
]).add_coverage (c
->before
);
969 count
= lookahead
.len
;
970 for (unsigned int i
= 0; i
< count
; i
++)
971 (this+lookahead
[i
]).add_coverage (c
->after
);
973 const ArrayOf
<GlyphID
> &substitute
= StructAfter
<ArrayOf
<GlyphID
> > (lookahead
);
974 count
= substitute
.len
;
975 for (unsigned int i
= 0; i
< count
; i
++)
976 c
->output
->add (substitute
[i
]);
979 inline const Coverage
&get_coverage (void) const
981 return this+coverage
;
984 inline bool would_apply (hb_would_apply_context_t
*c
) const
986 TRACE_WOULD_APPLY (this);
987 return TRACE_RETURN (c
->len
== 1 && (this+coverage
).get_coverage (c
->glyphs
[0]) != NOT_COVERED
);
990 inline bool apply (hb_apply_context_t
*c
) const
993 if (unlikely (c
->nesting_level_left
!= MAX_NESTING_LEVEL
))
994 return TRACE_RETURN (false); /* No chaining to this type */
996 unsigned int index
= (this+coverage
).get_coverage (c
->buffer
->cur().codepoint
);
997 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
999 const OffsetArrayOf
<Coverage
> &lookahead
= StructAfter
<OffsetArrayOf
<Coverage
> > (backtrack
);
1000 const ArrayOf
<GlyphID
> &substitute
= StructAfter
<ArrayOf
<GlyphID
> > (lookahead
);
1002 if (match_backtrack (c
,
1003 backtrack
.len
, (USHORT
*) backtrack
.array
,
1004 match_coverage
, this) &&
1006 lookahead
.len
, (USHORT
*) lookahead
.array
,
1007 match_coverage
, this,
1010 c
->replace_glyph_inplace (substitute
[index
]);
1011 /* Note: We DON'T decrease buffer->idx. The main loop does it
1012 * for us. This is useful for preventing surprises if someone
1013 * calls us through a Context lookup. */
1014 return TRACE_RETURN (true);
1017 return TRACE_RETURN (false);
1020 inline bool sanitize (hb_sanitize_context_t
*c
) {
1021 TRACE_SANITIZE (this);
1022 if (!(coverage
.sanitize (c
, this) && backtrack
.sanitize (c
, this)))
1023 return TRACE_RETURN (false);
1024 OffsetArrayOf
<Coverage
> &lookahead
= StructAfter
<OffsetArrayOf
<Coverage
> > (backtrack
);
1025 if (!lookahead
.sanitize (c
, this))
1026 return TRACE_RETURN (false);
1027 ArrayOf
<GlyphID
> &substitute
= StructAfter
<ArrayOf
<GlyphID
> > (lookahead
);
1028 return TRACE_RETURN (substitute
.sanitize (c
));
1032 USHORT format
; /* Format identifier--format = 1 */
1034 coverage
; /* Offset to Coverage table--from
1035 * beginning of table */
1036 OffsetArrayOf
<Coverage
>
1037 backtrack
; /* Array of coverage tables
1038 * in backtracking sequence, in glyph
1040 OffsetArrayOf
<Coverage
>
1041 lookaheadX
; /* Array of coverage tables
1042 * in lookahead sequence, in glyph
1045 substituteX
; /* Array of substitute
1046 * GlyphIDs--ordered by Coverage Index */
1048 DEFINE_SIZE_MIN (10);
1051 struct ReverseChainSingleSubst
1053 template <typename context_t
>
1054 inline typename
context_t::return_t
dispatch (context_t
*c
) const
1056 TRACE_DISPATCH (this, u
.format
);
1058 case 1: return TRACE_RETURN (c
->dispatch (u
.format1
));
1059 default:return TRACE_RETURN (c
->default_return_value ());
1063 inline bool sanitize (hb_sanitize_context_t
*c
) {
1064 TRACE_SANITIZE (this);
1065 if (!u
.format
.sanitize (c
)) return TRACE_RETURN (false);
1067 case 1: return TRACE_RETURN (u
.format1
.sanitize (c
));
1068 default:return TRACE_RETURN (true);
1074 USHORT format
; /* Format identifier */
1075 ReverseChainSingleSubstFormat1 format1
;
1085 struct SubstLookupSubTable
1087 friend struct SubstLookup
;
1097 ReverseChainSingle
= 8
1100 template <typename context_t
>
1101 inline typename
context_t::return_t
dispatch (context_t
*c
, unsigned int lookup_type
) const
1103 TRACE_DISPATCH (this, lookup_type
);
1104 switch (lookup_type
) {
1105 case Single
: return TRACE_RETURN (u
.single
.dispatch (c
));
1106 case Multiple
: return TRACE_RETURN (u
.multiple
.dispatch (c
));
1107 case Alternate
: return TRACE_RETURN (u
.alternate
.dispatch (c
));
1108 case Ligature
: return TRACE_RETURN (u
.ligature
.dispatch (c
));
1109 case Context
: return TRACE_RETURN (u
.context
.dispatch (c
));
1110 case ChainContext
: return TRACE_RETURN (u
.chainContext
.dispatch (c
));
1111 case Extension
: return TRACE_RETURN (u
.extension
.dispatch (c
));
1112 case ReverseChainSingle
: return TRACE_RETURN (u
.reverseChainContextSingle
.dispatch (c
));
1113 default: return TRACE_RETURN (c
->default_return_value ());
1117 inline bool sanitize (hb_sanitize_context_t
*c
, unsigned int lookup_type
) {
1118 TRACE_SANITIZE (this);
1119 if (!u
.header
.sub_format
.sanitize (c
))
1120 return TRACE_RETURN (false);
1121 switch (lookup_type
) {
1122 case Single
: return TRACE_RETURN (u
.single
.sanitize (c
));
1123 case Multiple
: return TRACE_RETURN (u
.multiple
.sanitize (c
));
1124 case Alternate
: return TRACE_RETURN (u
.alternate
.sanitize (c
));
1125 case Ligature
: return TRACE_RETURN (u
.ligature
.sanitize (c
));
1126 case Context
: return TRACE_RETURN (u
.context
.sanitize (c
));
1127 case ChainContext
: return TRACE_RETURN (u
.chainContext
.sanitize (c
));
1128 case Extension
: return TRACE_RETURN (u
.extension
.sanitize (c
));
1129 case ReverseChainSingle
: return TRACE_RETURN (u
.reverseChainContextSingle
.sanitize (c
));
1130 default: return TRACE_RETURN (true);
1140 MultipleSubst multiple
;
1141 AlternateSubst alternate
;
1142 LigatureSubst ligature
;
1143 ContextSubst context
;
1144 ChainContextSubst chainContext
;
1145 ExtensionSubst extension
;
1146 ReverseChainSingleSubst reverseChainContextSingle
;
1149 DEFINE_SIZE_UNION (2, header
.sub_format
);
1153 struct SubstLookup
: Lookup
1155 inline const SubstLookupSubTable
& get_subtable (unsigned int i
) const
1156 { return this+CastR
<OffsetArrayOf
<SubstLookupSubTable
> > (subTable
)[i
]; }
1158 inline static bool lookup_type_is_reverse (unsigned int lookup_type
)
1159 { return lookup_type
== SubstLookupSubTable::ReverseChainSingle
; }
1161 inline bool is_reverse (void) const
1163 unsigned int type
= get_type ();
1164 if (unlikely (type
== SubstLookupSubTable::Extension
))
1165 return CastR
<ExtensionSubst
> (get_subtable(0)).is_reverse ();
1166 return lookup_type_is_reverse (type
);
1169 inline hb_closure_context_t::return_t
closure (hb_closure_context_t
*c
) const
1171 TRACE_CLOSURE (this);
1172 c
->set_recurse_func (dispatch_recurse_func
<hb_closure_context_t
>);
1173 return TRACE_RETURN (dispatch (c
));
1176 inline hb_collect_glyphs_context_t::return_t
collect_glyphs (hb_collect_glyphs_context_t
*c
) const
1178 TRACE_COLLECT_GLYPHS (this);
1179 c
->set_recurse_func (dispatch_recurse_func
<hb_collect_glyphs_context_t
>);
1180 return TRACE_RETURN (dispatch (c
));
1183 template <typename set_t
>
1184 inline void add_coverage (set_t
*glyphs
) const
1186 hb_get_coverage_context_t c
;
1187 const Coverage
*last
= NULL
;
1188 unsigned int count
= get_subtable_count ();
1189 for (unsigned int i
= 0; i
< count
; i
++) {
1190 const Coverage
*coverage
= &get_subtable (i
).dispatch (&c
, get_type ());
1191 if (coverage
!= last
) {
1192 coverage
->add_coverage (glyphs
);
1198 inline bool would_apply (hb_would_apply_context_t
*c
, const hb_set_digest_t
*digest
) const
1200 TRACE_WOULD_APPLY (this);
1201 if (unlikely (!c
->len
)) return TRACE_RETURN (false);
1202 if (!digest
->may_have (c
->glyphs
[0])) return TRACE_RETURN (false);
1203 return TRACE_RETURN (dispatch (c
));
1206 inline bool apply_once (hb_apply_context_t
*c
) const
1209 if (!c
->check_glyph_property (&c
->buffer
->cur(), c
->lookup_props
))
1210 return TRACE_RETURN (false);
1211 return TRACE_RETURN (dispatch (c
));
1214 static bool apply_recurse_func (hb_apply_context_t
*c
, unsigned int lookup_index
);
1216 inline SubstLookupSubTable
& serialize_subtable (hb_serialize_context_t
*c
,
1218 { return CastR
<OffsetArrayOf
<SubstLookupSubTable
> > (subTable
)[i
].serialize (c
, this); }
1220 inline bool serialize_single (hb_serialize_context_t
*c
,
1221 uint32_t lookup_props
,
1222 Supplier
<GlyphID
> &glyphs
,
1223 Supplier
<GlyphID
> &substitutes
,
1224 unsigned int num_glyphs
)
1226 TRACE_SERIALIZE (this);
1227 if (unlikely (!Lookup::serialize (c
, SubstLookupSubTable::Single
, lookup_props
, 1))) return TRACE_RETURN (false);
1228 return TRACE_RETURN (serialize_subtable (c
, 0).u
.single
.serialize (c
, glyphs
, substitutes
, num_glyphs
));
1231 inline bool serialize_multiple (hb_serialize_context_t
*c
,
1232 uint32_t lookup_props
,
1233 Supplier
<GlyphID
> &glyphs
,
1234 Supplier
<unsigned int> &substitute_len_list
,
1235 unsigned int num_glyphs
,
1236 Supplier
<GlyphID
> &substitute_glyphs_list
)
1238 TRACE_SERIALIZE (this);
1239 if (unlikely (!Lookup::serialize (c
, SubstLookupSubTable::Multiple
, lookup_props
, 1))) return TRACE_RETURN (false);
1240 return TRACE_RETURN (serialize_subtable (c
, 0).u
.multiple
.serialize (c
, glyphs
, substitute_len_list
, num_glyphs
,
1241 substitute_glyphs_list
));
1244 inline bool serialize_alternate (hb_serialize_context_t
*c
,
1245 uint32_t lookup_props
,
1246 Supplier
<GlyphID
> &glyphs
,
1247 Supplier
<unsigned int> &alternate_len_list
,
1248 unsigned int num_glyphs
,
1249 Supplier
<GlyphID
> &alternate_glyphs_list
)
1251 TRACE_SERIALIZE (this);
1252 if (unlikely (!Lookup::serialize (c
, SubstLookupSubTable::Alternate
, lookup_props
, 1))) return TRACE_RETURN (false);
1253 return TRACE_RETURN (serialize_subtable (c
, 0).u
.alternate
.serialize (c
, glyphs
, alternate_len_list
, num_glyphs
,
1254 alternate_glyphs_list
));
1257 inline bool serialize_ligature (hb_serialize_context_t
*c
,
1258 uint32_t lookup_props
,
1259 Supplier
<GlyphID
> &first_glyphs
,
1260 Supplier
<unsigned int> &ligature_per_first_glyph_count_list
,
1261 unsigned int num_first_glyphs
,
1262 Supplier
<GlyphID
> &ligatures_list
,
1263 Supplier
<unsigned int> &component_count_list
,
1264 Supplier
<GlyphID
> &component_list
/* Starting from second for each ligature */)
1266 TRACE_SERIALIZE (this);
1267 if (unlikely (!Lookup::serialize (c
, SubstLookupSubTable::Ligature
, lookup_props
, 1))) return TRACE_RETURN (false);
1268 return TRACE_RETURN (serialize_subtable (c
, 0).u
.ligature
.serialize (c
, first_glyphs
, ligature_per_first_glyph_count_list
, num_first_glyphs
,
1269 ligatures_list
, component_count_list
, component_list
));
1272 template <typename context_t
>
1273 static inline typename
context_t::return_t
dispatch_recurse_func (context_t
*c
, unsigned int lookup_index
);
1275 template <typename context_t
>
1276 inline typename
context_t::return_t
dispatch (context_t
*c
) const
1278 unsigned int lookup_type
= get_type ();
1279 TRACE_DISPATCH (this, lookup_type
);
1280 unsigned int count
= get_subtable_count ();
1281 for (unsigned int i
= 0; i
< count
; i
++) {
1282 typename
context_t::return_t r
= get_subtable (i
).dispatch (c
, lookup_type
);
1283 if (c
->stop_sublookup_iteration (r
))
1284 return TRACE_RETURN (r
);
1286 return TRACE_RETURN (c
->default_return_value ());
1289 inline bool sanitize (hb_sanitize_context_t
*c
)
1291 TRACE_SANITIZE (this);
1292 if (unlikely (!Lookup::sanitize (c
))) return TRACE_RETURN (false);
1293 OffsetArrayOf
<SubstLookupSubTable
> &list
= CastR
<OffsetArrayOf
<SubstLookupSubTable
> > (subTable
);
1294 if (unlikely (!list
.sanitize (c
, this, get_type ()))) return TRACE_RETURN (false);
1296 if (unlikely (get_type () == SubstLookupSubTable::Extension
))
1298 /* The spec says all subtables of an Extension lookup should
1299 * have the same type. This is specially important if one has
1300 * a reverse type! */
1301 unsigned int type
= get_subtable (0).u
.extension
.get_type ();
1302 unsigned int count
= get_subtable_count ();
1303 for (unsigned int i
= 1; i
< count
; i
++)
1304 if (get_subtable (i
).u
.extension
.get_type () != type
)
1305 return TRACE_RETURN (false);
1307 return TRACE_RETURN (true);
1311 typedef OffsetListOf
<SubstLookup
> SubstLookupList
;
1314 * GSUB -- The Glyph Substitution Table
1317 struct GSUB
: GSUBGPOS
1319 static const hb_tag_t tableTag
= HB_OT_TAG_GSUB
;
1321 inline const SubstLookup
& get_lookup (unsigned int i
) const
1322 { return CastR
<SubstLookup
> (GSUBGPOS::get_lookup (i
)); }
1324 static inline void substitute_start (hb_font_t
*font
, hb_buffer_t
*buffer
);
1325 static inline void substitute_finish (hb_font_t
*font
, hb_buffer_t
*buffer
);
1327 inline bool sanitize (hb_sanitize_context_t
*c
) {
1328 TRACE_SANITIZE (this);
1329 if (unlikely (!GSUBGPOS::sanitize (c
))) return TRACE_RETURN (false);
1330 OffsetTo
<SubstLookupList
> &list
= CastR
<OffsetTo
<SubstLookupList
> > (lookupList
);
1331 return TRACE_RETURN (list
.sanitize (c
, this));
1334 DEFINE_SIZE_STATIC (10);
1339 GSUB::substitute_start (hb_font_t
*font
, hb_buffer_t
*buffer
)
1341 _hb_buffer_assert_gsubgpos_vars (buffer
);
1343 const GDEF
&gdef
= *hb_ot_layout_from_face (font
->face
)->gdef
;
1344 unsigned int count
= buffer
->len
;
1345 for (unsigned int i
= 0; i
< count
; i
++)
1347 _hb_glyph_info_set_glyph_props (&buffer
->info
[i
], gdef
.get_glyph_props (buffer
->info
[i
].codepoint
));
1348 _hb_glyph_info_clear_lig_props (&buffer
->info
[i
]);
1349 buffer
->info
[i
].syllable() = 0;
1354 GSUB::substitute_finish (hb_font_t
*font HB_UNUSED
, hb_buffer_t
*buffer HB_UNUSED
)
1359 /* Out-of-class implementation for methods recursing */
1361 /*static*/ inline bool ExtensionSubst::is_reverse (void) const
1363 unsigned int type
= get_type ();
1364 if (unlikely (type
== SubstLookupSubTable::Extension
))
1365 return CastR
<ExtensionSubst
> (get_subtable
<SubstLookupSubTable
>()).is_reverse ();
1366 return SubstLookup::lookup_type_is_reverse (type
);
1369 template <typename context_t
>
1370 /*static*/ inline typename
context_t::return_t
SubstLookup::dispatch_recurse_func (context_t
*c
, unsigned int lookup_index
)
1372 const GSUB
&gsub
= *(hb_ot_layout_from_face (c
->face
)->gsub
);
1373 const SubstLookup
&l
= gsub
.get_lookup (lookup_index
);
1374 return l
.dispatch (c
);
1377 /*static*/ inline bool SubstLookup::apply_recurse_func (hb_apply_context_t
*c
, unsigned int lookup_index
)
1379 const GSUB
&gsub
= *(hb_ot_layout_from_face (c
->face
)->gsub
);
1380 const SubstLookup
&l
= gsub
.get_lookup (lookup_index
);
1381 unsigned int saved_lookup_props
= c
->lookup_props
;
1383 bool ret
= l
.apply_once (c
);
1384 c
->lookup_props
= saved_lookup_props
;
1389 } /* namespace OT */
1392 #endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */