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 for (unsigned int i
= 0; i
< count
; i
++) {
279 set_lig_props_for_component (c
->buffer
->cur(), i
);
280 c
->output_glyph (substitute
.array
[i
], klass
);
282 c
->buffer
->skip_glyph ();
284 return TRACE_RETURN (true);
287 inline bool serialize (hb_serialize_context_t
*c
,
288 Supplier
<GlyphID
> &glyphs
,
289 unsigned int num_glyphs
)
291 TRACE_SERIALIZE (this);
292 if (unlikely (!c
->extend_min (*this))) return TRACE_RETURN (false);
293 if (unlikely (!substitute
.serialize (c
, glyphs
, num_glyphs
))) return TRACE_RETURN (false);
294 return TRACE_RETURN (true);
297 inline bool sanitize (hb_sanitize_context_t
*c
) {
298 TRACE_SANITIZE (this);
299 return TRACE_RETURN (substitute
.sanitize (c
));
304 substitute
; /* String of GlyphIDs to substitute */
306 DEFINE_SIZE_ARRAY (2, substitute
);
309 struct MultipleSubstFormat1
311 inline void closure (hb_closure_context_t
*c
) const
313 TRACE_CLOSURE (this);
315 for (iter
.init (this+coverage
); iter
.more (); iter
.next ()) {
316 if (c
->glyphs
->has (iter
.get_glyph ()))
317 (this+sequence
[iter
.get_coverage ()]).closure (c
);
321 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
323 TRACE_COLLECT_GLYPHS (this);
324 (this+coverage
).add_coverage (c
->input
);
325 unsigned int count
= sequence
.len
;
326 for (unsigned int i
= 0; i
< count
; i
++)
327 (this+sequence
[i
]).collect_glyphs (c
);
330 inline const Coverage
&get_coverage (void) const
332 return this+coverage
;
335 inline bool would_apply (hb_would_apply_context_t
*c
) const
337 TRACE_WOULD_APPLY (this);
338 return TRACE_RETURN (c
->len
== 1 && (this+coverage
).get_coverage (c
->glyphs
[0]) != NOT_COVERED
);
341 inline bool apply (hb_apply_context_t
*c
) const
345 unsigned int index
= (this+coverage
).get_coverage (c
->buffer
->cur().codepoint
);
346 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
348 return TRACE_RETURN ((this+sequence
[index
]).apply (c
));
351 inline bool serialize (hb_serialize_context_t
*c
,
352 Supplier
<GlyphID
> &glyphs
,
353 Supplier
<unsigned int> &substitute_len_list
,
354 unsigned int num_glyphs
,
355 Supplier
<GlyphID
> &substitute_glyphs_list
)
357 TRACE_SERIALIZE (this);
358 if (unlikely (!c
->extend_min (*this))) return TRACE_RETURN (false);
359 if (unlikely (!sequence
.serialize (c
, num_glyphs
))) return TRACE_RETURN (false);
360 for (unsigned int i
= 0; i
< num_glyphs
; i
++)
361 if (unlikely (!sequence
[i
].serialize (c
, this).serialize (c
,
362 substitute_glyphs_list
,
363 substitute_len_list
[i
]))) return TRACE_RETURN (false);
364 substitute_len_list
.advance (num_glyphs
);
365 if (unlikely (!coverage
.serialize (c
, this).serialize (c
, glyphs
, num_glyphs
))) return TRACE_RETURN (false);
366 return TRACE_RETURN (true);
369 inline bool sanitize (hb_sanitize_context_t
*c
) {
370 TRACE_SANITIZE (this);
371 return TRACE_RETURN (coverage
.sanitize (c
, this) && sequence
.sanitize (c
, this));
375 USHORT format
; /* Format identifier--format = 1 */
377 coverage
; /* Offset to Coverage table--from
378 * beginning of Substitution table */
379 OffsetArrayOf
<Sequence
>
380 sequence
; /* Array of Sequence tables
381 * ordered by Coverage Index */
383 DEFINE_SIZE_ARRAY (6, sequence
);
388 inline bool serialize (hb_serialize_context_t
*c
,
389 Supplier
<GlyphID
> &glyphs
,
390 Supplier
<unsigned int> &substitute_len_list
,
391 unsigned int num_glyphs
,
392 Supplier
<GlyphID
> &substitute_glyphs_list
)
394 TRACE_SERIALIZE (this);
395 if (unlikely (!c
->extend_min (u
.format
))) return TRACE_RETURN (false);
396 unsigned int format
= 1;
397 u
.format
.set (format
);
399 case 1: return TRACE_RETURN (u
.format1
.serialize (c
, glyphs
, substitute_len_list
, num_glyphs
, substitute_glyphs_list
));
400 default:return TRACE_RETURN (false);
404 template <typename context_t
>
405 inline typename
context_t::return_t
dispatch (context_t
*c
) const
407 TRACE_DISPATCH (this);
409 case 1: return TRACE_RETURN (c
->dispatch (u
.format1
));
410 default:return TRACE_RETURN (c
->default_return_value ());
414 inline bool sanitize (hb_sanitize_context_t
*c
) {
415 TRACE_SANITIZE (this);
416 if (!u
.format
.sanitize (c
)) return TRACE_RETURN (false);
418 case 1: return TRACE_RETURN (u
.format1
.sanitize (c
));
419 default:return TRACE_RETURN (true);
425 USHORT format
; /* Format identifier */
426 MultipleSubstFormat1 format1
;
431 typedef ArrayOf
<GlyphID
> AlternateSet
; /* Array of alternate GlyphIDs--in
434 struct AlternateSubstFormat1
436 inline void closure (hb_closure_context_t
*c
) const
438 TRACE_CLOSURE (this);
440 for (iter
.init (this+coverage
); iter
.more (); iter
.next ()) {
441 if (c
->glyphs
->has (iter
.get_glyph ())) {
442 const AlternateSet
&alt_set
= this+alternateSet
[iter
.get_coverage ()];
443 unsigned int count
= alt_set
.len
;
444 for (unsigned int i
= 0; i
< count
; i
++)
445 c
->glyphs
->add (alt_set
[i
]);
450 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
452 TRACE_COLLECT_GLYPHS (this);
454 for (iter
.init (this+coverage
); iter
.more (); iter
.next ()) {
455 c
->input
->add (iter
.get_glyph ());
456 const AlternateSet
&alt_set
= this+alternateSet
[iter
.get_coverage ()];
457 unsigned int count
= alt_set
.len
;
458 for (unsigned int i
= 0; i
< count
; i
++)
459 c
->output
->add (alt_set
[i
]);
463 inline const Coverage
&get_coverage (void) const
465 return this+coverage
;
468 inline bool would_apply (hb_would_apply_context_t
*c
) const
470 TRACE_WOULD_APPLY (this);
471 return TRACE_RETURN (c
->len
== 1 && (this+coverage
).get_coverage (c
->glyphs
[0]) != NOT_COVERED
);
474 inline bool apply (hb_apply_context_t
*c
) const
477 hb_codepoint_t glyph_id
= c
->buffer
->cur().codepoint
;
479 unsigned int index
= (this+coverage
).get_coverage (glyph_id
);
480 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
482 const AlternateSet
&alt_set
= this+alternateSet
[index
];
484 if (unlikely (!alt_set
.len
)) return TRACE_RETURN (false);
486 hb_mask_t glyph_mask
= c
->buffer
->cur().mask
;
487 hb_mask_t lookup_mask
= c
->lookup_mask
;
489 /* Note: This breaks badly if two features enabled this lookup together. */
490 unsigned int shift
= _hb_ctz (lookup_mask
);
491 unsigned int alt_index
= ((lookup_mask
& glyph_mask
) >> shift
);
493 if (unlikely (alt_index
> alt_set
.len
|| alt_index
== 0)) return TRACE_RETURN (false);
495 glyph_id
= alt_set
[alt_index
- 1];
497 c
->replace_glyph (glyph_id
);
499 return TRACE_RETURN (true);
502 inline bool serialize (hb_serialize_context_t
*c
,
503 Supplier
<GlyphID
> &glyphs
,
504 Supplier
<unsigned int> &alternate_len_list
,
505 unsigned int num_glyphs
,
506 Supplier
<GlyphID
> &alternate_glyphs_list
)
508 TRACE_SERIALIZE (this);
509 if (unlikely (!c
->extend_min (*this))) return TRACE_RETURN (false);
510 if (unlikely (!alternateSet
.serialize (c
, num_glyphs
))) return TRACE_RETURN (false);
511 for (unsigned int i
= 0; i
< num_glyphs
; i
++)
512 if (unlikely (!alternateSet
[i
].serialize (c
, this).serialize (c
,
513 alternate_glyphs_list
,
514 alternate_len_list
[i
]))) return TRACE_RETURN (false);
515 alternate_len_list
.advance (num_glyphs
);
516 if (unlikely (!coverage
.serialize (c
, this).serialize (c
, glyphs
, num_glyphs
))) return TRACE_RETURN (false);
517 return TRACE_RETURN (true);
520 inline bool sanitize (hb_sanitize_context_t
*c
) {
521 TRACE_SANITIZE (this);
522 return TRACE_RETURN (coverage
.sanitize (c
, this) && alternateSet
.sanitize (c
, this));
526 USHORT format
; /* Format identifier--format = 1 */
528 coverage
; /* Offset to Coverage table--from
529 * beginning of Substitution table */
530 OffsetArrayOf
<AlternateSet
>
531 alternateSet
; /* Array of AlternateSet tables
532 * ordered by Coverage Index */
534 DEFINE_SIZE_ARRAY (6, alternateSet
);
537 struct AlternateSubst
539 inline bool serialize (hb_serialize_context_t
*c
,
540 Supplier
<GlyphID
> &glyphs
,
541 Supplier
<unsigned int> &alternate_len_list
,
542 unsigned int num_glyphs
,
543 Supplier
<GlyphID
> &alternate_glyphs_list
)
545 TRACE_SERIALIZE (this);
546 if (unlikely (!c
->extend_min (u
.format
))) return TRACE_RETURN (false);
547 unsigned int format
= 1;
548 u
.format
.set (format
);
550 case 1: return TRACE_RETURN (u
.format1
.serialize (c
, glyphs
, alternate_len_list
, num_glyphs
, alternate_glyphs_list
));
551 default:return TRACE_RETURN (false);
555 template <typename context_t
>
556 inline typename
context_t::return_t
dispatch (context_t
*c
) const
558 TRACE_DISPATCH (this);
560 case 1: return TRACE_RETURN (c
->dispatch (u
.format1
));
561 default:return TRACE_RETURN (c
->default_return_value ());
565 inline bool sanitize (hb_sanitize_context_t
*c
) {
566 TRACE_SANITIZE (this);
567 if (!u
.format
.sanitize (c
)) return TRACE_RETURN (false);
569 case 1: return TRACE_RETURN (u
.format1
.sanitize (c
));
570 default:return TRACE_RETURN (true);
576 USHORT format
; /* Format identifier */
577 AlternateSubstFormat1 format1
;
584 inline void closure (hb_closure_context_t
*c
) const
586 TRACE_CLOSURE (this);
587 unsigned int count
= component
.len
;
588 for (unsigned int i
= 1; i
< count
; i
++)
589 if (!c
->glyphs
->has (component
[i
]))
591 c
->glyphs
->add (ligGlyph
);
594 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
596 TRACE_COLLECT_GLYPHS (this);
597 unsigned int count
= component
.len
;
598 for (unsigned int i
= 1; i
< count
; i
++)
599 c
->input
->add (component
[i
]);
600 c
->output
->add (ligGlyph
);
603 inline bool would_apply (hb_would_apply_context_t
*c
) const
605 TRACE_WOULD_APPLY (this);
606 if (c
->len
!= component
.len
)
607 return TRACE_RETURN (false);
609 for (unsigned int i
= 1; i
< c
->len
; i
++)
610 if (likely (c
->glyphs
[i
] != component
[i
]))
611 return TRACE_RETURN (false);
613 return TRACE_RETURN (true);
616 inline bool apply (hb_apply_context_t
*c
) const
619 unsigned int count
= component
.len
;
620 if (unlikely (count
< 1)) return TRACE_RETURN (false);
622 unsigned int end_offset
= 0;
623 bool is_mark_ligature
= false;
624 unsigned int total_component_count
= 0;
626 if (likely (!match_input (c
, count
,
632 &total_component_count
)))
633 return TRACE_RETURN (false);
635 /* Deal, we are forming the ligature. */
636 c
->buffer
->merge_clusters (c
->buffer
->idx
, c
->buffer
->idx
+ end_offset
);
645 total_component_count
);
647 return TRACE_RETURN (true);
650 inline bool serialize (hb_serialize_context_t
*c
,
652 Supplier
<GlyphID
> &components
, /* Starting from second */
653 unsigned int num_components
/* Including first component */)
655 TRACE_SERIALIZE (this);
656 if (unlikely (!c
->extend_min (*this))) return TRACE_RETURN (false);
658 if (unlikely (!component
.serialize (c
, components
, num_components
))) return TRACE_RETURN (false);
659 return TRACE_RETURN (true);
663 inline bool sanitize (hb_sanitize_context_t
*c
) {
664 TRACE_SANITIZE (this);
665 return TRACE_RETURN (ligGlyph
.sanitize (c
) && component
.sanitize (c
));
669 GlyphID ligGlyph
; /* GlyphID of ligature to substitute */
670 HeadlessArrayOf
<GlyphID
>
671 component
; /* Array of component GlyphIDs--start
672 * with the second component--ordered
673 * in writing direction */
675 DEFINE_SIZE_ARRAY (4, component
);
680 inline void closure (hb_closure_context_t
*c
) const
682 TRACE_CLOSURE (this);
683 unsigned int num_ligs
= ligature
.len
;
684 for (unsigned int i
= 0; i
< num_ligs
; i
++)
685 (this+ligature
[i
]).closure (c
);
688 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
690 TRACE_COLLECT_GLYPHS (this);
691 unsigned int num_ligs
= ligature
.len
;
692 for (unsigned int i
= 0; i
< num_ligs
; i
++)
693 (this+ligature
[i
]).collect_glyphs (c
);
696 inline bool would_apply (hb_would_apply_context_t
*c
) const
698 TRACE_WOULD_APPLY (this);
699 unsigned int num_ligs
= ligature
.len
;
700 for (unsigned int i
= 0; i
< num_ligs
; i
++)
702 const Ligature
&lig
= this+ligature
[i
];
703 if (lig
.would_apply (c
))
704 return TRACE_RETURN (true);
706 return TRACE_RETURN (false);
709 inline bool apply (hb_apply_context_t
*c
) const
712 unsigned int num_ligs
= ligature
.len
;
713 for (unsigned int i
= 0; i
< num_ligs
; i
++)
715 const Ligature
&lig
= this+ligature
[i
];
716 if (lig
.apply (c
)) return TRACE_RETURN (true);
719 return TRACE_RETURN (false);
722 inline bool serialize (hb_serialize_context_t
*c
,
723 Supplier
<GlyphID
> &ligatures
,
724 Supplier
<unsigned int> &component_count_list
,
725 unsigned int num_ligatures
,
726 Supplier
<GlyphID
> &component_list
/* Starting from second for each ligature */)
728 TRACE_SERIALIZE (this);
729 if (unlikely (!c
->extend_min (*this))) return TRACE_RETURN (false);
730 if (unlikely (!ligature
.serialize (c
, num_ligatures
))) return TRACE_RETURN (false);
731 for (unsigned int i
= 0; i
< num_ligatures
; i
++)
732 if (unlikely (!ligature
[i
].serialize (c
, this).serialize (c
,
735 component_count_list
[i
]))) return TRACE_RETURN (false);
736 ligatures
.advance (num_ligatures
);
737 component_count_list
.advance (num_ligatures
);
738 return TRACE_RETURN (true);
741 inline bool sanitize (hb_sanitize_context_t
*c
) {
742 TRACE_SANITIZE (this);
743 return TRACE_RETURN (ligature
.sanitize (c
, this));
747 OffsetArrayOf
<Ligature
>
748 ligature
; /* Array LigatureSet tables
749 * ordered by preference */
751 DEFINE_SIZE_ARRAY (2, ligature
);
754 struct LigatureSubstFormat1
756 inline void closure (hb_closure_context_t
*c
) const
758 TRACE_CLOSURE (this);
760 for (iter
.init (this+coverage
); iter
.more (); iter
.next ()) {
761 if (c
->glyphs
->has (iter
.get_glyph ()))
762 (this+ligatureSet
[iter
.get_coverage ()]).closure (c
);
766 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
768 TRACE_COLLECT_GLYPHS (this);
770 for (iter
.init (this+coverage
); iter
.more (); iter
.next ()) {
771 c
->input
->add (iter
.get_glyph ());
772 (this+ligatureSet
[iter
.get_coverage ()]).collect_glyphs (c
);
776 inline const Coverage
&get_coverage (void) const
778 return this+coverage
;
781 inline bool would_apply (hb_would_apply_context_t
*c
) const
783 TRACE_WOULD_APPLY (this);
784 unsigned int index
= (this+coverage
).get_coverage (c
->glyphs
[0]);
785 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
787 const LigatureSet
&lig_set
= this+ligatureSet
[index
];
788 return TRACE_RETURN (lig_set
.would_apply (c
));
791 inline bool apply (hb_apply_context_t
*c
) const
794 hb_codepoint_t glyph_id
= c
->buffer
->cur().codepoint
;
796 unsigned int index
= (this+coverage
).get_coverage (glyph_id
);
797 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
799 const LigatureSet
&lig_set
= this+ligatureSet
[index
];
800 return TRACE_RETURN (lig_set
.apply (c
));
803 inline bool serialize (hb_serialize_context_t
*c
,
804 Supplier
<GlyphID
> &first_glyphs
,
805 Supplier
<unsigned int> &ligature_per_first_glyph_count_list
,
806 unsigned int num_first_glyphs
,
807 Supplier
<GlyphID
> &ligatures_list
,
808 Supplier
<unsigned int> &component_count_list
,
809 Supplier
<GlyphID
> &component_list
/* Starting from second for each ligature */)
811 TRACE_SERIALIZE (this);
812 if (unlikely (!c
->extend_min (*this))) return TRACE_RETURN (false);
813 if (unlikely (!ligatureSet
.serialize (c
, num_first_glyphs
))) return TRACE_RETURN (false);
814 for (unsigned int i
= 0; i
< num_first_glyphs
; i
++)
815 if (unlikely (!ligatureSet
[i
].serialize (c
, this).serialize (c
,
817 component_count_list
,
818 ligature_per_first_glyph_count_list
[i
],
819 component_list
))) return TRACE_RETURN (false);
820 ligature_per_first_glyph_count_list
.advance (num_first_glyphs
);
821 if (unlikely (!coverage
.serialize (c
, this).serialize (c
, first_glyphs
, num_first_glyphs
))) return TRACE_RETURN (false);
822 return TRACE_RETURN (true);
825 inline bool sanitize (hb_sanitize_context_t
*c
) {
826 TRACE_SANITIZE (this);
827 return TRACE_RETURN (coverage
.sanitize (c
, this) && ligatureSet
.sanitize (c
, this));
831 USHORT format
; /* Format identifier--format = 1 */
833 coverage
; /* Offset to Coverage table--from
834 * beginning of Substitution table */
835 OffsetArrayOf
<LigatureSet
>
836 ligatureSet
; /* Array LigatureSet tables
837 * ordered by Coverage Index */
839 DEFINE_SIZE_ARRAY (6, ligatureSet
);
844 inline bool serialize (hb_serialize_context_t
*c
,
845 Supplier
<GlyphID
> &first_glyphs
,
846 Supplier
<unsigned int> &ligature_per_first_glyph_count_list
,
847 unsigned int num_first_glyphs
,
848 Supplier
<GlyphID
> &ligatures_list
,
849 Supplier
<unsigned int> &component_count_list
,
850 Supplier
<GlyphID
> &component_list
/* Starting from second for each ligature */)
852 TRACE_SERIALIZE (this);
853 if (unlikely (!c
->extend_min (u
.format
))) return TRACE_RETURN (false);
854 unsigned int format
= 1;
855 u
.format
.set (format
);
857 case 1: return TRACE_RETURN (u
.format1
.serialize (c
, first_glyphs
, ligature_per_first_glyph_count_list
, num_first_glyphs
,
858 ligatures_list
, component_count_list
, component_list
));
859 default:return TRACE_RETURN (false);
863 template <typename context_t
>
864 inline typename
context_t::return_t
dispatch (context_t
*c
) const
866 TRACE_DISPATCH (this);
868 case 1: return TRACE_RETURN (c
->dispatch (u
.format1
));
869 default:return TRACE_RETURN (c
->default_return_value ());
873 inline bool sanitize (hb_sanitize_context_t
*c
) {
874 TRACE_SANITIZE (this);
875 if (!u
.format
.sanitize (c
)) return TRACE_RETURN (false);
877 case 1: return TRACE_RETURN (u
.format1
.sanitize (c
));
878 default:return TRACE_RETURN (true);
884 USHORT format
; /* Format identifier */
885 LigatureSubstFormat1 format1
;
890 struct ContextSubst
: Context
{};
892 struct ChainContextSubst
: ChainContext
{};
894 struct ExtensionSubst
: Extension
<ExtensionSubst
>
896 typedef struct SubstLookupSubTable LookupSubTable
;
898 inline bool is_reverse (void) const;
902 struct ReverseChainSingleSubstFormat1
904 inline void closure (hb_closure_context_t
*c
) const
906 TRACE_CLOSURE (this);
907 const OffsetArrayOf
<Coverage
> &lookahead
= StructAfter
<OffsetArrayOf
<Coverage
> > (backtrack
);
911 count
= backtrack
.len
;
912 for (unsigned int i
= 0; i
< count
; i
++)
913 if (!(this+backtrack
[i
]).intersects (c
->glyphs
))
916 count
= lookahead
.len
;
917 for (unsigned int i
= 0; i
< count
; i
++)
918 if (!(this+lookahead
[i
]).intersects (c
->glyphs
))
921 const ArrayOf
<GlyphID
> &substitute
= StructAfter
<ArrayOf
<GlyphID
> > (lookahead
);
923 for (iter
.init (this+coverage
); iter
.more (); iter
.next ()) {
924 if (c
->glyphs
->has (iter
.get_glyph ()))
925 c
->glyphs
->add (substitute
[iter
.get_coverage ()]);
929 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
931 TRACE_COLLECT_GLYPHS (this);
933 const OffsetArrayOf
<Coverage
> &lookahead
= StructAfter
<OffsetArrayOf
<Coverage
> > (backtrack
);
937 (this+coverage
).add_coverage (c
->input
);
939 count
= backtrack
.len
;
940 for (unsigned int i
= 0; i
< count
; i
++)
941 (this+backtrack
[i
]).add_coverage (c
->before
);
943 count
= lookahead
.len
;
944 for (unsigned int i
= 0; i
< count
; i
++)
945 (this+lookahead
[i
]).add_coverage (c
->after
);
947 const ArrayOf
<GlyphID
> &substitute
= StructAfter
<ArrayOf
<GlyphID
> > (lookahead
);
948 count
= substitute
.len
;
949 for (unsigned int i
= 0; i
< count
; i
++)
950 c
->output
->add (substitute
[i
]);
953 inline const Coverage
&get_coverage (void) const
955 return this+coverage
;
958 inline bool would_apply (hb_would_apply_context_t
*c
) const
960 TRACE_WOULD_APPLY (this);
961 return TRACE_RETURN (c
->len
== 1 && (this+coverage
).get_coverage (c
->glyphs
[0]) != NOT_COVERED
);
964 inline bool apply (hb_apply_context_t
*c
) const
967 if (unlikely (c
->nesting_level_left
!= MAX_NESTING_LEVEL
))
968 return TRACE_RETURN (false); /* No chaining to this type */
970 unsigned int index
= (this+coverage
).get_coverage (c
->buffer
->cur().codepoint
);
971 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
973 const OffsetArrayOf
<Coverage
> &lookahead
= StructAfter
<OffsetArrayOf
<Coverage
> > (backtrack
);
974 const ArrayOf
<GlyphID
> &substitute
= StructAfter
<ArrayOf
<GlyphID
> > (lookahead
);
976 if (match_backtrack (c
,
977 backtrack
.len
, (USHORT
*) backtrack
.array
,
978 match_coverage
, this) &&
980 lookahead
.len
, (USHORT
*) lookahead
.array
,
981 match_coverage
, this,
984 c
->replace_glyph_inplace (substitute
[index
]);
985 c
->buffer
->idx
--; /* Reverse! */
986 return TRACE_RETURN (true);
989 return TRACE_RETURN (false);
992 inline bool sanitize (hb_sanitize_context_t
*c
) {
993 TRACE_SANITIZE (this);
994 if (!(coverage
.sanitize (c
, this) && backtrack
.sanitize (c
, this)))
995 return TRACE_RETURN (false);
996 OffsetArrayOf
<Coverage
> &lookahead
= StructAfter
<OffsetArrayOf
<Coverage
> > (backtrack
);
997 if (!lookahead
.sanitize (c
, this))
998 return TRACE_RETURN (false);
999 ArrayOf
<GlyphID
> &substitute
= StructAfter
<ArrayOf
<GlyphID
> > (lookahead
);
1000 return TRACE_RETURN (substitute
.sanitize (c
));
1004 USHORT format
; /* Format identifier--format = 1 */
1006 coverage
; /* Offset to Coverage table--from
1007 * beginning of table */
1008 OffsetArrayOf
<Coverage
>
1009 backtrack
; /* Array of coverage tables
1010 * in backtracking sequence, in glyph
1012 OffsetArrayOf
<Coverage
>
1013 lookaheadX
; /* Array of coverage tables
1014 * in lookahead sequence, in glyph
1017 substituteX
; /* Array of substitute
1018 * GlyphIDs--ordered by Coverage Index */
1020 DEFINE_SIZE_MIN (10);
1023 struct ReverseChainSingleSubst
1025 template <typename context_t
>
1026 inline typename
context_t::return_t
dispatch (context_t
*c
) const
1028 TRACE_DISPATCH (this);
1030 case 1: return TRACE_RETURN (c
->dispatch (u
.format1
));
1031 default:return TRACE_RETURN (c
->default_return_value ());
1035 inline bool sanitize (hb_sanitize_context_t
*c
) {
1036 TRACE_SANITIZE (this);
1037 if (!u
.format
.sanitize (c
)) return TRACE_RETURN (false);
1039 case 1: return TRACE_RETURN (u
.format1
.sanitize (c
));
1040 default:return TRACE_RETURN (true);
1046 USHORT format
; /* Format identifier */
1047 ReverseChainSingleSubstFormat1 format1
;
1057 struct SubstLookupSubTable
1059 friend struct SubstLookup
;
1069 ReverseChainSingle
= 8
1072 template <typename context_t
>
1073 inline typename
context_t::return_t
dispatch (context_t
*c
, unsigned int lookup_type
) const
1075 TRACE_DISPATCH (this);
1076 switch (lookup_type
) {
1077 case Single
: return TRACE_RETURN (u
.single
.dispatch (c
));
1078 case Multiple
: return TRACE_RETURN (u
.multiple
.dispatch (c
));
1079 case Alternate
: return TRACE_RETURN (u
.alternate
.dispatch (c
));
1080 case Ligature
: return TRACE_RETURN (u
.ligature
.dispatch (c
));
1081 case Context
: return TRACE_RETURN (u
.context
.dispatch (c
));
1082 case ChainContext
: return TRACE_RETURN (u
.chainContext
.dispatch (c
));
1083 case Extension
: return TRACE_RETURN (u
.extension
.dispatch (c
));
1084 case ReverseChainSingle
: return TRACE_RETURN (u
.reverseChainContextSingle
.dispatch (c
));
1085 default: return TRACE_RETURN (c
->default_return_value ());
1089 inline bool sanitize (hb_sanitize_context_t
*c
, unsigned int lookup_type
) {
1090 TRACE_SANITIZE (this);
1091 if (!u
.header
.sub_format
.sanitize (c
))
1092 return TRACE_RETURN (false);
1093 switch (lookup_type
) {
1094 case Single
: return TRACE_RETURN (u
.single
.sanitize (c
));
1095 case Multiple
: return TRACE_RETURN (u
.multiple
.sanitize (c
));
1096 case Alternate
: return TRACE_RETURN (u
.alternate
.sanitize (c
));
1097 case Ligature
: return TRACE_RETURN (u
.ligature
.sanitize (c
));
1098 case Context
: return TRACE_RETURN (u
.context
.sanitize (c
));
1099 case ChainContext
: return TRACE_RETURN (u
.chainContext
.sanitize (c
));
1100 case Extension
: return TRACE_RETURN (u
.extension
.sanitize (c
));
1101 case ReverseChainSingle
: return TRACE_RETURN (u
.reverseChainContextSingle
.sanitize (c
));
1102 default: return TRACE_RETURN (true);
1112 MultipleSubst multiple
;
1113 AlternateSubst alternate
;
1114 LigatureSubst ligature
;
1115 ContextSubst context
;
1116 ChainContextSubst chainContext
;
1117 ExtensionSubst extension
;
1118 ReverseChainSingleSubst reverseChainContextSingle
;
1121 DEFINE_SIZE_UNION (2, header
.sub_format
);
1125 struct SubstLookup
: Lookup
1127 inline const SubstLookupSubTable
& get_subtable (unsigned int i
) const
1128 { return this+CastR
<OffsetArrayOf
<SubstLookupSubTable
> > (subTable
)[i
]; }
1130 inline static bool lookup_type_is_reverse (unsigned int lookup_type
)
1131 { return lookup_type
== SubstLookupSubTable::ReverseChainSingle
; }
1133 inline bool is_reverse (void) const
1135 unsigned int type
= get_type ();
1136 if (unlikely (type
== SubstLookupSubTable::Extension
))
1137 return CastR
<ExtensionSubst
> (get_subtable(0)).is_reverse ();
1138 return lookup_type_is_reverse (type
);
1141 inline hb_closure_context_t::return_t
closure (hb_closure_context_t
*c
) const
1143 TRACE_CLOSURE (this);
1144 c
->set_recurse_func (dispatch_recurse_func
<hb_closure_context_t
>);
1145 return TRACE_RETURN (dispatch (c
));
1148 inline hb_collect_glyphs_context_t::return_t
collect_glyphs_lookup (hb_collect_glyphs_context_t
*c
) const
1150 TRACE_COLLECT_GLYPHS (this);
1151 c
->set_recurse_func (dispatch_recurse_func
<hb_collect_glyphs_context_t
>);
1152 return TRACE_RETURN (dispatch (c
));
1155 template <typename set_t
>
1156 inline void add_coverage (set_t
*glyphs
) const
1158 hb_get_coverage_context_t c
;
1159 const Coverage
*last
= NULL
;
1160 unsigned int count
= get_subtable_count ();
1161 for (unsigned int i
= 0; i
< count
; i
++) {
1162 const Coverage
*coverage
= &get_subtable (i
).dispatch (&c
, get_type ());
1163 if (coverage
!= last
) {
1164 coverage
->add_coverage (glyphs
);
1170 inline bool would_apply (hb_would_apply_context_t
*c
, const hb_set_digest_t
*digest
) const
1172 TRACE_WOULD_APPLY (this);
1173 if (unlikely (!c
->len
)) return TRACE_RETURN (false);
1174 if (!digest
->may_have (c
->glyphs
[0])) return TRACE_RETURN (false);
1175 return TRACE_RETURN (dispatch (c
));
1178 inline bool apply_once (hb_apply_context_t
*c
) const
1181 if (!c
->check_glyph_property (&c
->buffer
->cur(), c
->lookup_props
))
1182 return TRACE_RETURN (false);
1183 return TRACE_RETURN (dispatch (c
));
1186 static bool apply_recurse_func (hb_apply_context_t
*c
, unsigned int lookup_index
);
1187 inline bool apply_string (hb_apply_context_t
*c
, const hb_set_digest_t
*digest
) const
1191 if (unlikely (!c
->buffer
->len
|| !c
->lookup_mask
))
1194 c
->set_recurse_func (apply_recurse_func
);
1195 c
->set_lookup (*this);
1197 if (likely (!is_reverse ()))
1199 /* in/out forward substitution */
1200 c
->buffer
->clear_output ();
1203 while (c
->buffer
->idx
< c
->buffer
->len
)
1205 if ((c
->buffer
->cur().mask
& c
->lookup_mask
) &&
1206 digest
->may_have (c
->buffer
->cur().codepoint
) &&
1210 c
->buffer
->next_glyph ();
1213 c
->buffer
->swap_buffers ();
1217 /* in-place backward substitution */
1218 c
->buffer
->remove_output ();
1219 c
->buffer
->idx
= c
->buffer
->len
- 1;
1222 if ((c
->buffer
->cur().mask
& c
->lookup_mask
) &&
1223 digest
->may_have (c
->buffer
->cur().codepoint
) &&
1230 while ((int) c
->buffer
->idx
>= 0);
1236 inline SubstLookupSubTable
& serialize_subtable (hb_serialize_context_t
*c
,
1238 { return CastR
<OffsetArrayOf
<SubstLookupSubTable
> > (subTable
)[i
].serialize (c
, this); }
1240 inline bool serialize_single (hb_serialize_context_t
*c
,
1241 uint32_t lookup_props
,
1242 Supplier
<GlyphID
> &glyphs
,
1243 Supplier
<GlyphID
> &substitutes
,
1244 unsigned int num_glyphs
)
1246 TRACE_SERIALIZE (this);
1247 if (unlikely (!Lookup::serialize (c
, SubstLookupSubTable::Single
, lookup_props
, 1))) return TRACE_RETURN (false);
1248 return TRACE_RETURN (serialize_subtable (c
, 0).u
.single
.serialize (c
, glyphs
, substitutes
, num_glyphs
));
1251 inline bool serialize_multiple (hb_serialize_context_t
*c
,
1252 uint32_t lookup_props
,
1253 Supplier
<GlyphID
> &glyphs
,
1254 Supplier
<unsigned int> &substitute_len_list
,
1255 unsigned int num_glyphs
,
1256 Supplier
<GlyphID
> &substitute_glyphs_list
)
1258 TRACE_SERIALIZE (this);
1259 if (unlikely (!Lookup::serialize (c
, SubstLookupSubTable::Multiple
, lookup_props
, 1))) return TRACE_RETURN (false);
1260 return TRACE_RETURN (serialize_subtable (c
, 0).u
.multiple
.serialize (c
, glyphs
, substitute_len_list
, num_glyphs
,
1261 substitute_glyphs_list
));
1264 inline bool serialize_alternate (hb_serialize_context_t
*c
,
1265 uint32_t lookup_props
,
1266 Supplier
<GlyphID
> &glyphs
,
1267 Supplier
<unsigned int> &alternate_len_list
,
1268 unsigned int num_glyphs
,
1269 Supplier
<GlyphID
> &alternate_glyphs_list
)
1271 TRACE_SERIALIZE (this);
1272 if (unlikely (!Lookup::serialize (c
, SubstLookupSubTable::Alternate
, lookup_props
, 1))) return TRACE_RETURN (false);
1273 return TRACE_RETURN (serialize_subtable (c
, 0).u
.alternate
.serialize (c
, glyphs
, alternate_len_list
, num_glyphs
,
1274 alternate_glyphs_list
));
1277 inline bool serialize_ligature (hb_serialize_context_t
*c
,
1278 uint32_t lookup_props
,
1279 Supplier
<GlyphID
> &first_glyphs
,
1280 Supplier
<unsigned int> &ligature_per_first_glyph_count_list
,
1281 unsigned int num_first_glyphs
,
1282 Supplier
<GlyphID
> &ligatures_list
,
1283 Supplier
<unsigned int> &component_count_list
,
1284 Supplier
<GlyphID
> &component_list
/* Starting from second for each ligature */)
1286 TRACE_SERIALIZE (this);
1287 if (unlikely (!Lookup::serialize (c
, SubstLookupSubTable::Ligature
, lookup_props
, 1))) return TRACE_RETURN (false);
1288 return TRACE_RETURN (serialize_subtable (c
, 0).u
.ligature
.serialize (c
, first_glyphs
, ligature_per_first_glyph_count_list
, num_first_glyphs
,
1289 ligatures_list
, component_count_list
, component_list
));
1292 template <typename context_t
>
1293 static inline typename
context_t::return_t
dispatch_recurse_func (context_t
*c
, unsigned int lookup_index
);
1295 template <typename context_t
>
1296 inline typename
context_t::return_t
dispatch (context_t
*c
) const
1298 TRACE_DISPATCH (this);
1299 unsigned int lookup_type
= get_type ();
1300 unsigned int count
= get_subtable_count ();
1301 for (unsigned int i
= 0; i
< count
; i
++) {
1302 typename
context_t::return_t r
= get_subtable (i
).dispatch (c
, lookup_type
);
1303 if (c
->stop_sublookup_iteration (r
))
1304 return TRACE_RETURN (r
);
1306 return TRACE_RETURN (c
->default_return_value ());
1309 inline bool sanitize (hb_sanitize_context_t
*c
)
1311 TRACE_SANITIZE (this);
1312 if (unlikely (!Lookup::sanitize (c
))) return TRACE_RETURN (false);
1313 OffsetArrayOf
<SubstLookupSubTable
> &list
= CastR
<OffsetArrayOf
<SubstLookupSubTable
> > (subTable
);
1314 if (unlikely (!list
.sanitize (c
, this, get_type ()))) return TRACE_RETURN (false);
1316 if (unlikely (get_type () == SubstLookupSubTable::Extension
))
1318 /* The spec says all subtables of an Extension lookup should
1319 * have the same type. This is specially important if one has
1320 * a reverse type! */
1321 unsigned int type
= get_subtable (0).u
.extension
.get_type ();
1322 unsigned int count
= get_subtable_count ();
1323 for (unsigned int i
= 1; i
< count
; i
++)
1324 if (get_subtable (i
).u
.extension
.get_type () != type
)
1325 return TRACE_RETURN (false);
1327 return TRACE_RETURN (true);
1331 typedef OffsetListOf
<SubstLookup
> SubstLookupList
;
1334 * GSUB -- The Glyph Substitution Table
1337 struct GSUB
: GSUBGPOS
1339 static const hb_tag_t Tag
= HB_OT_TAG_GSUB
;
1341 inline const SubstLookup
& get_lookup (unsigned int i
) const
1342 { return CastR
<SubstLookup
> (GSUBGPOS::get_lookup (i
)); }
1344 static inline void substitute_start (hb_font_t
*font
, hb_buffer_t
*buffer
);
1345 static inline void substitute_finish (hb_font_t
*font
, hb_buffer_t
*buffer
);
1347 inline bool sanitize (hb_sanitize_context_t
*c
) {
1348 TRACE_SANITIZE (this);
1349 if (unlikely (!GSUBGPOS::sanitize (c
))) return TRACE_RETURN (false);
1350 OffsetTo
<SubstLookupList
> &list
= CastR
<OffsetTo
<SubstLookupList
> > (lookupList
);
1351 return TRACE_RETURN (list
.sanitize (c
, this));
1354 DEFINE_SIZE_STATIC (10);
1359 GSUB::substitute_start (hb_font_t
*font
, hb_buffer_t
*buffer
)
1361 HB_BUFFER_ALLOCATE_VAR (buffer
, glyph_props
);
1362 HB_BUFFER_ALLOCATE_VAR (buffer
, lig_props
);
1363 HB_BUFFER_ALLOCATE_VAR (buffer
, syllable
);
1365 const GDEF
&gdef
= *hb_ot_layout_from_face (font
->face
)->gdef
;
1366 unsigned int count
= buffer
->len
;
1367 for (unsigned int i
= 0; i
< count
; i
++) {
1368 buffer
->info
[i
].lig_props() = buffer
->info
[i
].syllable() = 0;
1369 buffer
->info
[i
].glyph_props() = gdef
.get_glyph_props (buffer
->info
[i
].codepoint
);
1374 GSUB::substitute_finish (hb_font_t
*font HB_UNUSED
, hb_buffer_t
*buffer HB_UNUSED
)
1379 /* Out-of-class implementation for methods recursing */
1381 inline bool ExtensionSubst::is_reverse (void) const
1383 unsigned int type
= get_type ();
1384 if (unlikely (type
== SubstLookupSubTable::Extension
))
1385 return CastR
<ExtensionSubst
> (get_subtable
<SubstLookupSubTable
>()).is_reverse ();
1386 return SubstLookup::lookup_type_is_reverse (type
);
1389 template <typename context_t
>
1390 inline typename
context_t::return_t
SubstLookup::dispatch_recurse_func (context_t
*c
, unsigned int lookup_index
)
1392 const GSUB
&gsub
= *(hb_ot_layout_from_face (c
->face
)->gsub
);
1393 const SubstLookup
&l
= gsub
.get_lookup (lookup_index
);
1394 return l
.dispatch (c
);
1397 inline bool SubstLookup::apply_recurse_func (hb_apply_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 unsigned int saved_lookup_props
= c
->lookup_props
;
1403 bool ret
= l
.apply_once (c
);
1404 c
->lookup_props
= saved_lookup_props
;
1409 } /* namespace OT */
1412 #endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */