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_GSUBGPOS_PRIVATE_HH
30 #define HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH
32 #include "hb-buffer-private.hh"
33 #include "hb-ot-layout-gdef-table.hh"
34 #include "hb-set-private.hh"
41 #define TRACE_DISPATCH(this, format) \
42 hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \
43 (&c->debug_depth, c->get_name (), this, HB_FUNC, \
44 "format %d", (int) format);
46 #ifndef HB_DEBUG_CLOSURE
47 #define HB_DEBUG_CLOSURE (HB_DEBUG+0)
50 #define TRACE_CLOSURE(this) \
51 hb_auto_trace_t<HB_DEBUG_CLOSURE, hb_void_t> trace \
52 (&c->debug_depth, c->get_name (), this, HB_FUNC, \
55 struct hb_closure_context_t
57 inline const char *get_name (void) { return "CLOSURE"; }
58 static const unsigned int max_debug_depth
= HB_DEBUG_CLOSURE
;
59 typedef hb_void_t return_t
;
60 typedef return_t (*recurse_func_t
) (hb_closure_context_t
*c
, unsigned int lookup_index
);
62 inline return_t
dispatch (const T
&obj
) { obj
.closure (this); return HB_VOID
; }
63 static return_t
default_return_value (void) { return HB_VOID
; }
64 bool stop_sublookup_iteration (return_t r HB_UNUSED
) const { return false; }
65 return_t
recurse (unsigned int lookup_index
)
67 if (unlikely (nesting_level_left
== 0 || !recurse_func
))
68 return default_return_value ();
71 recurse_func (this, lookup_index
);
78 recurse_func_t recurse_func
;
79 unsigned int nesting_level_left
;
80 unsigned int debug_depth
;
82 hb_closure_context_t (hb_face_t
*face_
,
84 unsigned int nesting_level_left_
= MAX_NESTING_LEVEL
) :
88 nesting_level_left (nesting_level_left_
),
91 void set_recurse_func (recurse_func_t func
) { recurse_func
= func
; }
96 #ifndef HB_DEBUG_WOULD_APPLY
97 #define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0)
100 #define TRACE_WOULD_APPLY(this) \
101 hb_auto_trace_t<HB_DEBUG_WOULD_APPLY, bool> trace \
102 (&c->debug_depth, c->get_name (), this, HB_FUNC, \
103 "%d glyphs", c->len);
105 struct hb_would_apply_context_t
107 inline const char *get_name (void) { return "WOULD_APPLY"; }
108 static const unsigned int max_debug_depth
= HB_DEBUG_WOULD_APPLY
;
109 typedef bool return_t
;
110 template <typename T
>
111 inline return_t
dispatch (const T
&obj
) { return obj
.would_apply (this); }
112 static return_t
default_return_value (void) { return false; }
113 bool stop_sublookup_iteration (return_t r
) const { return r
; }
116 const hb_codepoint_t
*glyphs
;
119 unsigned int debug_depth
;
121 hb_would_apply_context_t (hb_face_t
*face_
,
122 const hb_codepoint_t
*glyphs_
,
124 bool zero_context_
) :
128 zero_context (zero_context_
),
134 #ifndef HB_DEBUG_COLLECT_GLYPHS
135 #define HB_DEBUG_COLLECT_GLYPHS (HB_DEBUG+0)
138 #define TRACE_COLLECT_GLYPHS(this) \
139 hb_auto_trace_t<HB_DEBUG_COLLECT_GLYPHS, hb_void_t> trace \
140 (&c->debug_depth, c->get_name (), this, HB_FUNC, \
143 struct hb_collect_glyphs_context_t
145 inline const char *get_name (void) { return "COLLECT_GLYPHS"; }
146 static const unsigned int max_debug_depth
= HB_DEBUG_COLLECT_GLYPHS
;
147 typedef hb_void_t return_t
;
148 typedef return_t (*recurse_func_t
) (hb_collect_glyphs_context_t
*c
, unsigned int lookup_index
);
149 template <typename T
>
150 inline return_t
dispatch (const T
&obj
) { obj
.collect_glyphs (this); return HB_VOID
; }
151 static return_t
default_return_value (void) { return HB_VOID
; }
152 bool stop_sublookup_iteration (return_t r HB_UNUSED
) const { return false; }
153 return_t
recurse (unsigned int lookup_index
)
155 if (unlikely (nesting_level_left
== 0 || !recurse_func
))
156 return default_return_value ();
158 /* Note that GPOS sets recurse_func to NULL already, so it doesn't get
159 * past the previous check. For GSUB, we only want to collect the output
160 * glyphs in the recursion. If output is not requested, we can go home now.
162 * Note further, that the above is not exactly correct. A recursed lookup
163 * is allowed to match input that is not matched in the context, but that's
164 * not how most fonts are built. It's possible to relax that and recurse
165 * with all sets here if it proves to be an issue.
168 if (output
== hb_set_get_empty ())
171 /* Return if new lookup was recursed to before. */
172 if (recursed_lookups
.has (lookup_index
))
175 hb_set_t
*old_before
= before
;
176 hb_set_t
*old_input
= input
;
177 hb_set_t
*old_after
= after
;
178 before
= input
= after
= hb_set_get_empty ();
180 nesting_level_left
--;
181 recurse_func (this, lookup_index
);
182 nesting_level_left
++;
188 recursed_lookups
.add (lookup_index
);
198 recurse_func_t recurse_func
;
199 hb_set_t recursed_lookups
;
200 unsigned int nesting_level_left
;
201 unsigned int debug_depth
;
203 hb_collect_glyphs_context_t (hb_face_t
*face_
,
204 hb_set_t
*glyphs_before
, /* OUT. May be NULL */
205 hb_set_t
*glyphs_input
, /* OUT. May be NULL */
206 hb_set_t
*glyphs_after
, /* OUT. May be NULL */
207 hb_set_t
*glyphs_output
, /* OUT. May be NULL */
208 unsigned int nesting_level_left_
= MAX_NESTING_LEVEL
) :
210 before (glyphs_before
? glyphs_before
: hb_set_get_empty ()),
211 input (glyphs_input
? glyphs_input
: hb_set_get_empty ()),
212 after (glyphs_after
? glyphs_after
: hb_set_get_empty ()),
213 output (glyphs_output
? glyphs_output
: hb_set_get_empty ()),
216 nesting_level_left (nesting_level_left_
),
219 recursed_lookups
.init ();
221 ~hb_collect_glyphs_context_t (void)
223 recursed_lookups
.fini ();
226 void set_recurse_func (recurse_func_t func
) { recurse_func
= func
; }
231 #ifndef HB_DEBUG_GET_COVERAGE
232 #define HB_DEBUG_GET_COVERAGE (HB_DEBUG+0)
235 struct hb_get_coverage_context_t
237 inline const char *get_name (void) { return "GET_COVERAGE"; }
238 static const unsigned int max_debug_depth
= HB_DEBUG_GET_COVERAGE
;
239 typedef const Coverage
&return_t
;
240 template <typename T
>
241 inline return_t
dispatch (const T
&obj
) { return obj
.get_coverage (); }
242 static return_t
default_return_value (void) { return Null(Coverage
); }
244 hb_get_coverage_context_t (void) :
247 unsigned int debug_depth
;
252 #ifndef HB_DEBUG_APPLY
253 #define HB_DEBUG_APPLY (HB_DEBUG+0)
256 #define TRACE_APPLY(this) \
257 hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace \
258 (&c->debug_depth, c->get_name (), this, HB_FUNC, \
259 "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
261 struct hb_apply_context_t
263 inline const char *get_name (void) { return "APPLY"; }
264 static const unsigned int max_debug_depth
= HB_DEBUG_APPLY
;
265 typedef bool return_t
;
266 typedef return_t (*recurse_func_t
) (hb_apply_context_t
*c
, unsigned int lookup_index
);
267 template <typename T
>
268 inline return_t
dispatch (const T
&obj
) { return obj
.apply (this); }
269 static return_t
default_return_value (void) { return false; }
270 bool stop_sublookup_iteration (return_t r
) const { return r
; }
271 return_t
recurse (unsigned int lookup_index
)
273 if (unlikely (nesting_level_left
== 0 || !recurse_func
))
274 return default_return_value ();
276 nesting_level_left
--;
277 bool ret
= recurse_func (this, lookup_index
);
278 nesting_level_left
++;
282 unsigned int table_index
; /* GSUB/GPOS */
286 hb_direction_t direction
;
287 hb_mask_t lookup_mask
;
289 recurse_func_t recurse_func
;
290 unsigned int nesting_level_left
;
291 unsigned int lookup_props
;
293 bool has_glyph_classes
;
294 unsigned int debug_depth
;
297 hb_apply_context_t (unsigned int table_index_
,
299 hb_buffer_t
*buffer_
) :
300 table_index (table_index_
),
301 font (font_
), face (font
->face
), buffer (buffer_
),
302 direction (buffer_
->props
.direction
),
306 nesting_level_left (MAX_NESTING_LEVEL
),
308 gdef (*hb_ot_layout_from_face (face
)->gdef
),
309 has_glyph_classes (gdef
.has_glyph_classes ()),
312 inline void set_lookup_mask (hb_mask_t mask
) { lookup_mask
= mask
; }
313 inline void set_auto_zwj (bool auto_zwj_
) { auto_zwj
= auto_zwj_
; }
314 inline void set_recurse_func (recurse_func_t func
) { recurse_func
= func
; }
315 inline void set_lookup_props (unsigned int lookup_props_
) { lookup_props
= lookup_props_
; }
316 inline void set_lookup (const Lookup
&l
) { lookup_props
= l
.get_props (); }
320 inline matcher_t (void) :
325 #define arg1(arg) (arg) /* Remove the macro to see why it's needed! */
329 match_data (NULL
) {};
331 typedef bool (*match_func_t
) (hb_codepoint_t glyph_id
, const USHORT
&value
, const void *data
);
333 inline void set_ignore_zwnj (bool ignore_zwnj_
) { ignore_zwnj
= ignore_zwnj_
; }
334 inline void set_ignore_zwj (bool ignore_zwj_
) { ignore_zwj
= ignore_zwj_
; }
335 inline void set_lookup_props (unsigned int lookup_props_
) { lookup_props
= lookup_props_
; }
336 inline void set_mask (hb_mask_t mask_
) { mask
= mask_
; }
337 inline void set_syllable (uint8_t syllable_
) { syllable
= syllable_
; }
338 inline void set_match_func (match_func_t match_func_
,
339 const void *match_data_
)
340 { match_func
= match_func_
; match_data
= match_data_
; }
348 inline may_match_t
may_match (const hb_glyph_info_t
&info
,
349 const USHORT
*glyph_data
) const
351 if (!(info
.mask
& mask
) ||
352 (syllable
&& syllable
!= info
.syllable ()))
356 return match_func (info
.codepoint
, *glyph_data
, match_data
) ? MATCH_YES
: MATCH_NO
;
368 may_skip (const hb_apply_context_t
*c
,
369 const hb_glyph_info_t
&info
) const
371 if (!c
->check_glyph_property (&info
, lookup_props
))
374 if (unlikely (_hb_glyph_info_is_default_ignorable (&info
) &&
375 (ignore_zwnj
|| !_hb_glyph_info_is_zwnj (&info
)) &&
376 (ignore_zwj
|| !_hb_glyph_info_is_zwj (&info
)) &&
377 !_hb_glyph_info_ligated (&info
)))
384 unsigned int lookup_props
;
389 match_func_t match_func
;
390 const void *match_data
;
393 struct skipping_forward_iterator_t
395 inline skipping_forward_iterator_t (hb_apply_context_t
*c_
,
396 unsigned int start_index_
,
397 unsigned int num_items_
,
398 bool context_match
= false) :
401 match_glyph_data (NULL
),
402 num_items (num_items_
),
405 matcher
.set_lookup_props (c
->lookup_props
);
406 /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
407 matcher
.set_ignore_zwnj (context_match
|| c
->table_index
== 1);
408 /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */
409 matcher
.set_ignore_zwj (context_match
|| c
->table_index
== 1 || c
->auto_zwj
);
411 matcher
.set_mask (c
->lookup_mask
);
412 matcher
.set_syllable (start_index_
== c
->buffer
->idx
? c
->buffer
->cur().syllable () : 0);
414 inline void set_lookup_props (unsigned int lookup_props
) { matcher
.set_lookup_props (lookup_props
); }
415 inline void set_syllable (unsigned int syllable
) { matcher
.set_syllable (syllable
); }
416 inline void set_match_func (matcher_t::match_func_t match_func
,
417 const void *match_data
,
418 const USHORT glyph_data
[])
420 matcher
.set_match_func (match_func
, match_data
);
421 match_glyph_data
= glyph_data
;
424 inline bool has_no_chance (void) const { return unlikely (num_items
&& idx
+ num_items
>= end
); }
425 inline void reject (void) { num_items
++; match_glyph_data
--; }
426 inline bool next (void)
428 assert (num_items
> 0);
429 while (!has_no_chance ())
432 const hb_glyph_info_t
&info
= c
->buffer
->info
[idx
];
434 matcher_t::may_skip_t skip
= matcher
.may_skip (c
, info
);
435 if (unlikely (skip
== matcher_t::SKIP_YES
))
438 matcher_t::may_match_t match
= matcher
.may_match (info
, match_glyph_data
);
439 if (match
== matcher_t::MATCH_YES
||
440 (match
== matcher_t::MATCH_MAYBE
&&
441 skip
== matcher_t::SKIP_NO
))
448 if (skip
== matcher_t::SKIP_NO
)
456 hb_apply_context_t
*c
;
458 const USHORT
*match_glyph_data
;
460 unsigned int num_items
;
464 struct skipping_backward_iterator_t
466 inline skipping_backward_iterator_t (hb_apply_context_t
*c_
,
467 unsigned int start_index_
,
468 unsigned int num_items_
,
469 bool context_match
= false) :
472 match_glyph_data (NULL
),
473 num_items (num_items_
)
475 matcher
.set_lookup_props (c
->lookup_props
);
476 /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
477 matcher
.set_ignore_zwnj (context_match
|| c
->table_index
== 1);
478 /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */
479 matcher
.set_ignore_zwj (context_match
|| c
->table_index
== 1 || c
->auto_zwj
);
481 matcher
.set_mask (c
->lookup_mask
);
482 matcher
.set_syllable (start_index_
== c
->buffer
->idx
? c
->buffer
->cur().syllable () : 0);
484 inline void set_lookup_props (unsigned int lookup_props
) { matcher
.set_lookup_props (lookup_props
); }
485 inline void set_syllable (unsigned int syllable
) { matcher
.set_syllable (syllable
); }
486 inline void set_match_func (matcher_t::match_func_t match_func
,
487 const void *match_data
,
488 const USHORT glyph_data
[])
490 matcher
.set_match_func (match_func
, match_data
);
491 match_glyph_data
= glyph_data
;
494 inline bool has_no_chance (void) const { return unlikely (idx
< num_items
); }
495 inline void reject (void) { num_items
++; }
496 inline bool prev (void)
498 assert (num_items
> 0);
499 while (!has_no_chance ())
502 const hb_glyph_info_t
&info
= c
->buffer
->out_info
[idx
];
504 matcher_t::may_skip_t skip
= matcher
.may_skip (c
, info
);
505 if (unlikely (skip
== matcher_t::SKIP_YES
))
508 matcher_t::may_match_t match
= matcher
.may_match (info
, match_glyph_data
);
509 if (match
== matcher_t::MATCH_YES
||
510 (match
== matcher_t::MATCH_MAYBE
&&
511 skip
== matcher_t::SKIP_NO
))
518 if (skip
== matcher_t::SKIP_NO
)
526 hb_apply_context_t
*c
;
528 const USHORT
*match_glyph_data
;
530 unsigned int num_items
;
534 match_properties_mark (hb_codepoint_t glyph
,
535 unsigned int glyph_props
,
536 unsigned int lookup_props
) const
538 /* If using mark filtering sets, the high short of
539 * lookup_props has the set index.
541 if (lookup_props
& LookupFlag::UseMarkFilteringSet
)
542 return gdef
.mark_set_covers (lookup_props
>> 16, glyph
);
544 /* The second byte of lookup_props has the meaning
545 * "ignore marks of attachment type different than
546 * the attachment type specified."
548 if (lookup_props
& LookupFlag::MarkAttachmentType
)
549 return (lookup_props
& LookupFlag::MarkAttachmentType
) == (glyph_props
& LookupFlag::MarkAttachmentType
);
555 check_glyph_property (const hb_glyph_info_t
*info
,
556 unsigned int lookup_props
) const
558 hb_codepoint_t glyph
= info
->codepoint
;
559 unsigned int glyph_props
= _hb_glyph_info_get_glyph_props (info
);
561 /* Not covered, if, for example, glyph class is ligature and
562 * lookup_props includes LookupFlags::IgnoreLigatures
564 if (glyph_props
& lookup_props
& LookupFlag::IgnoreFlags
)
567 if (unlikely (glyph_props
& HB_OT_LAYOUT_GLYPH_PROPS_MARK
))
568 return match_properties_mark (glyph
, glyph_props
, lookup_props
);
573 inline void _set_glyph_props (hb_codepoint_t glyph_index
,
574 unsigned int class_guess
= 0,
575 bool ligature
= false,
576 bool component
= false) const
578 unsigned int add_in
= _hb_glyph_info_get_glyph_props (&buffer
->cur()) &
579 HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE
;
580 add_in
|= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED
;
583 add_in
|= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED
;
584 /* In the only place that the MULTIPLIED bit is used, Uniscribe
585 * seems to only care about the "last" transformation between
586 * Ligature and Multiple substitions. Ie. if you ligate, expand,
587 * and ligate again, it forgives the multiplication and acts as
588 * if only ligation happened. As such, clear MULTIPLIED bit.
590 add_in
&= ~HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED
;
593 add_in
|= HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED
;
594 if (likely (has_glyph_classes
))
595 _hb_glyph_info_set_glyph_props (&buffer
->cur(), add_in
| gdef
.get_glyph_props (glyph_index
));
596 else if (class_guess
)
597 _hb_glyph_info_set_glyph_props (&buffer
->cur(), add_in
| class_guess
);
600 inline void replace_glyph (hb_codepoint_t glyph_index
) const
602 _set_glyph_props (glyph_index
);
603 buffer
->replace_glyph (glyph_index
);
605 inline void replace_glyph_inplace (hb_codepoint_t glyph_index
) const
607 _set_glyph_props (glyph_index
);
608 buffer
->cur().codepoint
= glyph_index
;
610 inline void replace_glyph_with_ligature (hb_codepoint_t glyph_index
,
611 unsigned int class_guess
) const
613 _set_glyph_props (glyph_index
, class_guess
, true);
614 buffer
->replace_glyph (glyph_index
);
616 inline void output_glyph_for_component (hb_codepoint_t glyph_index
,
617 unsigned int class_guess
) const
619 _set_glyph_props (glyph_index
, class_guess
, false, true);
620 buffer
->output_glyph (glyph_index
);
626 typedef bool (*intersects_func_t
) (hb_set_t
*glyphs
, const USHORT
&value
, const void *data
);
627 typedef void (*collect_glyphs_func_t
) (hb_set_t
*glyphs
, const USHORT
&value
, const void *data
);
628 typedef bool (*match_func_t
) (hb_codepoint_t glyph_id
, const USHORT
&value
, const void *data
);
630 struct ContextClosureFuncs
632 intersects_func_t intersects
;
634 struct ContextCollectGlyphsFuncs
636 collect_glyphs_func_t collect
;
638 struct ContextApplyFuncs
644 static inline bool intersects_glyph (hb_set_t
*glyphs
, const USHORT
&value
, const void *data HB_UNUSED
)
646 return glyphs
->has (value
);
648 static inline bool intersects_class (hb_set_t
*glyphs
, const USHORT
&value
, const void *data
)
650 const ClassDef
&class_def
= *reinterpret_cast<const ClassDef
*>(data
);
651 return class_def
.intersects_class (glyphs
, value
);
653 static inline bool intersects_coverage (hb_set_t
*glyphs
, const USHORT
&value
, const void *data
)
655 const OffsetTo
<Coverage
> &coverage
= (const OffsetTo
<Coverage
>&)value
;
656 return (data
+coverage
).intersects (glyphs
);
659 static inline bool intersects_array (hb_closure_context_t
*c
,
661 const USHORT values
[],
662 intersects_func_t intersects_func
,
663 const void *intersects_data
)
665 for (unsigned int i
= 0; i
< count
; i
++)
666 if (likely (!intersects_func (c
->glyphs
, values
[i
], intersects_data
)))
672 static inline void collect_glyph (hb_set_t
*glyphs
, const USHORT
&value
, const void *data HB_UNUSED
)
676 static inline void collect_class (hb_set_t
*glyphs
, const USHORT
&value
, const void *data
)
678 const ClassDef
&class_def
= *reinterpret_cast<const ClassDef
*>(data
);
679 class_def
.add_class (glyphs
, value
);
681 static inline void collect_coverage (hb_set_t
*glyphs
, const USHORT
&value
, const void *data
)
683 const OffsetTo
<Coverage
> &coverage
= (const OffsetTo
<Coverage
>&)value
;
684 (data
+coverage
).add_coverage (glyphs
);
686 static inline void collect_array (hb_collect_glyphs_context_t
*c HB_UNUSED
,
689 const USHORT values
[],
690 collect_glyphs_func_t collect_func
,
691 const void *collect_data
)
693 for (unsigned int i
= 0; i
< count
; i
++)
694 collect_func (glyphs
, values
[i
], collect_data
);
698 static inline bool match_glyph (hb_codepoint_t glyph_id
, const USHORT
&value
, const void *data HB_UNUSED
)
700 return glyph_id
== value
;
702 static inline bool match_class (hb_codepoint_t glyph_id
, const USHORT
&value
, const void *data
)
704 const ClassDef
&class_def
= *reinterpret_cast<const ClassDef
*>(data
);
705 return class_def
.get_class (glyph_id
) == value
;
707 static inline bool match_coverage (hb_codepoint_t glyph_id
, const USHORT
&value
, const void *data
)
709 const OffsetTo
<Coverage
> &coverage
= (const OffsetTo
<Coverage
>&)value
;
710 return (data
+coverage
).get_coverage (glyph_id
) != NOT_COVERED
;
713 static inline bool would_match_input (hb_would_apply_context_t
*c
,
714 unsigned int count
, /* Including the first glyph (not matched) */
715 const USHORT input
[], /* Array of input values--start with second glyph */
716 match_func_t match_func
,
717 const void *match_data
)
722 for (unsigned int i
= 1; i
< count
; i
++)
723 if (likely (!match_func (c
->glyphs
[i
], input
[i
- 1], match_data
)))
728 static inline bool match_input (hb_apply_context_t
*c
,
729 unsigned int count
, /* Including the first glyph (not matched) */
730 const USHORT input
[], /* Array of input values--start with second glyph */
731 match_func_t match_func
,
732 const void *match_data
,
733 unsigned int *end_offset
,
734 unsigned int match_positions
[MAX_CONTEXT_LENGTH
],
735 bool *p_is_mark_ligature
= NULL
,
736 unsigned int *p_total_component_count
= NULL
)
740 if (unlikely (count
> MAX_CONTEXT_LENGTH
)) TRACE_RETURN (false);
742 hb_buffer_t
*buffer
= c
->buffer
;
744 hb_apply_context_t::skipping_forward_iterator_t
skippy_iter (c
, buffer
->idx
, count
- 1);
745 skippy_iter
.set_match_func (match_func
, match_data
, input
);
746 if (skippy_iter
.has_no_chance ()) return TRACE_RETURN (false);
749 * This is perhaps the trickiest part of OpenType... Remarks:
751 * - If all components of the ligature were marks, we call this a mark ligature.
753 * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize
754 * it as a ligature glyph.
756 * - Ligatures cannot be formed across glyphs attached to different components
757 * of previous ligatures. Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
758 * LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
759 * However, it would be wrong to ligate that SHADDA,FATHA sequence.o
760 * There is an exception to this: If a ligature tries ligating with marks that
761 * belong to it itself, go ahead, assuming that the font designer knows what
762 * they are doing (otherwise it can break Indic stuff when a matra wants to
763 * ligate with a conjunct...)
766 bool is_mark_ligature
= _hb_glyph_info_is_mark (&buffer
->cur());
768 unsigned int total_component_count
= 0;
769 total_component_count
+= _hb_glyph_info_get_lig_num_comps (&buffer
->cur());
771 unsigned int first_lig_id
= _hb_glyph_info_get_lig_id (&buffer
->cur());
772 unsigned int first_lig_comp
= _hb_glyph_info_get_lig_comp (&buffer
->cur());
774 match_positions
[0] = buffer
->idx
;
775 for (unsigned int i
= 1; i
< count
; i
++)
777 if (!skippy_iter
.next ()) return TRACE_RETURN (false);
779 match_positions
[i
] = skippy_iter
.idx
;
781 unsigned int this_lig_id
= _hb_glyph_info_get_lig_id (&buffer
->info
[skippy_iter
.idx
]);
782 unsigned int this_lig_comp
= _hb_glyph_info_get_lig_comp (&buffer
->info
[skippy_iter
.idx
]);
784 if (first_lig_id
&& first_lig_comp
) {
785 /* If first component was attached to a previous ligature component,
786 * all subsequent components should be attached to the same ligature
787 * component, otherwise we shouldn't ligate them. */
788 if (first_lig_id
!= this_lig_id
|| first_lig_comp
!= this_lig_comp
)
789 return TRACE_RETURN (false);
791 /* If first component was NOT attached to a previous ligature component,
792 * all subsequent components should also NOT be attached to any ligature
793 * component, unless they are attached to the first component itself! */
794 if (this_lig_id
&& this_lig_comp
&& (this_lig_id
!= first_lig_id
))
795 return TRACE_RETURN (false);
798 is_mark_ligature
= is_mark_ligature
&& _hb_glyph_info_is_mark (&buffer
->info
[skippy_iter
.idx
]);
799 total_component_count
+= _hb_glyph_info_get_lig_num_comps (&buffer
->info
[skippy_iter
.idx
]);
802 *end_offset
= skippy_iter
.idx
- buffer
->idx
+ 1;
804 if (p_is_mark_ligature
)
805 *p_is_mark_ligature
= is_mark_ligature
;
807 if (p_total_component_count
)
808 *p_total_component_count
= total_component_count
;
810 return TRACE_RETURN (true);
812 static inline void ligate_input (hb_apply_context_t
*c
,
813 unsigned int count
, /* Including the first glyph */
814 unsigned int match_positions
[MAX_CONTEXT_LENGTH
], /* Including the first glyph */
815 unsigned int match_length
,
816 hb_codepoint_t lig_glyph
,
817 bool is_mark_ligature
,
818 unsigned int total_component_count
)
822 hb_buffer_t
*buffer
= c
->buffer
;
824 buffer
->merge_clusters (buffer
->idx
, buffer
->idx
+ match_length
);
827 * - If it *is* a mark ligature, we don't allocate a new ligature id, and leave
828 * the ligature to keep its old ligature id. This will allow it to attach to
829 * a base ligature in GPOS. Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
830 * and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA wit a
831 * ligature id and component value of 2. Then if SHADDA,FATHA form a ligature
832 * later, we don't want them to lose their ligature id/component, otherwise
833 * GPOS will fail to correctly position the mark ligature on top of the
834 * LAM,LAM,HEH ligature. See:
835 * https://bugzilla.gnome.org/show_bug.cgi?id=676343
837 * - If a ligature is formed of components that some of which are also ligatures
838 * themselves, and those ligature components had marks attached to *their*
839 * components, we have to attach the marks to the new ligature component
840 * positions! Now *that*'s tricky! And these marks may be following the
841 * last component of the whole sequence, so we should loop forward looking
842 * for them and update them.
844 * Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a
845 * 'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature
846 * id and component == 1. Now, during 'liga', the LAM and the LAM-HEH ligature
847 * form a LAM-LAM-HEH ligature. We need to reassign the SHADDA and FATHA to
848 * the new ligature with a component value of 2.
850 * This in fact happened to a font... See:
851 * https://bugzilla.gnome.org/show_bug.cgi?id=437633
854 unsigned int klass
= is_mark_ligature
? 0 : HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE
;
855 unsigned int lig_id
= is_mark_ligature
? 0 : _hb_allocate_lig_id (buffer
);
856 unsigned int last_lig_id
= _hb_glyph_info_get_lig_id (&buffer
->cur());
857 unsigned int last_num_components
= _hb_glyph_info_get_lig_num_comps (&buffer
->cur());
858 unsigned int components_so_far
= last_num_components
;
860 if (!is_mark_ligature
)
862 _hb_glyph_info_set_lig_props_for_ligature (&buffer
->cur(), lig_id
, total_component_count
);
863 if (_hb_glyph_info_get_general_category (&buffer
->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK
)
865 _hb_glyph_info_set_general_category (&buffer
->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER
);
866 _hb_glyph_info_set_modified_combining_class (&buffer
->cur(), 0);
869 c
->replace_glyph_with_ligature (lig_glyph
, klass
);
871 for (unsigned int i
= 1; i
< count
; i
++)
873 while (buffer
->idx
< match_positions
[i
])
875 if (!is_mark_ligature
) {
876 unsigned int new_lig_comp
= components_so_far
- last_num_components
+
877 MIN (MAX (_hb_glyph_info_get_lig_comp (&buffer
->cur()), 1u), last_num_components
);
878 _hb_glyph_info_set_lig_props_for_mark (&buffer
->cur(), lig_id
, new_lig_comp
);
880 buffer
->next_glyph ();
883 last_lig_id
= _hb_glyph_info_get_lig_id (&buffer
->cur());
884 last_num_components
= _hb_glyph_info_get_lig_num_comps (&buffer
->cur());
885 components_so_far
+= last_num_components
;
887 /* Skip the base glyph */
891 if (!is_mark_ligature
&& last_lig_id
) {
892 /* Re-adjust components for any marks following. */
893 for (unsigned int i
= buffer
->idx
; i
< buffer
->len
; i
++) {
894 if (last_lig_id
== _hb_glyph_info_get_lig_id (&buffer
->info
[i
])) {
895 unsigned int new_lig_comp
= components_so_far
- last_num_components
+
896 MIN (MAX (_hb_glyph_info_get_lig_comp (&buffer
->info
[i
]), 1u), last_num_components
);
897 _hb_glyph_info_set_lig_props_for_mark (&buffer
->info
[i
], lig_id
, new_lig_comp
);
905 static inline bool match_backtrack (hb_apply_context_t
*c
,
907 const USHORT backtrack
[],
908 match_func_t match_func
,
909 const void *match_data
)
913 hb_apply_context_t::skipping_backward_iterator_t
skippy_iter (c
, c
->buffer
->backtrack_len (), count
, true);
914 skippy_iter
.set_match_func (match_func
, match_data
, backtrack
);
915 if (skippy_iter
.has_no_chance ()) return TRACE_RETURN (false);
917 for (unsigned int i
= 0; i
< count
; i
++)
918 if (!skippy_iter
.prev ())
919 return TRACE_RETURN (false);
921 return TRACE_RETURN (true);
924 static inline bool match_lookahead (hb_apply_context_t
*c
,
926 const USHORT lookahead
[],
927 match_func_t match_func
,
928 const void *match_data
,
933 hb_apply_context_t::skipping_forward_iterator_t
skippy_iter (c
, c
->buffer
->idx
+ offset
- 1, count
, true);
934 skippy_iter
.set_match_func (match_func
, match_data
, lookahead
);
935 if (skippy_iter
.has_no_chance ()) return TRACE_RETURN (false);
937 for (unsigned int i
= 0; i
< count
; i
++)
938 if (!skippy_iter
.next ())
939 return TRACE_RETURN (false);
941 return TRACE_RETURN (true);
948 inline bool sanitize (hb_sanitize_context_t
*c
) {
949 TRACE_SANITIZE (this);
950 return TRACE_RETURN (c
->check_struct (this));
953 USHORT sequenceIndex
; /* Index into current glyph
954 * sequence--first glyph = 0 */
955 USHORT lookupListIndex
; /* Lookup to apply to that
956 * position--zero--based */
958 DEFINE_SIZE_STATIC (4);
962 template <typename context_t
>
963 static inline void recurse_lookups (context_t
*c
,
964 unsigned int lookupCount
,
965 const LookupRecord lookupRecord
[] /* Array of LookupRecords--in design order */)
967 for (unsigned int i
= 0; i
< lookupCount
; i
++)
968 c
->recurse (lookupRecord
[i
].lookupListIndex
);
971 static inline bool apply_lookup (hb_apply_context_t
*c
,
972 unsigned int count
, /* Including the first glyph */
973 unsigned int match_positions
[MAX_CONTEXT_LENGTH
], /* Including the first glyph */
974 unsigned int lookupCount
,
975 const LookupRecord lookupRecord
[], /* Array of LookupRecords--in design order */
976 unsigned int match_length
)
980 hb_buffer_t
*buffer
= c
->buffer
;
983 /* All positions are distance from beginning of *output* buffer.
986 unsigned int bl
= buffer
->backtrack_len ();
987 end
= bl
+ match_length
;
989 int delta
= bl
- buffer
->idx
;
990 /* Convert positions to new indexing. */
991 for (unsigned int j
= 0; j
< count
; j
++)
992 match_positions
[j
] += delta
;
995 for (unsigned int i
= 0; i
< lookupCount
; i
++)
997 unsigned int idx
= lookupRecord
[i
].sequenceIndex
;
1001 buffer
->move_to (match_positions
[idx
]);
1003 unsigned int orig_len
= buffer
->backtrack_len () + buffer
->lookahead_len ();
1004 if (!c
->recurse (lookupRecord
[i
].lookupListIndex
))
1007 unsigned int new_len
= buffer
->backtrack_len () + buffer
->lookahead_len ();
1008 int delta
= new_len
- orig_len
;
1013 /* Recursed lookup changed buffer len. Adjust. */
1015 /* end can't go back past the current match position.
1016 * Note: this is only true because we do NOT allow MultipleSubst
1017 * with zero sequence len. */
1018 end
= MAX ((int) match_positions
[idx
] + 1, int (end
) + delta
);
1020 unsigned int next
= idx
+ 1; /* next now is the position after the recursed lookup. */
1024 if (unlikely (delta
+ count
> MAX_CONTEXT_LENGTH
))
1029 /* NOTE: delta is negative. */
1030 delta
= MAX (delta
, (int) next
- (int) count
);
1035 memmove (match_positions
+ next
+ delta
, match_positions
+ next
,
1036 (count
- next
) * sizeof (match_positions
[0]));
1040 /* Fill in new entries. */
1041 for (unsigned int j
= idx
+ 1; j
< next
; j
++)
1042 match_positions
[j
] = match_positions
[j
- 1] + 1;
1044 /* And fixup the rest. */
1045 for (; next
< count
; next
++)
1046 match_positions
[next
] += delta
;
1049 buffer
->move_to (end
);
1051 return TRACE_RETURN (true);
1056 /* Contextual lookups */
1058 struct ContextClosureLookupContext
1060 ContextClosureFuncs funcs
;
1061 const void *intersects_data
;
1064 struct ContextCollectGlyphsLookupContext
1066 ContextCollectGlyphsFuncs funcs
;
1067 const void *collect_data
;
1070 struct ContextApplyLookupContext
1072 ContextApplyFuncs funcs
;
1073 const void *match_data
;
1076 static inline void context_closure_lookup (hb_closure_context_t
*c
,
1077 unsigned int inputCount
, /* Including the first glyph (not matched) */
1078 const USHORT input
[], /* Array of input values--start with second glyph */
1079 unsigned int lookupCount
,
1080 const LookupRecord lookupRecord
[],
1081 ContextClosureLookupContext
&lookup_context
)
1083 if (intersects_array (c
,
1084 inputCount
? inputCount
- 1 : 0, input
,
1085 lookup_context
.funcs
.intersects
, lookup_context
.intersects_data
))
1087 lookupCount
, lookupRecord
);
1090 static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t
*c
,
1091 unsigned int inputCount
, /* Including the first glyph (not matched) */
1092 const USHORT input
[], /* Array of input values--start with second glyph */
1093 unsigned int lookupCount
,
1094 const LookupRecord lookupRecord
[],
1095 ContextCollectGlyphsLookupContext
&lookup_context
)
1097 collect_array (c
, c
->input
,
1098 inputCount
? inputCount
- 1 : 0, input
,
1099 lookup_context
.funcs
.collect
, lookup_context
.collect_data
);
1101 lookupCount
, lookupRecord
);
1104 static inline bool context_would_apply_lookup (hb_would_apply_context_t
*c
,
1105 unsigned int inputCount
, /* Including the first glyph (not matched) */
1106 const USHORT input
[], /* Array of input values--start with second glyph */
1107 unsigned int lookupCount HB_UNUSED
,
1108 const LookupRecord lookupRecord
[] HB_UNUSED
,
1109 ContextApplyLookupContext
&lookup_context
)
1111 return would_match_input (c
,
1113 lookup_context
.funcs
.match
, lookup_context
.match_data
);
1115 static inline bool context_apply_lookup (hb_apply_context_t
*c
,
1116 unsigned int inputCount
, /* Including the first glyph (not matched) */
1117 const USHORT input
[], /* Array of input values--start with second glyph */
1118 unsigned int lookupCount
,
1119 const LookupRecord lookupRecord
[],
1120 ContextApplyLookupContext
&lookup_context
)
1122 unsigned int match_length
= 0;
1123 unsigned int match_positions
[MAX_CONTEXT_LENGTH
];
1124 return match_input (c
,
1126 lookup_context
.funcs
.match
, lookup_context
.match_data
,
1127 &match_length
, match_positions
)
1129 inputCount
, match_positions
,
1130 lookupCount
, lookupRecord
,
1136 inline void closure (hb_closure_context_t
*c
, ContextClosureLookupContext
&lookup_context
) const
1138 TRACE_CLOSURE (this);
1139 const LookupRecord
*lookupRecord
= &StructAtOffset
<LookupRecord
> (inputZ
, inputZ
[0].static_size
* (inputCount
? inputCount
- 1 : 0));
1140 context_closure_lookup (c
,
1142 lookupCount
, lookupRecord
,
1146 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
, ContextCollectGlyphsLookupContext
&lookup_context
) const
1148 TRACE_COLLECT_GLYPHS (this);
1149 const LookupRecord
*lookupRecord
= &StructAtOffset
<LookupRecord
> (inputZ
, inputZ
[0].static_size
* (inputCount
? inputCount
- 1 : 0));
1150 context_collect_glyphs_lookup (c
,
1152 lookupCount
, lookupRecord
,
1156 inline bool would_apply (hb_would_apply_context_t
*c
, ContextApplyLookupContext
&lookup_context
) const
1158 TRACE_WOULD_APPLY (this);
1159 const LookupRecord
*lookupRecord
= &StructAtOffset
<LookupRecord
> (inputZ
, inputZ
[0].static_size
* (inputCount
? inputCount
- 1 : 0));
1160 return TRACE_RETURN (context_would_apply_lookup (c
, inputCount
, inputZ
, lookupCount
, lookupRecord
, lookup_context
));
1163 inline bool apply (hb_apply_context_t
*c
, ContextApplyLookupContext
&lookup_context
) const
1166 const LookupRecord
*lookupRecord
= &StructAtOffset
<LookupRecord
> (inputZ
, inputZ
[0].static_size
* (inputCount
? inputCount
- 1 : 0));
1167 return TRACE_RETURN (context_apply_lookup (c
, inputCount
, inputZ
, lookupCount
, lookupRecord
, lookup_context
));
1171 inline bool sanitize (hb_sanitize_context_t
*c
) {
1172 TRACE_SANITIZE (this);
1173 return inputCount
.sanitize (c
)
1174 && lookupCount
.sanitize (c
)
1175 && c
->check_range (inputZ
,
1176 inputZ
[0].static_size
* inputCount
1177 + lookupRecordX
[0].static_size
* lookupCount
);
1181 USHORT inputCount
; /* Total number of glyphs in input
1182 * glyph sequence--includes the first
1184 USHORT lookupCount
; /* Number of LookupRecords */
1185 USHORT inputZ
[VAR
]; /* Array of match inputs--start with
1187 LookupRecord lookupRecordX
[VAR
]; /* Array of LookupRecords--in
1190 DEFINE_SIZE_ARRAY2 (4, inputZ
, lookupRecordX
);
1195 inline void closure (hb_closure_context_t
*c
, ContextClosureLookupContext
&lookup_context
) const
1197 TRACE_CLOSURE (this);
1198 unsigned int num_rules
= rule
.len
;
1199 for (unsigned int i
= 0; i
< num_rules
; i
++)
1200 (this+rule
[i
]).closure (c
, lookup_context
);
1203 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
, ContextCollectGlyphsLookupContext
&lookup_context
) const
1205 TRACE_COLLECT_GLYPHS (this);
1206 unsigned int num_rules
= rule
.len
;
1207 for (unsigned int i
= 0; i
< num_rules
; i
++)
1208 (this+rule
[i
]).collect_glyphs (c
, lookup_context
);
1211 inline bool would_apply (hb_would_apply_context_t
*c
, ContextApplyLookupContext
&lookup_context
) const
1213 TRACE_WOULD_APPLY (this);
1214 unsigned int num_rules
= rule
.len
;
1215 for (unsigned int i
= 0; i
< num_rules
; i
++)
1217 if ((this+rule
[i
]).would_apply (c
, lookup_context
))
1218 return TRACE_RETURN (true);
1220 return TRACE_RETURN (false);
1223 inline bool apply (hb_apply_context_t
*c
, ContextApplyLookupContext
&lookup_context
) const
1226 unsigned int num_rules
= rule
.len
;
1227 for (unsigned int i
= 0; i
< num_rules
; i
++)
1229 if ((this+rule
[i
]).apply (c
, lookup_context
))
1230 return TRACE_RETURN (true);
1232 return TRACE_RETURN (false);
1235 inline bool sanitize (hb_sanitize_context_t
*c
) {
1236 TRACE_SANITIZE (this);
1237 return TRACE_RETURN (rule
.sanitize (c
, this));
1242 rule
; /* Array of Rule tables
1243 * ordered by preference */
1245 DEFINE_SIZE_ARRAY (2, rule
);
1249 struct ContextFormat1
1251 inline void closure (hb_closure_context_t
*c
) const
1253 TRACE_CLOSURE (this);
1255 const Coverage
&cov
= (this+coverage
);
1257 struct ContextClosureLookupContext lookup_context
= {
1262 unsigned int count
= ruleSet
.len
;
1263 for (unsigned int i
= 0; i
< count
; i
++)
1264 if (cov
.intersects_coverage (c
->glyphs
, i
)) {
1265 const RuleSet
&rule_set
= this+ruleSet
[i
];
1266 rule_set
.closure (c
, lookup_context
);
1270 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
1272 TRACE_COLLECT_GLYPHS (this);
1273 (this+coverage
).add_coverage (c
->input
);
1275 struct ContextCollectGlyphsLookupContext lookup_context
= {
1280 unsigned int count
= ruleSet
.len
;
1281 for (unsigned int i
= 0; i
< count
; i
++)
1282 (this+ruleSet
[i
]).collect_glyphs (c
, lookup_context
);
1285 inline bool would_apply (hb_would_apply_context_t
*c
) const
1287 TRACE_WOULD_APPLY (this);
1289 const RuleSet
&rule_set
= this+ruleSet
[(this+coverage
).get_coverage (c
->glyphs
[0])];
1290 struct ContextApplyLookupContext lookup_context
= {
1294 return TRACE_RETURN (rule_set
.would_apply (c
, lookup_context
));
1297 inline const Coverage
&get_coverage (void) const
1299 return this+coverage
;
1302 inline bool apply (hb_apply_context_t
*c
) const
1305 unsigned int index
= (this+coverage
).get_coverage (c
->buffer
->cur().codepoint
);
1306 if (likely (index
== NOT_COVERED
))
1307 return TRACE_RETURN (false);
1309 const RuleSet
&rule_set
= this+ruleSet
[index
];
1310 struct ContextApplyLookupContext lookup_context
= {
1314 return TRACE_RETURN (rule_set
.apply (c
, lookup_context
));
1317 inline bool sanitize (hb_sanitize_context_t
*c
) {
1318 TRACE_SANITIZE (this);
1319 return TRACE_RETURN (coverage
.sanitize (c
, this) && ruleSet
.sanitize (c
, this));
1323 USHORT format
; /* Format identifier--format = 1 */
1325 coverage
; /* Offset to Coverage table--from
1326 * beginning of table */
1327 OffsetArrayOf
<RuleSet
>
1328 ruleSet
; /* Array of RuleSet tables
1329 * ordered by Coverage Index */
1331 DEFINE_SIZE_ARRAY (6, ruleSet
);
1335 struct ContextFormat2
1337 inline void closure (hb_closure_context_t
*c
) const
1339 TRACE_CLOSURE (this);
1340 if (!(this+coverage
).intersects (c
->glyphs
))
1343 const ClassDef
&class_def
= this+classDef
;
1345 struct ContextClosureLookupContext lookup_context
= {
1350 unsigned int count
= ruleSet
.len
;
1351 for (unsigned int i
= 0; i
< count
; i
++)
1352 if (class_def
.intersects_class (c
->glyphs
, i
)) {
1353 const RuleSet
&rule_set
= this+ruleSet
[i
];
1354 rule_set
.closure (c
, lookup_context
);
1358 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
1360 TRACE_COLLECT_GLYPHS (this);
1361 (this+coverage
).add_coverage (c
->input
);
1363 const ClassDef
&class_def
= this+classDef
;
1364 struct ContextCollectGlyphsLookupContext lookup_context
= {
1369 unsigned int count
= ruleSet
.len
;
1370 for (unsigned int i
= 0; i
< count
; i
++)
1371 (this+ruleSet
[i
]).collect_glyphs (c
, lookup_context
);
1374 inline bool would_apply (hb_would_apply_context_t
*c
) const
1376 TRACE_WOULD_APPLY (this);
1378 const ClassDef
&class_def
= this+classDef
;
1379 unsigned int index
= class_def
.get_class (c
->glyphs
[0]);
1380 const RuleSet
&rule_set
= this+ruleSet
[index
];
1381 struct ContextApplyLookupContext lookup_context
= {
1385 return TRACE_RETURN (rule_set
.would_apply (c
, lookup_context
));
1388 inline const Coverage
&get_coverage (void) const
1390 return this+coverage
;
1393 inline bool apply (hb_apply_context_t
*c
) const
1396 unsigned int index
= (this+coverage
).get_coverage (c
->buffer
->cur().codepoint
);
1397 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
1399 const ClassDef
&class_def
= this+classDef
;
1400 index
= class_def
.get_class (c
->buffer
->cur().codepoint
);
1401 const RuleSet
&rule_set
= this+ruleSet
[index
];
1402 struct ContextApplyLookupContext lookup_context
= {
1406 return TRACE_RETURN (rule_set
.apply (c
, lookup_context
));
1409 inline bool sanitize (hb_sanitize_context_t
*c
) {
1410 TRACE_SANITIZE (this);
1411 return TRACE_RETURN (coverage
.sanitize (c
, this) && classDef
.sanitize (c
, this) && ruleSet
.sanitize (c
, this));
1415 USHORT format
; /* Format identifier--format = 2 */
1417 coverage
; /* Offset to Coverage table--from
1418 * beginning of table */
1420 classDef
; /* Offset to glyph ClassDef table--from
1421 * beginning of table */
1422 OffsetArrayOf
<RuleSet
>
1423 ruleSet
; /* Array of RuleSet tables
1424 * ordered by class */
1426 DEFINE_SIZE_ARRAY (8, ruleSet
);
1430 struct ContextFormat3
1432 inline void closure (hb_closure_context_t
*c
) const
1434 TRACE_CLOSURE (this);
1435 if (!(this+coverageZ
[0]).intersects (c
->glyphs
))
1438 const LookupRecord
*lookupRecord
= &StructAtOffset
<LookupRecord
> (coverageZ
, coverageZ
[0].static_size
* glyphCount
);
1439 struct ContextClosureLookupContext lookup_context
= {
1440 {intersects_coverage
},
1443 context_closure_lookup (c
,
1444 glyphCount
, (const USHORT
*) (coverageZ
+ 1),
1445 lookupCount
, lookupRecord
,
1449 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
1451 TRACE_COLLECT_GLYPHS (this);
1452 (this+coverageZ
[0]).add_coverage (c
->input
);
1454 const LookupRecord
*lookupRecord
= &StructAtOffset
<LookupRecord
> (coverageZ
, coverageZ
[0].static_size
* glyphCount
);
1455 struct ContextCollectGlyphsLookupContext lookup_context
= {
1460 context_collect_glyphs_lookup (c
,
1461 glyphCount
, (const USHORT
*) (coverageZ
+ 1),
1462 lookupCount
, lookupRecord
,
1466 inline bool would_apply (hb_would_apply_context_t
*c
) const
1468 TRACE_WOULD_APPLY (this);
1470 const LookupRecord
*lookupRecord
= &StructAtOffset
<LookupRecord
> (coverageZ
, coverageZ
[0].static_size
* glyphCount
);
1471 struct ContextApplyLookupContext lookup_context
= {
1475 return TRACE_RETURN (context_would_apply_lookup (c
, glyphCount
, (const USHORT
*) (coverageZ
+ 1), lookupCount
, lookupRecord
, lookup_context
));
1478 inline const Coverage
&get_coverage (void) const
1480 return this+coverageZ
[0];
1483 inline bool apply (hb_apply_context_t
*c
) const
1486 unsigned int index
= (this+coverageZ
[0]).get_coverage (c
->buffer
->cur().codepoint
);
1487 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
1489 const LookupRecord
*lookupRecord
= &StructAtOffset
<LookupRecord
> (coverageZ
, coverageZ
[0].static_size
* glyphCount
);
1490 struct ContextApplyLookupContext lookup_context
= {
1494 return TRACE_RETURN (context_apply_lookup (c
, glyphCount
, (const USHORT
*) (coverageZ
+ 1), lookupCount
, lookupRecord
, lookup_context
));
1497 inline bool sanitize (hb_sanitize_context_t
*c
) {
1498 TRACE_SANITIZE (this);
1499 if (!c
->check_struct (this)) return TRACE_RETURN (false);
1500 unsigned int count
= glyphCount
;
1501 if (!count
) return TRACE_RETURN (false); /* We want to access coverageZ[0] freely. */
1502 if (!c
->check_array (coverageZ
, coverageZ
[0].static_size
, count
)) return TRACE_RETURN (false);
1503 for (unsigned int i
= 0; i
< count
; i
++)
1504 if (!coverageZ
[i
].sanitize (c
, this)) return TRACE_RETURN (false);
1505 LookupRecord
*lookupRecord
= &StructAtOffset
<LookupRecord
> (coverageZ
, coverageZ
[0].static_size
* count
);
1506 return TRACE_RETURN (c
->check_array (lookupRecord
, lookupRecord
[0].static_size
, lookupCount
));
1510 USHORT format
; /* Format identifier--format = 3 */
1511 USHORT glyphCount
; /* Number of glyphs in the input glyph
1513 USHORT lookupCount
; /* Number of LookupRecords */
1515 coverageZ
[VAR
]; /* Array of offsets to Coverage
1516 * table in glyph sequence order */
1517 LookupRecord lookupRecordX
[VAR
]; /* Array of LookupRecords--in
1520 DEFINE_SIZE_ARRAY2 (6, coverageZ
, lookupRecordX
);
1525 template <typename context_t
>
1526 inline typename
context_t::return_t
dispatch (context_t
*c
) const
1528 TRACE_DISPATCH (this, u
.format
);
1530 case 1: return TRACE_RETURN (c
->dispatch (u
.format1
));
1531 case 2: return TRACE_RETURN (c
->dispatch (u
.format2
));
1532 case 3: return TRACE_RETURN (c
->dispatch (u
.format3
));
1533 default:return TRACE_RETURN (c
->default_return_value ());
1537 inline bool sanitize (hb_sanitize_context_t
*c
) {
1538 TRACE_SANITIZE (this);
1539 if (!u
.format
.sanitize (c
)) return TRACE_RETURN (false);
1541 case 1: return TRACE_RETURN (u
.format1
.sanitize (c
));
1542 case 2: return TRACE_RETURN (u
.format2
.sanitize (c
));
1543 case 3: return TRACE_RETURN (u
.format3
.sanitize (c
));
1544 default:return TRACE_RETURN (true);
1550 USHORT format
; /* Format identifier */
1551 ContextFormat1 format1
;
1552 ContextFormat2 format2
;
1553 ContextFormat3 format3
;
1558 /* Chaining Contextual lookups */
1560 struct ChainContextClosureLookupContext
1562 ContextClosureFuncs funcs
;
1563 const void *intersects_data
[3];
1566 struct ChainContextCollectGlyphsLookupContext
1568 ContextCollectGlyphsFuncs funcs
;
1569 const void *collect_data
[3];
1572 struct ChainContextApplyLookupContext
1574 ContextApplyFuncs funcs
;
1575 const void *match_data
[3];
1578 static inline void chain_context_closure_lookup (hb_closure_context_t
*c
,
1579 unsigned int backtrackCount
,
1580 const USHORT backtrack
[],
1581 unsigned int inputCount
, /* Including the first glyph (not matched) */
1582 const USHORT input
[], /* Array of input values--start with second glyph */
1583 unsigned int lookaheadCount
,
1584 const USHORT lookahead
[],
1585 unsigned int lookupCount
,
1586 const LookupRecord lookupRecord
[],
1587 ChainContextClosureLookupContext
&lookup_context
)
1589 if (intersects_array (c
,
1590 backtrackCount
, backtrack
,
1591 lookup_context
.funcs
.intersects
, lookup_context
.intersects_data
[0])
1592 && intersects_array (c
,
1593 inputCount
? inputCount
- 1 : 0, input
,
1594 lookup_context
.funcs
.intersects
, lookup_context
.intersects_data
[1])
1595 && intersects_array (c
,
1596 lookaheadCount
, lookahead
,
1597 lookup_context
.funcs
.intersects
, lookup_context
.intersects_data
[2]))
1599 lookupCount
, lookupRecord
);
1602 static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t
*c
,
1603 unsigned int backtrackCount
,
1604 const USHORT backtrack
[],
1605 unsigned int inputCount
, /* Including the first glyph (not matched) */
1606 const USHORT input
[], /* Array of input values--start with second glyph */
1607 unsigned int lookaheadCount
,
1608 const USHORT lookahead
[],
1609 unsigned int lookupCount
,
1610 const LookupRecord lookupRecord
[],
1611 ChainContextCollectGlyphsLookupContext
&lookup_context
)
1613 collect_array (c
, c
->before
,
1614 backtrackCount
, backtrack
,
1615 lookup_context
.funcs
.collect
, lookup_context
.collect_data
[0]);
1616 collect_array (c
, c
->input
,
1617 inputCount
? inputCount
- 1 : 0, input
,
1618 lookup_context
.funcs
.collect
, lookup_context
.collect_data
[1]);
1619 collect_array (c
, c
->after
,
1620 lookaheadCount
, lookahead
,
1621 lookup_context
.funcs
.collect
, lookup_context
.collect_data
[2]);
1623 lookupCount
, lookupRecord
);
1626 static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t
*c
,
1627 unsigned int backtrackCount
,
1628 const USHORT backtrack
[] HB_UNUSED
,
1629 unsigned int inputCount
, /* Including the first glyph (not matched) */
1630 const USHORT input
[], /* Array of input values--start with second glyph */
1631 unsigned int lookaheadCount
,
1632 const USHORT lookahead
[] HB_UNUSED
,
1633 unsigned int lookupCount HB_UNUSED
,
1634 const LookupRecord lookupRecord
[] HB_UNUSED
,
1635 ChainContextApplyLookupContext
&lookup_context
)
1637 return (c
->zero_context
? !backtrackCount
&& !lookaheadCount
: true)
1638 && would_match_input (c
,
1640 lookup_context
.funcs
.match
, lookup_context
.match_data
[1]);
1643 static inline bool chain_context_apply_lookup (hb_apply_context_t
*c
,
1644 unsigned int backtrackCount
,
1645 const USHORT backtrack
[],
1646 unsigned int inputCount
, /* Including the first glyph (not matched) */
1647 const USHORT input
[], /* Array of input values--start with second glyph */
1648 unsigned int lookaheadCount
,
1649 const USHORT lookahead
[],
1650 unsigned int lookupCount
,
1651 const LookupRecord lookupRecord
[],
1652 ChainContextApplyLookupContext
&lookup_context
)
1654 unsigned int match_length
= 0;
1655 unsigned int match_positions
[MAX_CONTEXT_LENGTH
];
1656 return match_input (c
,
1658 lookup_context
.funcs
.match
, lookup_context
.match_data
[1],
1659 &match_length
, match_positions
)
1660 && match_backtrack (c
,
1661 backtrackCount
, backtrack
,
1662 lookup_context
.funcs
.match
, lookup_context
.match_data
[0])
1663 && match_lookahead (c
,
1664 lookaheadCount
, lookahead
,
1665 lookup_context
.funcs
.match
, lookup_context
.match_data
[2],
1668 inputCount
, match_positions
,
1669 lookupCount
, lookupRecord
,
1675 inline void closure (hb_closure_context_t
*c
, ChainContextClosureLookupContext
&lookup_context
) const
1677 TRACE_CLOSURE (this);
1678 const HeadlessArrayOf
<USHORT
> &input
= StructAfter
<HeadlessArrayOf
<USHORT
> > (backtrack
);
1679 const ArrayOf
<USHORT
> &lookahead
= StructAfter
<ArrayOf
<USHORT
> > (input
);
1680 const ArrayOf
<LookupRecord
> &lookup
= StructAfter
<ArrayOf
<LookupRecord
> > (lookahead
);
1681 chain_context_closure_lookup (c
,
1682 backtrack
.len
, backtrack
.array
,
1683 input
.len
, input
.array
,
1684 lookahead
.len
, lookahead
.array
,
1685 lookup
.len
, lookup
.array
,
1689 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
, ChainContextCollectGlyphsLookupContext
&lookup_context
) const
1691 TRACE_COLLECT_GLYPHS (this);
1692 const HeadlessArrayOf
<USHORT
> &input
= StructAfter
<HeadlessArrayOf
<USHORT
> > (backtrack
);
1693 const ArrayOf
<USHORT
> &lookahead
= StructAfter
<ArrayOf
<USHORT
> > (input
);
1694 const ArrayOf
<LookupRecord
> &lookup
= StructAfter
<ArrayOf
<LookupRecord
> > (lookahead
);
1695 chain_context_collect_glyphs_lookup (c
,
1696 backtrack
.len
, backtrack
.array
,
1697 input
.len
, input
.array
,
1698 lookahead
.len
, lookahead
.array
,
1699 lookup
.len
, lookup
.array
,
1703 inline bool would_apply (hb_would_apply_context_t
*c
, ChainContextApplyLookupContext
&lookup_context
) const
1705 TRACE_WOULD_APPLY (this);
1706 const HeadlessArrayOf
<USHORT
> &input
= StructAfter
<HeadlessArrayOf
<USHORT
> > (backtrack
);
1707 const ArrayOf
<USHORT
> &lookahead
= StructAfter
<ArrayOf
<USHORT
> > (input
);
1708 const ArrayOf
<LookupRecord
> &lookup
= StructAfter
<ArrayOf
<LookupRecord
> > (lookahead
);
1709 return TRACE_RETURN (chain_context_would_apply_lookup (c
,
1710 backtrack
.len
, backtrack
.array
,
1711 input
.len
, input
.array
,
1712 lookahead
.len
, lookahead
.array
, lookup
.len
,
1713 lookup
.array
, lookup_context
));
1716 inline bool apply (hb_apply_context_t
*c
, ChainContextApplyLookupContext
&lookup_context
) const
1719 const HeadlessArrayOf
<USHORT
> &input
= StructAfter
<HeadlessArrayOf
<USHORT
> > (backtrack
);
1720 const ArrayOf
<USHORT
> &lookahead
= StructAfter
<ArrayOf
<USHORT
> > (input
);
1721 const ArrayOf
<LookupRecord
> &lookup
= StructAfter
<ArrayOf
<LookupRecord
> > (lookahead
);
1722 return TRACE_RETURN (chain_context_apply_lookup (c
,
1723 backtrack
.len
, backtrack
.array
,
1724 input
.len
, input
.array
,
1725 lookahead
.len
, lookahead
.array
, lookup
.len
,
1726 lookup
.array
, lookup_context
));
1729 inline bool sanitize (hb_sanitize_context_t
*c
) {
1730 TRACE_SANITIZE (this);
1731 if (!backtrack
.sanitize (c
)) return TRACE_RETURN (false);
1732 HeadlessArrayOf
<USHORT
> &input
= StructAfter
<HeadlessArrayOf
<USHORT
> > (backtrack
);
1733 if (!input
.sanitize (c
)) return TRACE_RETURN (false);
1734 ArrayOf
<USHORT
> &lookahead
= StructAfter
<ArrayOf
<USHORT
> > (input
);
1735 if (!lookahead
.sanitize (c
)) return TRACE_RETURN (false);
1736 ArrayOf
<LookupRecord
> &lookup
= StructAfter
<ArrayOf
<LookupRecord
> > (lookahead
);
1737 return TRACE_RETURN (lookup
.sanitize (c
));
1742 backtrack
; /* Array of backtracking values
1743 * (to be matched before the input
1745 HeadlessArrayOf
<USHORT
>
1746 inputX
; /* Array of input values (start with
1749 lookaheadX
; /* Array of lookahead values's (to be
1750 * matched after the input sequence) */
1751 ArrayOf
<LookupRecord
>
1752 lookupX
; /* Array of LookupRecords--in
1755 DEFINE_SIZE_MIN (8);
1760 inline void closure (hb_closure_context_t
*c
, ChainContextClosureLookupContext
&lookup_context
) const
1762 TRACE_CLOSURE (this);
1763 unsigned int num_rules
= rule
.len
;
1764 for (unsigned int i
= 0; i
< num_rules
; i
++)
1765 (this+rule
[i
]).closure (c
, lookup_context
);
1768 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
, ChainContextCollectGlyphsLookupContext
&lookup_context
) const
1770 TRACE_COLLECT_GLYPHS (this);
1771 unsigned int num_rules
= rule
.len
;
1772 for (unsigned int i
= 0; i
< num_rules
; i
++)
1773 (this+rule
[i
]).collect_glyphs (c
, lookup_context
);
1776 inline bool would_apply (hb_would_apply_context_t
*c
, ChainContextApplyLookupContext
&lookup_context
) const
1778 TRACE_WOULD_APPLY (this);
1779 unsigned int num_rules
= rule
.len
;
1780 for (unsigned int i
= 0; i
< num_rules
; i
++)
1781 if ((this+rule
[i
]).would_apply (c
, lookup_context
))
1782 return TRACE_RETURN (true);
1784 return TRACE_RETURN (false);
1787 inline bool apply (hb_apply_context_t
*c
, ChainContextApplyLookupContext
&lookup_context
) const
1790 unsigned int num_rules
= rule
.len
;
1791 for (unsigned int i
= 0; i
< num_rules
; i
++)
1792 if ((this+rule
[i
]).apply (c
, lookup_context
))
1793 return TRACE_RETURN (true);
1795 return TRACE_RETURN (false);
1798 inline bool sanitize (hb_sanitize_context_t
*c
) {
1799 TRACE_SANITIZE (this);
1800 return TRACE_RETURN (rule
.sanitize (c
, this));
1804 OffsetArrayOf
<ChainRule
>
1805 rule
; /* Array of ChainRule tables
1806 * ordered by preference */
1808 DEFINE_SIZE_ARRAY (2, rule
);
1811 struct ChainContextFormat1
1813 inline void closure (hb_closure_context_t
*c
) const
1815 TRACE_CLOSURE (this);
1816 const Coverage
&cov
= (this+coverage
);
1818 struct ChainContextClosureLookupContext lookup_context
= {
1823 unsigned int count
= ruleSet
.len
;
1824 for (unsigned int i
= 0; i
< count
; i
++)
1825 if (cov
.intersects_coverage (c
->glyphs
, i
)) {
1826 const ChainRuleSet
&rule_set
= this+ruleSet
[i
];
1827 rule_set
.closure (c
, lookup_context
);
1831 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
1833 TRACE_COLLECT_GLYPHS (this);
1834 (this+coverage
).add_coverage (c
->input
);
1836 struct ChainContextCollectGlyphsLookupContext lookup_context
= {
1841 unsigned int count
= ruleSet
.len
;
1842 for (unsigned int i
= 0; i
< count
; i
++)
1843 (this+ruleSet
[i
]).collect_glyphs (c
, lookup_context
);
1846 inline bool would_apply (hb_would_apply_context_t
*c
) const
1848 TRACE_WOULD_APPLY (this);
1850 const ChainRuleSet
&rule_set
= this+ruleSet
[(this+coverage
).get_coverage (c
->glyphs
[0])];
1851 struct ChainContextApplyLookupContext lookup_context
= {
1855 return TRACE_RETURN (rule_set
.would_apply (c
, lookup_context
));
1858 inline const Coverage
&get_coverage (void) const
1860 return this+coverage
;
1863 inline bool apply (hb_apply_context_t
*c
) const
1866 unsigned int index
= (this+coverage
).get_coverage (c
->buffer
->cur().codepoint
);
1867 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
1869 const ChainRuleSet
&rule_set
= this+ruleSet
[index
];
1870 struct ChainContextApplyLookupContext lookup_context
= {
1874 return TRACE_RETURN (rule_set
.apply (c
, lookup_context
));
1877 inline bool sanitize (hb_sanitize_context_t
*c
) {
1878 TRACE_SANITIZE (this);
1879 return TRACE_RETURN (coverage
.sanitize (c
, this) && ruleSet
.sanitize (c
, this));
1883 USHORT format
; /* Format identifier--format = 1 */
1885 coverage
; /* Offset to Coverage table--from
1886 * beginning of table */
1887 OffsetArrayOf
<ChainRuleSet
>
1888 ruleSet
; /* Array of ChainRuleSet tables
1889 * ordered by Coverage Index */
1891 DEFINE_SIZE_ARRAY (6, ruleSet
);
1894 struct ChainContextFormat2
1896 inline void closure (hb_closure_context_t
*c
) const
1898 TRACE_CLOSURE (this);
1899 if (!(this+coverage
).intersects (c
->glyphs
))
1902 const ClassDef
&backtrack_class_def
= this+backtrackClassDef
;
1903 const ClassDef
&input_class_def
= this+inputClassDef
;
1904 const ClassDef
&lookahead_class_def
= this+lookaheadClassDef
;
1906 struct ChainContextClosureLookupContext lookup_context
= {
1908 {&backtrack_class_def
,
1910 &lookahead_class_def
}
1913 unsigned int count
= ruleSet
.len
;
1914 for (unsigned int i
= 0; i
< count
; i
++)
1915 if (input_class_def
.intersects_class (c
->glyphs
, i
)) {
1916 const ChainRuleSet
&rule_set
= this+ruleSet
[i
];
1917 rule_set
.closure (c
, lookup_context
);
1921 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
1923 TRACE_COLLECT_GLYPHS (this);
1924 (this+coverage
).add_coverage (c
->input
);
1926 const ClassDef
&backtrack_class_def
= this+backtrackClassDef
;
1927 const ClassDef
&input_class_def
= this+inputClassDef
;
1928 const ClassDef
&lookahead_class_def
= this+lookaheadClassDef
;
1930 struct ChainContextCollectGlyphsLookupContext lookup_context
= {
1932 {&backtrack_class_def
,
1934 &lookahead_class_def
}
1937 unsigned int count
= ruleSet
.len
;
1938 for (unsigned int i
= 0; i
< count
; i
++)
1939 (this+ruleSet
[i
]).collect_glyphs (c
, lookup_context
);
1942 inline bool would_apply (hb_would_apply_context_t
*c
) const
1944 TRACE_WOULD_APPLY (this);
1946 const ClassDef
&backtrack_class_def
= this+backtrackClassDef
;
1947 const ClassDef
&input_class_def
= this+inputClassDef
;
1948 const ClassDef
&lookahead_class_def
= this+lookaheadClassDef
;
1950 unsigned int index
= input_class_def
.get_class (c
->glyphs
[0]);
1951 const ChainRuleSet
&rule_set
= this+ruleSet
[index
];
1952 struct ChainContextApplyLookupContext lookup_context
= {
1954 {&backtrack_class_def
,
1956 &lookahead_class_def
}
1958 return TRACE_RETURN (rule_set
.would_apply (c
, lookup_context
));
1961 inline const Coverage
&get_coverage (void) const
1963 return this+coverage
;
1966 inline bool apply (hb_apply_context_t
*c
) const
1969 unsigned int index
= (this+coverage
).get_coverage (c
->buffer
->cur().codepoint
);
1970 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
1972 const ClassDef
&backtrack_class_def
= this+backtrackClassDef
;
1973 const ClassDef
&input_class_def
= this+inputClassDef
;
1974 const ClassDef
&lookahead_class_def
= this+lookaheadClassDef
;
1976 index
= input_class_def
.get_class (c
->buffer
->cur().codepoint
);
1977 const ChainRuleSet
&rule_set
= this+ruleSet
[index
];
1978 struct ChainContextApplyLookupContext lookup_context
= {
1980 {&backtrack_class_def
,
1982 &lookahead_class_def
}
1984 return TRACE_RETURN (rule_set
.apply (c
, lookup_context
));
1987 inline bool sanitize (hb_sanitize_context_t
*c
) {
1988 TRACE_SANITIZE (this);
1989 return TRACE_RETURN (coverage
.sanitize (c
, this) && backtrackClassDef
.sanitize (c
, this) &&
1990 inputClassDef
.sanitize (c
, this) && lookaheadClassDef
.sanitize (c
, this) &&
1991 ruleSet
.sanitize (c
, this));
1995 USHORT format
; /* Format identifier--format = 2 */
1997 coverage
; /* Offset to Coverage table--from
1998 * beginning of table */
2000 backtrackClassDef
; /* Offset to glyph ClassDef table
2001 * containing backtrack sequence
2002 * data--from beginning of table */
2004 inputClassDef
; /* Offset to glyph ClassDef
2005 * table containing input sequence
2006 * data--from beginning of table */
2008 lookaheadClassDef
; /* Offset to glyph ClassDef table
2009 * containing lookahead sequence
2010 * data--from beginning of table */
2011 OffsetArrayOf
<ChainRuleSet
>
2012 ruleSet
; /* Array of ChainRuleSet tables
2013 * ordered by class */
2015 DEFINE_SIZE_ARRAY (12, ruleSet
);
2018 struct ChainContextFormat3
2020 inline void closure (hb_closure_context_t
*c
) const
2022 TRACE_CLOSURE (this);
2023 const OffsetArrayOf
<Coverage
> &input
= StructAfter
<OffsetArrayOf
<Coverage
> > (backtrack
);
2025 if (!(this+input
[0]).intersects (c
->glyphs
))
2028 const OffsetArrayOf
<Coverage
> &lookahead
= StructAfter
<OffsetArrayOf
<Coverage
> > (input
);
2029 const ArrayOf
<LookupRecord
> &lookup
= StructAfter
<ArrayOf
<LookupRecord
> > (lookahead
);
2030 struct ChainContextClosureLookupContext lookup_context
= {
2031 {intersects_coverage
},
2034 chain_context_closure_lookup (c
,
2035 backtrack
.len
, (const USHORT
*) backtrack
.array
,
2036 input
.len
, (const USHORT
*) input
.array
+ 1,
2037 lookahead
.len
, (const USHORT
*) lookahead
.array
,
2038 lookup
.len
, lookup
.array
,
2042 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
2044 TRACE_COLLECT_GLYPHS (this);
2045 const OffsetArrayOf
<Coverage
> &input
= StructAfter
<OffsetArrayOf
<Coverage
> > (backtrack
);
2047 (this+input
[0]).add_coverage (c
->input
);
2049 const OffsetArrayOf
<Coverage
> &lookahead
= StructAfter
<OffsetArrayOf
<Coverage
> > (input
);
2050 const ArrayOf
<LookupRecord
> &lookup
= StructAfter
<ArrayOf
<LookupRecord
> > (lookahead
);
2051 struct ChainContextCollectGlyphsLookupContext lookup_context
= {
2055 chain_context_collect_glyphs_lookup (c
,
2056 backtrack
.len
, (const USHORT
*) backtrack
.array
,
2057 input
.len
, (const USHORT
*) input
.array
+ 1,
2058 lookahead
.len
, (const USHORT
*) lookahead
.array
,
2059 lookup
.len
, lookup
.array
,
2063 inline bool would_apply (hb_would_apply_context_t
*c
) const
2065 TRACE_WOULD_APPLY (this);
2067 const OffsetArrayOf
<Coverage
> &input
= StructAfter
<OffsetArrayOf
<Coverage
> > (backtrack
);
2068 const OffsetArrayOf
<Coverage
> &lookahead
= StructAfter
<OffsetArrayOf
<Coverage
> > (input
);
2069 const ArrayOf
<LookupRecord
> &lookup
= StructAfter
<ArrayOf
<LookupRecord
> > (lookahead
);
2070 struct ChainContextApplyLookupContext lookup_context
= {
2074 return TRACE_RETURN (chain_context_would_apply_lookup (c
,
2075 backtrack
.len
, (const USHORT
*) backtrack
.array
,
2076 input
.len
, (const USHORT
*) input
.array
+ 1,
2077 lookahead
.len
, (const USHORT
*) lookahead
.array
,
2078 lookup
.len
, lookup
.array
, lookup_context
));
2081 inline const Coverage
&get_coverage (void) const
2083 const OffsetArrayOf
<Coverage
> &input
= StructAfter
<OffsetArrayOf
<Coverage
> > (backtrack
);
2084 return this+input
[0];
2087 inline bool apply (hb_apply_context_t
*c
) const
2090 const OffsetArrayOf
<Coverage
> &input
= StructAfter
<OffsetArrayOf
<Coverage
> > (backtrack
);
2092 unsigned int index
= (this+input
[0]).get_coverage (c
->buffer
->cur().codepoint
);
2093 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
2095 const OffsetArrayOf
<Coverage
> &lookahead
= StructAfter
<OffsetArrayOf
<Coverage
> > (input
);
2096 const ArrayOf
<LookupRecord
> &lookup
= StructAfter
<ArrayOf
<LookupRecord
> > (lookahead
);
2097 struct ChainContextApplyLookupContext lookup_context
= {
2101 return TRACE_RETURN (chain_context_apply_lookup (c
,
2102 backtrack
.len
, (const USHORT
*) backtrack
.array
,
2103 input
.len
, (const USHORT
*) input
.array
+ 1,
2104 lookahead
.len
, (const USHORT
*) lookahead
.array
,
2105 lookup
.len
, lookup
.array
, lookup_context
));
2108 inline bool sanitize (hb_sanitize_context_t
*c
) {
2109 TRACE_SANITIZE (this);
2110 if (!backtrack
.sanitize (c
, this)) return TRACE_RETURN (false);
2111 OffsetArrayOf
<Coverage
> &input
= StructAfter
<OffsetArrayOf
<Coverage
> > (backtrack
);
2112 if (!input
.sanitize (c
, this)) return TRACE_RETURN (false);
2113 if (!input
.len
) return TRACE_RETURN (false); /* To be consistent with Context. */
2114 OffsetArrayOf
<Coverage
> &lookahead
= StructAfter
<OffsetArrayOf
<Coverage
> > (input
);
2115 if (!lookahead
.sanitize (c
, this)) return TRACE_RETURN (false);
2116 ArrayOf
<LookupRecord
> &lookup
= StructAfter
<ArrayOf
<LookupRecord
> > (lookahead
);
2117 return TRACE_RETURN (lookup
.sanitize (c
));
2121 USHORT format
; /* Format identifier--format = 3 */
2122 OffsetArrayOf
<Coverage
>
2123 backtrack
; /* Array of coverage tables
2124 * in backtracking sequence, in glyph
2126 OffsetArrayOf
<Coverage
>
2127 inputX
; /* Array of coverage
2128 * tables in input sequence, in glyph
2130 OffsetArrayOf
<Coverage
>
2131 lookaheadX
; /* Array of coverage tables
2132 * in lookahead sequence, in glyph
2134 ArrayOf
<LookupRecord
>
2135 lookupX
; /* Array of LookupRecords--in
2138 DEFINE_SIZE_MIN (10);
2143 template <typename context_t
>
2144 inline typename
context_t::return_t
dispatch (context_t
*c
) const
2146 TRACE_DISPATCH (this, u
.format
);
2148 case 1: return TRACE_RETURN (c
->dispatch (u
.format1
));
2149 case 2: return TRACE_RETURN (c
->dispatch (u
.format2
));
2150 case 3: return TRACE_RETURN (c
->dispatch (u
.format3
));
2151 default:return TRACE_RETURN (c
->default_return_value ());
2155 inline bool sanitize (hb_sanitize_context_t
*c
) {
2156 TRACE_SANITIZE (this);
2157 if (!u
.format
.sanitize (c
)) return TRACE_RETURN (false);
2159 case 1: return TRACE_RETURN (u
.format1
.sanitize (c
));
2160 case 2: return TRACE_RETURN (u
.format2
.sanitize (c
));
2161 case 3: return TRACE_RETURN (u
.format3
.sanitize (c
));
2162 default:return TRACE_RETURN (true);
2168 USHORT format
; /* Format identifier */
2169 ChainContextFormat1 format1
;
2170 ChainContextFormat2 format2
;
2171 ChainContextFormat3 format3
;
2176 struct ExtensionFormat1
2178 inline unsigned int get_type (void) const { return extensionLookupType
; }
2179 inline unsigned int get_offset (void) const { return extensionOffset
; }
2181 inline bool sanitize (hb_sanitize_context_t
*c
) {
2182 TRACE_SANITIZE (this);
2183 return TRACE_RETURN (c
->check_struct (this));
2187 USHORT format
; /* Format identifier. Set to 1. */
2188 USHORT extensionLookupType
; /* Lookup type of subtable referenced
2189 * by ExtensionOffset (i.e. the
2190 * extension subtable). */
2191 ULONG extensionOffset
; /* Offset to the extension subtable,
2192 * of lookup type subtable. */
2194 DEFINE_SIZE_STATIC (8);
2197 template <typename T
>
2200 inline unsigned int get_type (void) const
2203 case 1: return u
.format1
.get_type ();
2207 inline unsigned int get_offset (void) const
2210 case 1: return u
.format1
.get_offset ();
2215 template <typename X
>
2216 inline const X
& get_subtable (void) const
2218 unsigned int offset
= get_offset ();
2219 if (unlikely (!offset
)) return Null(typename
T::LookupSubTable
);
2220 return StructAtOffset
<typename
T::LookupSubTable
> (this, offset
);
2223 template <typename context_t
>
2224 inline typename
context_t::return_t
dispatch (context_t
*c
) const
2226 return get_subtable
<typename
T::LookupSubTable
> ().dispatch (c
, get_type ());
2229 inline bool sanitize_self (hb_sanitize_context_t
*c
) {
2230 TRACE_SANITIZE (this);
2231 if (!u
.format
.sanitize (c
)) return TRACE_RETURN (false);
2233 case 1: return TRACE_RETURN (u
.format1
.sanitize (c
));
2234 default:return TRACE_RETURN (true);
2238 inline bool sanitize (hb_sanitize_context_t
*c
) {
2239 TRACE_SANITIZE (this);
2240 if (!sanitize_self (c
)) return TRACE_RETURN (false);
2241 unsigned int offset
= get_offset ();
2242 if (unlikely (!offset
)) return TRACE_RETURN (true);
2243 return TRACE_RETURN (StructAtOffset
<typename
T::LookupSubTable
> (this, offset
).sanitize (c
, get_type ()));
2248 USHORT format
; /* Format identifier */
2249 ExtensionFormat1 format1
;
2260 static const hb_tag_t GSUBTag
= HB_OT_TAG_GSUB
;
2261 static const hb_tag_t GPOSTag
= HB_OT_TAG_GPOS
;
2263 inline unsigned int get_script_count (void) const
2264 { return (this+scriptList
).len
; }
2265 inline const Tag
& get_script_tag (unsigned int i
) const
2266 { return (this+scriptList
).get_tag (i
); }
2267 inline unsigned int get_script_tags (unsigned int start_offset
,
2268 unsigned int *script_count
/* IN/OUT */,
2269 hb_tag_t
*script_tags
/* OUT */) const
2270 { return (this+scriptList
).get_tags (start_offset
, script_count
, script_tags
); }
2271 inline const Script
& get_script (unsigned int i
) const
2272 { return (this+scriptList
)[i
]; }
2273 inline bool find_script_index (hb_tag_t tag
, unsigned int *index
) const
2274 { return (this+scriptList
).find_index (tag
, index
); }
2276 inline unsigned int get_feature_count (void) const
2277 { return (this+featureList
).len
; }
2278 inline hb_tag_t
get_feature_tag (unsigned int i
) const
2279 { return i
== Index::NOT_FOUND_INDEX
? HB_TAG_NONE
: (this+featureList
).get_tag (i
); }
2280 inline unsigned int get_feature_tags (unsigned int start_offset
,
2281 unsigned int *feature_count
/* IN/OUT */,
2282 hb_tag_t
*feature_tags
/* OUT */) const
2283 { return (this+featureList
).get_tags (start_offset
, feature_count
, feature_tags
); }
2284 inline const Feature
& get_feature (unsigned int i
) const
2285 { return (this+featureList
)[i
]; }
2286 inline bool find_feature_index (hb_tag_t tag
, unsigned int *index
) const
2287 { return (this+featureList
).find_index (tag
, index
); }
2289 inline unsigned int get_lookup_count (void) const
2290 { return (this+lookupList
).len
; }
2291 inline const Lookup
& get_lookup (unsigned int i
) const
2292 { return (this+lookupList
)[i
]; }
2294 inline bool sanitize (hb_sanitize_context_t
*c
) {
2295 TRACE_SANITIZE (this);
2296 return TRACE_RETURN (version
.sanitize (c
) && likely (version
.major
== 1) &&
2297 scriptList
.sanitize (c
, this) &&
2298 featureList
.sanitize (c
, this) &&
2299 lookupList
.sanitize (c
, this));
2303 FixedVersion version
; /* Version of the GSUB/GPOS table--initially set
2305 OffsetTo
<ScriptList
>
2306 scriptList
; /* ScriptList table */
2307 OffsetTo
<FeatureList
>
2308 featureList
; /* FeatureList table */
2309 OffsetTo
<LookupList
>
2310 lookupList
; /* LookupList table */
2312 DEFINE_SIZE_STATIC (10);
2316 } /* namespace OT */
2319 #endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */