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
) const
102 TRACE_SANITIZE (this);
103 return TRACE_RETURN (coverage
.sanitize (c
, this) && deltaGlyphID
.sanitize (c
));
107 USHORT format
; /* Format identifier--format = 1 */
109 coverage
; /* Offset to Coverage table--from
110 * beginning of Substitution table */
111 SHORT deltaGlyphID
; /* Add to original GlyphID to get
112 * substitute GlyphID */
114 DEFINE_SIZE_STATIC (6);
117 struct SingleSubstFormat2
119 inline void closure (hb_closure_context_t
*c
) const
121 TRACE_CLOSURE (this);
123 for (iter
.init (this+coverage
); iter
.more (); iter
.next ()) {
124 if (c
->glyphs
->has (iter
.get_glyph ()))
125 c
->glyphs
->add (substitute
[iter
.get_coverage ()]);
129 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
131 TRACE_COLLECT_GLYPHS (this);
133 for (iter
.init (this+coverage
); iter
.more (); iter
.next ()) {
134 c
->input
->add (iter
.get_glyph ());
135 c
->output
->add (substitute
[iter
.get_coverage ()]);
139 inline const Coverage
&get_coverage (void) const
141 return this+coverage
;
144 inline bool would_apply (hb_would_apply_context_t
*c
) const
146 TRACE_WOULD_APPLY (this);
147 return TRACE_RETURN (c
->len
== 1 && (this+coverage
).get_coverage (c
->glyphs
[0]) != NOT_COVERED
);
150 inline bool apply (hb_apply_context_t
*c
) const
153 hb_codepoint_t glyph_id
= c
->buffer
->cur().codepoint
;
154 unsigned int index
= (this+coverage
).get_coverage (glyph_id
);
155 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
157 if (unlikely (index
>= substitute
.len
)) return TRACE_RETURN (false);
159 glyph_id
= substitute
[index
];
160 c
->replace_glyph (glyph_id
);
162 return TRACE_RETURN (true);
165 inline bool serialize (hb_serialize_context_t
*c
,
166 Supplier
<GlyphID
> &glyphs
,
167 Supplier
<GlyphID
> &substitutes
,
168 unsigned int num_glyphs
)
170 TRACE_SERIALIZE (this);
171 if (unlikely (!c
->extend_min (*this))) return TRACE_RETURN (false);
172 if (unlikely (!substitute
.serialize (c
, substitutes
, num_glyphs
))) return TRACE_RETURN (false);
173 if (unlikely (!coverage
.serialize (c
, this).serialize (c
, glyphs
, num_glyphs
))) return TRACE_RETURN (false);
174 return TRACE_RETURN (true);
177 inline bool sanitize (hb_sanitize_context_t
*c
) const
179 TRACE_SANITIZE (this);
180 return TRACE_RETURN (coverage
.sanitize (c
, this) && substitute
.sanitize (c
));
184 USHORT format
; /* Format identifier--format = 2 */
186 coverage
; /* Offset to Coverage table--from
187 * beginning of Substitution table */
189 substitute
; /* Array of substitute
190 * GlyphIDs--ordered by Coverage Index */
192 DEFINE_SIZE_ARRAY (6, substitute
);
197 inline bool serialize (hb_serialize_context_t
*c
,
198 Supplier
<GlyphID
> &glyphs
,
199 Supplier
<GlyphID
> &substitutes
,
200 unsigned int num_glyphs
)
202 TRACE_SERIALIZE (this);
203 if (unlikely (!c
->extend_min (u
.format
))) return TRACE_RETURN (false);
204 unsigned int format
= 2;
208 /* TODO(serialize) check for wrap-around */
209 delta
= substitutes
[0] - glyphs
[0];
210 for (unsigned int i
= 1; i
< num_glyphs
; i
++)
211 if (delta
!= substitutes
[i
] - glyphs
[i
]) {
216 u
.format
.set (format
);
218 case 1: return TRACE_RETURN (u
.format1
.serialize (c
, glyphs
, num_glyphs
, delta
));
219 case 2: return TRACE_RETURN (u
.format2
.serialize (c
, glyphs
, substitutes
, num_glyphs
));
220 default:return TRACE_RETURN (false);
224 template <typename context_t
>
225 inline typename
context_t::return_t
dispatch (context_t
*c
) const
227 TRACE_DISPATCH (this, u
.format
);
228 if (unlikely (!c
->may_dispatch (this, &u
.format
))) TRACE_RETURN (c
->default_return_value ());
230 case 1: return TRACE_RETURN (c
->dispatch (u
.format1
));
231 case 2: return TRACE_RETURN (c
->dispatch (u
.format2
));
232 default:return TRACE_RETURN (c
->default_return_value ());
238 USHORT format
; /* Format identifier */
239 SingleSubstFormat1 format1
;
240 SingleSubstFormat2 format2
;
247 inline void closure (hb_closure_context_t
*c
) const
249 TRACE_CLOSURE (this);
250 unsigned int count
= substitute
.len
;
251 for (unsigned int i
= 0; i
< count
; i
++)
252 c
->glyphs
->add (substitute
[i
]);
255 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
257 TRACE_COLLECT_GLYPHS (this);
258 unsigned int count
= substitute
.len
;
259 for (unsigned int i
= 0; i
< count
; i
++)
260 c
->output
->add (substitute
[i
]);
263 inline bool apply (hb_apply_context_t
*c
) const
266 unsigned int count
= substitute
.len
;
269 * Testing shows that Uniscribe actually allows zero-len susbstitute,
270 * which essentially deletes a glyph. We don't allow for now. It
271 * can be confusing to the client since the cluster from the deleted
272 * glyph won't be merged with any output cluster... Also, currently
273 * buffer->move_to() makes assumptions about this too. Perhaps fix
274 * in the future after figuring out what to do with the clusters.
276 if (unlikely (!count
)) return TRACE_RETURN (false);
278 /* Special-case to make it in-place and not consider this
279 * as a "multiplied" substitution. */
280 if (unlikely (count
== 1))
282 c
->replace_glyph (substitute
.array
[0]);
283 return TRACE_RETURN (true);
286 unsigned int klass
= _hb_glyph_info_is_ligature (&c
->buffer
->cur()) ?
287 HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH
: 0;
289 for (unsigned int i
= 0; i
< count
; i
++) {
290 _hb_glyph_info_set_lig_props_for_component (&c
->buffer
->cur(), i
);
291 c
->output_glyph_for_component (substitute
.array
[i
], klass
);
293 c
->buffer
->skip_glyph ();
295 return TRACE_RETURN (true);
298 inline bool serialize (hb_serialize_context_t
*c
,
299 Supplier
<GlyphID
> &glyphs
,
300 unsigned int num_glyphs
)
302 TRACE_SERIALIZE (this);
303 if (unlikely (!c
->extend_min (*this))) return TRACE_RETURN (false);
304 if (unlikely (!substitute
.serialize (c
, glyphs
, num_glyphs
))) return TRACE_RETURN (false);
305 return TRACE_RETURN (true);
308 inline bool sanitize (hb_sanitize_context_t
*c
) const
310 TRACE_SANITIZE (this);
311 return TRACE_RETURN (substitute
.sanitize (c
));
316 substitute
; /* String of GlyphIDs to substitute */
318 DEFINE_SIZE_ARRAY (2, substitute
);
321 struct MultipleSubstFormat1
323 inline void closure (hb_closure_context_t
*c
) const
325 TRACE_CLOSURE (this);
327 for (iter
.init (this+coverage
); iter
.more (); iter
.next ()) {
328 if (c
->glyphs
->has (iter
.get_glyph ()))
329 (this+sequence
[iter
.get_coverage ()]).closure (c
);
333 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
335 TRACE_COLLECT_GLYPHS (this);
336 (this+coverage
).add_coverage (c
->input
);
337 unsigned int count
= sequence
.len
;
338 for (unsigned int i
= 0; i
< count
; i
++)
339 (this+sequence
[i
]).collect_glyphs (c
);
342 inline const Coverage
&get_coverage (void) const
344 return this+coverage
;
347 inline bool would_apply (hb_would_apply_context_t
*c
) const
349 TRACE_WOULD_APPLY (this);
350 return TRACE_RETURN (c
->len
== 1 && (this+coverage
).get_coverage (c
->glyphs
[0]) != NOT_COVERED
);
353 inline bool apply (hb_apply_context_t
*c
) const
357 unsigned int index
= (this+coverage
).get_coverage (c
->buffer
->cur().codepoint
);
358 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
360 return TRACE_RETURN ((this+sequence
[index
]).apply (c
));
363 inline bool serialize (hb_serialize_context_t
*c
,
364 Supplier
<GlyphID
> &glyphs
,
365 Supplier
<unsigned int> &substitute_len_list
,
366 unsigned int num_glyphs
,
367 Supplier
<GlyphID
> &substitute_glyphs_list
)
369 TRACE_SERIALIZE (this);
370 if (unlikely (!c
->extend_min (*this))) return TRACE_RETURN (false);
371 if (unlikely (!sequence
.serialize (c
, num_glyphs
))) return TRACE_RETURN (false);
372 for (unsigned int i
= 0; i
< num_glyphs
; i
++)
373 if (unlikely (!sequence
[i
].serialize (c
, this).serialize (c
,
374 substitute_glyphs_list
,
375 substitute_len_list
[i
]))) return TRACE_RETURN (false);
376 substitute_len_list
.advance (num_glyphs
);
377 if (unlikely (!coverage
.serialize (c
, this).serialize (c
, glyphs
, num_glyphs
))) return TRACE_RETURN (false);
378 return TRACE_RETURN (true);
381 inline bool sanitize (hb_sanitize_context_t
*c
) const
383 TRACE_SANITIZE (this);
384 return TRACE_RETURN (coverage
.sanitize (c
, this) && sequence
.sanitize (c
, this));
388 USHORT format
; /* Format identifier--format = 1 */
390 coverage
; /* Offset to Coverage table--from
391 * beginning of Substitution table */
392 OffsetArrayOf
<Sequence
>
393 sequence
; /* Array of Sequence tables
394 * ordered by Coverage Index */
396 DEFINE_SIZE_ARRAY (6, sequence
);
401 inline bool serialize (hb_serialize_context_t
*c
,
402 Supplier
<GlyphID
> &glyphs
,
403 Supplier
<unsigned int> &substitute_len_list
,
404 unsigned int num_glyphs
,
405 Supplier
<GlyphID
> &substitute_glyphs_list
)
407 TRACE_SERIALIZE (this);
408 if (unlikely (!c
->extend_min (u
.format
))) return TRACE_RETURN (false);
409 unsigned int format
= 1;
410 u
.format
.set (format
);
412 case 1: return TRACE_RETURN (u
.format1
.serialize (c
, glyphs
, substitute_len_list
, num_glyphs
, substitute_glyphs_list
));
413 default:return TRACE_RETURN (false);
417 template <typename context_t
>
418 inline typename
context_t::return_t
dispatch (context_t
*c
) const
420 TRACE_DISPATCH (this, u
.format
);
421 if (unlikely (!c
->may_dispatch (this, &u
.format
))) TRACE_RETURN (c
->default_return_value ());
423 case 1: return TRACE_RETURN (c
->dispatch (u
.format1
));
424 default:return TRACE_RETURN (c
->default_return_value ());
430 USHORT format
; /* Format identifier */
431 MultipleSubstFormat1 format1
;
436 typedef ArrayOf
<GlyphID
> AlternateSet
; /* Array of alternate GlyphIDs--in
439 struct AlternateSubstFormat1
441 inline void closure (hb_closure_context_t
*c
) const
443 TRACE_CLOSURE (this);
445 for (iter
.init (this+coverage
); iter
.more (); iter
.next ()) {
446 if (c
->glyphs
->has (iter
.get_glyph ())) {
447 const AlternateSet
&alt_set
= this+alternateSet
[iter
.get_coverage ()];
448 unsigned int count
= alt_set
.len
;
449 for (unsigned int i
= 0; i
< count
; i
++)
450 c
->glyphs
->add (alt_set
[i
]);
455 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
457 TRACE_COLLECT_GLYPHS (this);
459 for (iter
.init (this+coverage
); iter
.more (); iter
.next ()) {
460 c
->input
->add (iter
.get_glyph ());
461 const AlternateSet
&alt_set
= this+alternateSet
[iter
.get_coverage ()];
462 unsigned int count
= alt_set
.len
;
463 for (unsigned int i
= 0; i
< count
; i
++)
464 c
->output
->add (alt_set
[i
]);
468 inline const Coverage
&get_coverage (void) const
470 return this+coverage
;
473 inline bool would_apply (hb_would_apply_context_t
*c
) const
475 TRACE_WOULD_APPLY (this);
476 return TRACE_RETURN (c
->len
== 1 && (this+coverage
).get_coverage (c
->glyphs
[0]) != NOT_COVERED
);
479 inline bool apply (hb_apply_context_t
*c
) const
482 hb_codepoint_t glyph_id
= c
->buffer
->cur().codepoint
;
484 unsigned int index
= (this+coverage
).get_coverage (glyph_id
);
485 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
487 const AlternateSet
&alt_set
= this+alternateSet
[index
];
489 if (unlikely (!alt_set
.len
)) return TRACE_RETURN (false);
491 hb_mask_t glyph_mask
= c
->buffer
->cur().mask
;
492 hb_mask_t lookup_mask
= c
->lookup_mask
;
494 /* Note: This breaks badly if two features enabled this lookup together. */
495 unsigned int shift
= _hb_ctz (lookup_mask
);
496 unsigned int alt_index
= ((lookup_mask
& glyph_mask
) >> shift
);
498 if (unlikely (alt_index
> alt_set
.len
|| alt_index
== 0)) return TRACE_RETURN (false);
500 glyph_id
= alt_set
[alt_index
- 1];
502 c
->replace_glyph (glyph_id
);
504 return TRACE_RETURN (true);
507 inline bool serialize (hb_serialize_context_t
*c
,
508 Supplier
<GlyphID
> &glyphs
,
509 Supplier
<unsigned int> &alternate_len_list
,
510 unsigned int num_glyphs
,
511 Supplier
<GlyphID
> &alternate_glyphs_list
)
513 TRACE_SERIALIZE (this);
514 if (unlikely (!c
->extend_min (*this))) return TRACE_RETURN (false);
515 if (unlikely (!alternateSet
.serialize (c
, num_glyphs
))) return TRACE_RETURN (false);
516 for (unsigned int i
= 0; i
< num_glyphs
; i
++)
517 if (unlikely (!alternateSet
[i
].serialize (c
, this).serialize (c
,
518 alternate_glyphs_list
,
519 alternate_len_list
[i
]))) return TRACE_RETURN (false);
520 alternate_len_list
.advance (num_glyphs
);
521 if (unlikely (!coverage
.serialize (c
, this).serialize (c
, glyphs
, num_glyphs
))) return TRACE_RETURN (false);
522 return TRACE_RETURN (true);
525 inline bool sanitize (hb_sanitize_context_t
*c
) const
527 TRACE_SANITIZE (this);
528 return TRACE_RETURN (coverage
.sanitize (c
, this) && alternateSet
.sanitize (c
, this));
532 USHORT format
; /* Format identifier--format = 1 */
534 coverage
; /* Offset to Coverage table--from
535 * beginning of Substitution table */
536 OffsetArrayOf
<AlternateSet
>
537 alternateSet
; /* Array of AlternateSet tables
538 * ordered by Coverage Index */
540 DEFINE_SIZE_ARRAY (6, alternateSet
);
543 struct AlternateSubst
545 inline bool serialize (hb_serialize_context_t
*c
,
546 Supplier
<GlyphID
> &glyphs
,
547 Supplier
<unsigned int> &alternate_len_list
,
548 unsigned int num_glyphs
,
549 Supplier
<GlyphID
> &alternate_glyphs_list
)
551 TRACE_SERIALIZE (this);
552 if (unlikely (!c
->extend_min (u
.format
))) return TRACE_RETURN (false);
553 unsigned int format
= 1;
554 u
.format
.set (format
);
556 case 1: return TRACE_RETURN (u
.format1
.serialize (c
, glyphs
, alternate_len_list
, num_glyphs
, alternate_glyphs_list
));
557 default:return TRACE_RETURN (false);
561 template <typename context_t
>
562 inline typename
context_t::return_t
dispatch (context_t
*c
) const
564 TRACE_DISPATCH (this, u
.format
);
565 if (unlikely (!c
->may_dispatch (this, &u
.format
))) TRACE_RETURN (c
->default_return_value ());
567 case 1: return TRACE_RETURN (c
->dispatch (u
.format1
));
568 default:return TRACE_RETURN (c
->default_return_value ());
574 USHORT format
; /* Format identifier */
575 AlternateSubstFormat1 format1
;
582 inline void closure (hb_closure_context_t
*c
) const
584 TRACE_CLOSURE (this);
585 unsigned int count
= component
.len
;
586 for (unsigned int i
= 1; i
< count
; i
++)
587 if (!c
->glyphs
->has (component
[i
]))
589 c
->glyphs
->add (ligGlyph
);
592 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
594 TRACE_COLLECT_GLYPHS (this);
595 unsigned int count
= component
.len
;
596 for (unsigned int i
= 1; i
< count
; i
++)
597 c
->input
->add (component
[i
]);
598 c
->output
->add (ligGlyph
);
601 inline bool would_apply (hb_would_apply_context_t
*c
) const
603 TRACE_WOULD_APPLY (this);
604 if (c
->len
!= component
.len
)
605 return TRACE_RETURN (false);
607 for (unsigned int i
= 1; i
< c
->len
; i
++)
608 if (likely (c
->glyphs
[i
] != component
[i
]))
609 return TRACE_RETURN (false);
611 return TRACE_RETURN (true);
614 inline bool apply (hb_apply_context_t
*c
) const
617 unsigned int count
= component
.len
;
619 if (unlikely (!count
)) return TRACE_RETURN (false);
621 /* Special-case to make it in-place and not consider this
622 * as a "ligated" substitution. */
623 if (unlikely (count
== 1))
625 c
->replace_glyph (ligGlyph
);
626 return TRACE_RETURN (true);
629 bool is_mark_ligature
= false;
630 unsigned int total_component_count
= 0;
632 unsigned int match_length
= 0;
633 unsigned int match_positions
[MAX_CONTEXT_LENGTH
];
635 if (likely (!match_input (c
, count
,
642 &total_component_count
)))
643 return TRACE_RETURN (false);
651 total_component_count
);
653 return TRACE_RETURN (true);
656 inline bool serialize (hb_serialize_context_t
*c
,
658 Supplier
<GlyphID
> &components
, /* Starting from second */
659 unsigned int num_components
/* Including first component */)
661 TRACE_SERIALIZE (this);
662 if (unlikely (!c
->extend_min (*this))) return TRACE_RETURN (false);
664 if (unlikely (!component
.serialize (c
, components
, num_components
))) return TRACE_RETURN (false);
665 return TRACE_RETURN (true);
669 inline bool sanitize (hb_sanitize_context_t
*c
) const
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
) const
750 TRACE_SANITIZE (this);
751 return TRACE_RETURN (ligature
.sanitize (c
, this));
755 OffsetArrayOf
<Ligature
>
756 ligature
; /* Array LigatureSet tables
757 * ordered by preference */
759 DEFINE_SIZE_ARRAY (2, ligature
);
762 struct LigatureSubstFormat1
764 inline void closure (hb_closure_context_t
*c
) const
766 TRACE_CLOSURE (this);
768 for (iter
.init (this+coverage
); iter
.more (); iter
.next ()) {
769 if (c
->glyphs
->has (iter
.get_glyph ()))
770 (this+ligatureSet
[iter
.get_coverage ()]).closure (c
);
774 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
776 TRACE_COLLECT_GLYPHS (this);
778 for (iter
.init (this+coverage
); iter
.more (); iter
.next ()) {
779 c
->input
->add (iter
.get_glyph ());
780 (this+ligatureSet
[iter
.get_coverage ()]).collect_glyphs (c
);
784 inline const Coverage
&get_coverage (void) const
786 return this+coverage
;
789 inline bool would_apply (hb_would_apply_context_t
*c
) const
791 TRACE_WOULD_APPLY (this);
792 unsigned int index
= (this+coverage
).get_coverage (c
->glyphs
[0]);
793 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
795 const LigatureSet
&lig_set
= this+ligatureSet
[index
];
796 return TRACE_RETURN (lig_set
.would_apply (c
));
799 inline bool apply (hb_apply_context_t
*c
) const
802 hb_codepoint_t glyph_id
= c
->buffer
->cur().codepoint
;
804 unsigned int index
= (this+coverage
).get_coverage (glyph_id
);
805 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
807 const LigatureSet
&lig_set
= this+ligatureSet
[index
];
808 return TRACE_RETURN (lig_set
.apply (c
));
811 inline bool serialize (hb_serialize_context_t
*c
,
812 Supplier
<GlyphID
> &first_glyphs
,
813 Supplier
<unsigned int> &ligature_per_first_glyph_count_list
,
814 unsigned int num_first_glyphs
,
815 Supplier
<GlyphID
> &ligatures_list
,
816 Supplier
<unsigned int> &component_count_list
,
817 Supplier
<GlyphID
> &component_list
/* Starting from second for each ligature */)
819 TRACE_SERIALIZE (this);
820 if (unlikely (!c
->extend_min (*this))) return TRACE_RETURN (false);
821 if (unlikely (!ligatureSet
.serialize (c
, num_first_glyphs
))) return TRACE_RETURN (false);
822 for (unsigned int i
= 0; i
< num_first_glyphs
; i
++)
823 if (unlikely (!ligatureSet
[i
].serialize (c
, this).serialize (c
,
825 component_count_list
,
826 ligature_per_first_glyph_count_list
[i
],
827 component_list
))) return TRACE_RETURN (false);
828 ligature_per_first_glyph_count_list
.advance (num_first_glyphs
);
829 if (unlikely (!coverage
.serialize (c
, this).serialize (c
, first_glyphs
, num_first_glyphs
))) return TRACE_RETURN (false);
830 return TRACE_RETURN (true);
833 inline bool sanitize (hb_sanitize_context_t
*c
) const
835 TRACE_SANITIZE (this);
836 return TRACE_RETURN (coverage
.sanitize (c
, this) && ligatureSet
.sanitize (c
, this));
840 USHORT format
; /* Format identifier--format = 1 */
842 coverage
; /* Offset to Coverage table--from
843 * beginning of Substitution table */
844 OffsetArrayOf
<LigatureSet
>
845 ligatureSet
; /* Array LigatureSet tables
846 * ordered by Coverage Index */
848 DEFINE_SIZE_ARRAY (6, ligatureSet
);
853 inline bool serialize (hb_serialize_context_t
*c
,
854 Supplier
<GlyphID
> &first_glyphs
,
855 Supplier
<unsigned int> &ligature_per_first_glyph_count_list
,
856 unsigned int num_first_glyphs
,
857 Supplier
<GlyphID
> &ligatures_list
,
858 Supplier
<unsigned int> &component_count_list
,
859 Supplier
<GlyphID
> &component_list
/* Starting from second for each ligature */)
861 TRACE_SERIALIZE (this);
862 if (unlikely (!c
->extend_min (u
.format
))) return TRACE_RETURN (false);
863 unsigned int format
= 1;
864 u
.format
.set (format
);
866 case 1: return TRACE_RETURN (u
.format1
.serialize (c
, first_glyphs
, ligature_per_first_glyph_count_list
, num_first_glyphs
,
867 ligatures_list
, component_count_list
, component_list
));
868 default:return TRACE_RETURN (false);
872 template <typename context_t
>
873 inline typename
context_t::return_t
dispatch (context_t
*c
) const
875 TRACE_DISPATCH (this, u
.format
);
876 if (unlikely (!c
->may_dispatch (this, &u
.format
))) TRACE_RETURN (c
->default_return_value ());
878 case 1: return TRACE_RETURN (c
->dispatch (u
.format1
));
879 default:return TRACE_RETURN (c
->default_return_value ());
885 USHORT format
; /* Format identifier */
886 LigatureSubstFormat1 format1
;
891 struct ContextSubst
: Context
{};
893 struct ChainContextSubst
: ChainContext
{};
895 struct ExtensionSubst
: Extension
<ExtensionSubst
>
897 typedef struct SubstLookupSubTable LookupSubTable
;
899 inline bool is_reverse (void) const;
903 struct ReverseChainSingleSubstFormat1
905 inline void closure (hb_closure_context_t
*c
) const
907 TRACE_CLOSURE (this);
908 const OffsetArrayOf
<Coverage
> &lookahead
= StructAfter
<OffsetArrayOf
<Coverage
> > (backtrack
);
912 count
= backtrack
.len
;
913 for (unsigned int i
= 0; i
< count
; i
++)
914 if (!(this+backtrack
[i
]).intersects (c
->glyphs
))
917 count
= lookahead
.len
;
918 for (unsigned int i
= 0; i
< count
; i
++)
919 if (!(this+lookahead
[i
]).intersects (c
->glyphs
))
922 const ArrayOf
<GlyphID
> &substitute
= StructAfter
<ArrayOf
<GlyphID
> > (lookahead
);
924 for (iter
.init (this+coverage
); iter
.more (); iter
.next ()) {
925 if (c
->glyphs
->has (iter
.get_glyph ()))
926 c
->glyphs
->add (substitute
[iter
.get_coverage ()]);
930 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
932 TRACE_COLLECT_GLYPHS (this);
934 const OffsetArrayOf
<Coverage
> &lookahead
= StructAfter
<OffsetArrayOf
<Coverage
> > (backtrack
);
938 (this+coverage
).add_coverage (c
->input
);
940 count
= backtrack
.len
;
941 for (unsigned int i
= 0; i
< count
; i
++)
942 (this+backtrack
[i
]).add_coverage (c
->before
);
944 count
= lookahead
.len
;
945 for (unsigned int i
= 0; i
< count
; i
++)
946 (this+lookahead
[i
]).add_coverage (c
->after
);
948 const ArrayOf
<GlyphID
> &substitute
= StructAfter
<ArrayOf
<GlyphID
> > (lookahead
);
949 count
= substitute
.len
;
950 for (unsigned int i
= 0; i
< count
; i
++)
951 c
->output
->add (substitute
[i
]);
954 inline const Coverage
&get_coverage (void) const
956 return this+coverage
;
959 inline bool would_apply (hb_would_apply_context_t
*c
) const
961 TRACE_WOULD_APPLY (this);
962 return TRACE_RETURN (c
->len
== 1 && (this+coverage
).get_coverage (c
->glyphs
[0]) != NOT_COVERED
);
965 inline bool apply (hb_apply_context_t
*c
) const
968 if (unlikely (c
->nesting_level_left
!= MAX_NESTING_LEVEL
))
969 return TRACE_RETURN (false); /* No chaining to this type */
971 unsigned int index
= (this+coverage
).get_coverage (c
->buffer
->cur().codepoint
);
972 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
974 const OffsetArrayOf
<Coverage
> &lookahead
= StructAfter
<OffsetArrayOf
<Coverage
> > (backtrack
);
975 const ArrayOf
<GlyphID
> &substitute
= StructAfter
<ArrayOf
<GlyphID
> > (lookahead
);
977 if (match_backtrack (c
,
978 backtrack
.len
, (USHORT
*) backtrack
.array
,
979 match_coverage
, this) &&
981 lookahead
.len
, (USHORT
*) lookahead
.array
,
982 match_coverage
, this,
985 c
->replace_glyph_inplace (substitute
[index
]);
986 /* Note: We DON'T decrease buffer->idx. The main loop does it
987 * for us. This is useful for preventing surprises if someone
988 * calls us through a Context lookup. */
989 return TRACE_RETURN (true);
992 return TRACE_RETURN (false);
995 inline bool sanitize (hb_sanitize_context_t
*c
) const
997 TRACE_SANITIZE (this);
998 if (!(coverage
.sanitize (c
, this) && backtrack
.sanitize (c
, this)))
999 return TRACE_RETURN (false);
1000 const OffsetArrayOf
<Coverage
> &lookahead
= StructAfter
<OffsetArrayOf
<Coverage
> > (backtrack
);
1001 if (!lookahead
.sanitize (c
, this))
1002 return TRACE_RETURN (false);
1003 const ArrayOf
<GlyphID
> &substitute
= StructAfter
<ArrayOf
<GlyphID
> > (lookahead
);
1004 return TRACE_RETURN (substitute
.sanitize (c
));
1008 USHORT format
; /* Format identifier--format = 1 */
1010 coverage
; /* Offset to Coverage table--from
1011 * beginning of table */
1012 OffsetArrayOf
<Coverage
>
1013 backtrack
; /* Array of coverage tables
1014 * in backtracking sequence, in glyph
1016 OffsetArrayOf
<Coverage
>
1017 lookaheadX
; /* Array of coverage tables
1018 * in lookahead sequence, in glyph
1021 substituteX
; /* Array of substitute
1022 * GlyphIDs--ordered by Coverage Index */
1024 DEFINE_SIZE_MIN (10);
1027 struct ReverseChainSingleSubst
1029 template <typename context_t
>
1030 inline typename
context_t::return_t
dispatch (context_t
*c
) const
1032 TRACE_DISPATCH (this, u
.format
);
1033 if (unlikely (!c
->may_dispatch (this, &u
.format
))) TRACE_RETURN (c
->default_return_value ());
1035 case 1: return TRACE_RETURN (c
->dispatch (u
.format1
));
1036 default:return TRACE_RETURN (c
->default_return_value ());
1042 USHORT format
; /* Format identifier */
1043 ReverseChainSingleSubstFormat1 format1
;
1053 struct SubstLookupSubTable
1055 friend struct SubstLookup
;
1065 ReverseChainSingle
= 8
1068 template <typename context_t
>
1069 inline typename
context_t::return_t
dispatch (context_t
*c
, unsigned int lookup_type
) const
1071 TRACE_DISPATCH (this, lookup_type
);
1072 /* The sub_format passed to may_dispatch is unnecessary but harmless. */
1073 if (unlikely (!c
->may_dispatch (this, &u
.sub_format
))) TRACE_RETURN (c
->default_return_value ());
1074 switch (lookup_type
) {
1075 case Single
: return TRACE_RETURN (u
.single
.dispatch (c
));
1076 case Multiple
: return TRACE_RETURN (u
.multiple
.dispatch (c
));
1077 case Alternate
: return TRACE_RETURN (u
.alternate
.dispatch (c
));
1078 case Ligature
: return TRACE_RETURN (u
.ligature
.dispatch (c
));
1079 case Context
: return TRACE_RETURN (u
.context
.dispatch (c
));
1080 case ChainContext
: return TRACE_RETURN (u
.chainContext
.dispatch (c
));
1081 case Extension
: return TRACE_RETURN (u
.extension
.dispatch (c
));
1082 case ReverseChainSingle
: return TRACE_RETURN (u
.reverseChainContextSingle
.dispatch (c
));
1083 default: return TRACE_RETURN (c
->default_return_value ());
1091 MultipleSubst multiple
;
1092 AlternateSubst alternate
;
1093 LigatureSubst ligature
;
1094 ContextSubst context
;
1095 ChainContextSubst chainContext
;
1096 ExtensionSubst extension
;
1097 ReverseChainSingleSubst reverseChainContextSingle
;
1100 DEFINE_SIZE_UNION (2, sub_format
);
1104 struct SubstLookup
: Lookup
1106 inline const SubstLookupSubTable
& get_subtable (unsigned int i
) const
1107 { return Lookup::get_subtable
<SubstLookupSubTable
> (i
); }
1109 inline static bool lookup_type_is_reverse (unsigned int lookup_type
)
1110 { return lookup_type
== SubstLookupSubTable::ReverseChainSingle
; }
1112 inline bool is_reverse (void) const
1114 unsigned int type
= get_type ();
1115 if (unlikely (type
== SubstLookupSubTable::Extension
))
1116 return CastR
<ExtensionSubst
> (get_subtable(0)).is_reverse ();
1117 return lookup_type_is_reverse (type
);
1120 inline bool apply (hb_apply_context_t
*c
) const
1123 return TRACE_RETURN (dispatch (c
));
1126 inline hb_closure_context_t::return_t
closure (hb_closure_context_t
*c
) const
1128 TRACE_CLOSURE (this);
1129 c
->set_recurse_func (dispatch_recurse_func
<hb_closure_context_t
>);
1130 return TRACE_RETURN (dispatch (c
));
1133 inline hb_collect_glyphs_context_t::return_t
collect_glyphs (hb_collect_glyphs_context_t
*c
) const
1135 TRACE_COLLECT_GLYPHS (this);
1136 c
->set_recurse_func (dispatch_recurse_func
<hb_collect_glyphs_context_t
>);
1137 return TRACE_RETURN (dispatch (c
));
1140 template <typename set_t
>
1141 inline void add_coverage (set_t
*glyphs
) const
1143 hb_add_coverage_context_t
<set_t
> c (glyphs
);
1147 inline bool would_apply (hb_would_apply_context_t
*c
,
1148 const hb_ot_layout_lookup_accelerator_t
*accel
) const
1150 TRACE_WOULD_APPLY (this);
1151 if (unlikely (!c
->len
)) return TRACE_RETURN (false);
1152 if (!accel
->may_have (c
->glyphs
[0])) return TRACE_RETURN (false);
1153 return TRACE_RETURN (dispatch (c
));
1156 static bool apply_recurse_func (hb_apply_context_t
*c
, unsigned int lookup_index
);
1158 inline SubstLookupSubTable
& serialize_subtable (hb_serialize_context_t
*c
,
1160 { return get_subtables
<SubstLookupSubTable
> ()[i
].serialize (c
, this); }
1162 inline bool serialize_single (hb_serialize_context_t
*c
,
1163 uint32_t lookup_props
,
1164 Supplier
<GlyphID
> &glyphs
,
1165 Supplier
<GlyphID
> &substitutes
,
1166 unsigned int num_glyphs
)
1168 TRACE_SERIALIZE (this);
1169 if (unlikely (!Lookup::serialize (c
, SubstLookupSubTable::Single
, lookup_props
, 1))) return TRACE_RETURN (false);
1170 return TRACE_RETURN (serialize_subtable (c
, 0).u
.single
.serialize (c
, glyphs
, substitutes
, num_glyphs
));
1173 inline bool serialize_multiple (hb_serialize_context_t
*c
,
1174 uint32_t lookup_props
,
1175 Supplier
<GlyphID
> &glyphs
,
1176 Supplier
<unsigned int> &substitute_len_list
,
1177 unsigned int num_glyphs
,
1178 Supplier
<GlyphID
> &substitute_glyphs_list
)
1180 TRACE_SERIALIZE (this);
1181 if (unlikely (!Lookup::serialize (c
, SubstLookupSubTable::Multiple
, lookup_props
, 1))) return TRACE_RETURN (false);
1182 return TRACE_RETURN (serialize_subtable (c
, 0).u
.multiple
.serialize (c
, glyphs
, substitute_len_list
, num_glyphs
,
1183 substitute_glyphs_list
));
1186 inline bool serialize_alternate (hb_serialize_context_t
*c
,
1187 uint32_t lookup_props
,
1188 Supplier
<GlyphID
> &glyphs
,
1189 Supplier
<unsigned int> &alternate_len_list
,
1190 unsigned int num_glyphs
,
1191 Supplier
<GlyphID
> &alternate_glyphs_list
)
1193 TRACE_SERIALIZE (this);
1194 if (unlikely (!Lookup::serialize (c
, SubstLookupSubTable::Alternate
, lookup_props
, 1))) return TRACE_RETURN (false);
1195 return TRACE_RETURN (serialize_subtable (c
, 0).u
.alternate
.serialize (c
, glyphs
, alternate_len_list
, num_glyphs
,
1196 alternate_glyphs_list
));
1199 inline bool serialize_ligature (hb_serialize_context_t
*c
,
1200 uint32_t lookup_props
,
1201 Supplier
<GlyphID
> &first_glyphs
,
1202 Supplier
<unsigned int> &ligature_per_first_glyph_count_list
,
1203 unsigned int num_first_glyphs
,
1204 Supplier
<GlyphID
> &ligatures_list
,
1205 Supplier
<unsigned int> &component_count_list
,
1206 Supplier
<GlyphID
> &component_list
/* Starting from second for each ligature */)
1208 TRACE_SERIALIZE (this);
1209 if (unlikely (!Lookup::serialize (c
, SubstLookupSubTable::Ligature
, lookup_props
, 1))) return TRACE_RETURN (false);
1210 return TRACE_RETURN (serialize_subtable (c
, 0).u
.ligature
.serialize (c
, first_glyphs
, ligature_per_first_glyph_count_list
, num_first_glyphs
,
1211 ligatures_list
, component_count_list
, component_list
));
1214 template <typename context_t
>
1215 static inline typename
context_t::return_t
dispatch_recurse_func (context_t
*c
, unsigned int lookup_index
);
1217 template <typename context_t
>
1218 inline typename
context_t::return_t
dispatch (context_t
*c
) const
1219 { return Lookup::dispatch
<SubstLookupSubTable
> (c
); }
1221 inline bool sanitize (hb_sanitize_context_t
*c
) const
1223 TRACE_SANITIZE (this);
1224 if (unlikely (!Lookup::sanitize (c
))) return TRACE_RETURN (false);
1225 if (unlikely (!dispatch (c
))) return TRACE_RETURN (false);
1227 if (unlikely (get_type () == SubstLookupSubTable::Extension
))
1229 /* The spec says all subtables of an Extension lookup should
1230 * have the same type. This is specially important if one has
1231 * a reverse type! */
1232 unsigned int type
= get_subtable (0).u
.extension
.get_type ();
1233 unsigned int count
= get_subtable_count ();
1234 for (unsigned int i
= 1; i
< count
; i
++)
1235 if (get_subtable (i
).u
.extension
.get_type () != type
)
1236 return TRACE_RETURN (false);
1238 return TRACE_RETURN (true);
1242 typedef OffsetListOf
<SubstLookup
> SubstLookupList
;
1245 * GSUB -- The Glyph Substitution Table
1248 struct GSUB
: GSUBGPOS
1250 static const hb_tag_t tableTag
= HB_OT_TAG_GSUB
;
1252 inline const SubstLookup
& get_lookup (unsigned int i
) const
1253 { return CastR
<SubstLookup
> (GSUBGPOS::get_lookup (i
)); }
1255 static inline void substitute_start (hb_font_t
*font
, hb_buffer_t
*buffer
);
1256 static inline void substitute_finish (hb_font_t
*font
, hb_buffer_t
*buffer
);
1258 inline bool sanitize (hb_sanitize_context_t
*c
) const
1260 TRACE_SANITIZE (this);
1261 if (unlikely (!GSUBGPOS::sanitize (c
))) return TRACE_RETURN (false);
1262 const OffsetTo
<SubstLookupList
> &list
= CastR
<OffsetTo
<SubstLookupList
> > (lookupList
);
1263 return TRACE_RETURN (list
.sanitize (c
, this));
1266 DEFINE_SIZE_STATIC (10);
1271 GSUB::substitute_start (hb_font_t
*font
, hb_buffer_t
*buffer
)
1273 _hb_buffer_assert_gsubgpos_vars (buffer
);
1275 const GDEF
&gdef
= *hb_ot_layout_from_face (font
->face
)->gdef
;
1276 unsigned int count
= buffer
->len
;
1277 for (unsigned int i
= 0; i
< count
; i
++)
1279 _hb_glyph_info_set_glyph_props (&buffer
->info
[i
], gdef
.get_glyph_props (buffer
->info
[i
].codepoint
));
1280 _hb_glyph_info_clear_lig_props (&buffer
->info
[i
]);
1281 buffer
->info
[i
].syllable() = 0;
1286 GSUB::substitute_finish (hb_font_t
*font HB_UNUSED
, hb_buffer_t
*buffer HB_UNUSED
)
1291 /* Out-of-class implementation for methods recursing */
1293 /*static*/ inline bool ExtensionSubst::is_reverse (void) const
1295 unsigned int type
= get_type ();
1296 if (unlikely (type
== SubstLookupSubTable::Extension
))
1297 return CastR
<ExtensionSubst
> (get_subtable
<LookupSubTable
>()).is_reverse ();
1298 return SubstLookup::lookup_type_is_reverse (type
);
1301 template <typename context_t
>
1302 /*static*/ inline typename
context_t::return_t
SubstLookup::dispatch_recurse_func (context_t
*c
, unsigned int lookup_index
)
1304 const GSUB
&gsub
= *(hb_ot_layout_from_face (c
->face
)->gsub
);
1305 const SubstLookup
&l
= gsub
.get_lookup (lookup_index
);
1306 return l
.dispatch (c
);
1309 /*static*/ inline bool SubstLookup::apply_recurse_func (hb_apply_context_t
*c
, unsigned int lookup_index
)
1311 const GSUB
&gsub
= *(hb_ot_layout_from_face (c
->face
)->gsub
);
1312 const SubstLookup
&l
= gsub
.get_lookup (lookup_index
);
1313 unsigned int saved_lookup_props
= c
->lookup_props
;
1314 unsigned int saved_lookup_index
= c
->lookup_index
;
1315 c
->set_lookup_index (lookup_index
);
1316 c
->set_lookup_props (l
.get_props ());
1317 bool ret
= l
.dispatch (c
);
1318 c
->set_lookup_index (saved_lookup_index
);
1319 c
->set_lookup_props (saved_lookup_props
);
1324 } /* namespace OT */
1327 #endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */