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) \
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, \
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 hb_set_t
*old_before
= before
;
172 hb_set_t
*old_input
= input
;
173 hb_set_t
*old_after
= after
;
174 before
= input
= after
= hb_set_get_empty ();
176 nesting_level_left
--;
177 recurse_func (this, lookup_index
);
178 nesting_level_left
++;
192 recurse_func_t recurse_func
;
193 unsigned int nesting_level_left
;
194 unsigned int debug_depth
;
196 hb_collect_glyphs_context_t (hb_face_t
*face_
,
197 hb_set_t
*glyphs_before
, /* OUT. May be NULL */
198 hb_set_t
*glyphs_input
, /* OUT. May be NULL */
199 hb_set_t
*glyphs_after
, /* OUT. May be NULL */
200 hb_set_t
*glyphs_output
, /* OUT. May be NULL */
201 unsigned int nesting_level_left_
= MAX_NESTING_LEVEL
) :
203 before (glyphs_before
? glyphs_before
: hb_set_get_empty ()),
204 input (glyphs_input
? glyphs_input
: hb_set_get_empty ()),
205 after (glyphs_after
? glyphs_after
: hb_set_get_empty ()),
206 output (glyphs_output
? glyphs_output
: hb_set_get_empty ()),
208 nesting_level_left (nesting_level_left_
),
211 void set_recurse_func (recurse_func_t func
) { recurse_func
= func
; }
216 struct hb_get_coverage_context_t
218 inline const char *get_name (void) { return "GET_COVERAGE"; }
219 static const unsigned int max_debug_depth
= 0;
220 typedef const Coverage
&return_t
;
221 template <typename T
>
222 inline return_t
dispatch (const T
&obj
) { return obj
.get_coverage (); }
223 static return_t
default_return_value (void) { return Null(Coverage
); }
225 hb_get_coverage_context_t (void) :
228 unsigned int debug_depth
;
233 #ifndef HB_DEBUG_APPLY
234 #define HB_DEBUG_APPLY (HB_DEBUG+0)
237 #define TRACE_APPLY(this) \
238 hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace \
239 (&c->debug_depth, c->get_name (), this, HB_FUNC, \
240 "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
242 struct hb_apply_context_t
244 inline const char *get_name (void) { return "APPLY"; }
245 static const unsigned int max_debug_depth
= HB_DEBUG_APPLY
;
246 typedef bool return_t
;
247 typedef return_t (*recurse_func_t
) (hb_apply_context_t
*c
, unsigned int lookup_index
);
248 template <typename T
>
249 inline return_t
dispatch (const T
&obj
) { return obj
.apply (this); }
250 static return_t
default_return_value (void) { return false; }
251 bool stop_sublookup_iteration (return_t r
) const { return r
; }
252 return_t
recurse (unsigned int lookup_index
)
254 if (unlikely (nesting_level_left
== 0 || !recurse_func
))
255 return default_return_value ();
257 nesting_level_left
--;
258 bool ret
= recurse_func (this, lookup_index
);
259 nesting_level_left
++;
263 unsigned int table_index
; /* GSUB/GPOS */
267 hb_direction_t direction
;
268 hb_mask_t lookup_mask
;
270 recurse_func_t recurse_func
;
271 unsigned int nesting_level_left
;
272 unsigned int lookup_props
;
274 bool has_glyph_classes
;
275 unsigned int debug_depth
;
278 hb_apply_context_t (unsigned int table_index_
,
280 hb_buffer_t
*buffer_
) :
281 table_index (table_index_
),
282 font (font_
), face (font
->face
), buffer (buffer_
),
283 direction (buffer_
->props
.direction
),
287 nesting_level_left (MAX_NESTING_LEVEL
),
289 gdef (*hb_ot_layout_from_face (face
)->gdef
),
290 has_glyph_classes (gdef
.has_glyph_classes ()),
293 inline void set_lookup_mask (hb_mask_t mask
) { lookup_mask
= mask
; }
294 inline void set_auto_zwj (bool auto_zwj_
) { auto_zwj
= auto_zwj_
; }
295 inline void set_recurse_func (recurse_func_t func
) { recurse_func
= func
; }
296 inline void set_lookup_props (unsigned int lookup_props_
) { lookup_props
= lookup_props_
; }
297 inline void set_lookup (const Lookup
&l
) { lookup_props
= l
.get_props (); }
301 inline matcher_t (void) :
306 #define arg1(arg) (arg) /* Remove the macro to see why it's needed! */
310 match_data (NULL
) {};
312 typedef bool (*match_func_t
) (hb_codepoint_t glyph_id
, const USHORT
&value
, const void *data
);
314 inline void set_ignore_zwnj (bool ignore_zwnj_
) { ignore_zwnj
= ignore_zwnj_
; }
315 inline void set_ignore_zwj (bool ignore_zwj_
) { ignore_zwj
= ignore_zwj_
; }
316 inline void set_lookup_props (unsigned int lookup_props_
) { lookup_props
= lookup_props_
; }
317 inline void set_mask (hb_mask_t mask_
) { mask
= mask_
; }
318 inline void set_syllable (uint8_t syllable_
) { syllable
= syllable_
; }
319 inline void set_match_func (match_func_t match_func_
,
320 const void *match_data_
)
321 { match_func
= match_func_
; match_data
= match_data_
; }
329 inline may_match_t
may_match (const hb_glyph_info_t
&info
,
330 const USHORT
*glyph_data
) const
332 if (!(info
.mask
& mask
) ||
333 (syllable
&& syllable
!= info
.syllable ()))
337 return match_func (info
.codepoint
, *glyph_data
, match_data
) ? MATCH_YES
: MATCH_NO
;
349 may_skip (const hb_apply_context_t
*c
,
350 const hb_glyph_info_t
&info
) const
352 unsigned int property
;
354 property
= _hb_glyph_info_get_glyph_props (&info
);
356 if (!c
->match_properties (info
.codepoint
, property
, lookup_props
))
359 if (unlikely (_hb_glyph_info_is_default_ignorable (&info
) &&
360 (ignore_zwnj
|| !_hb_glyph_info_is_zwnj (&info
)) &&
361 (ignore_zwj
|| !_hb_glyph_info_is_zwj (&info
)) &&
362 !_hb_glyph_info_ligated (&info
)))
369 unsigned int lookup_props
;
374 match_func_t match_func
;
375 const void *match_data
;
378 struct skipping_forward_iterator_t
380 inline skipping_forward_iterator_t (hb_apply_context_t
*c_
,
381 unsigned int start_index_
,
382 unsigned int num_items_
,
383 bool context_match
= false) :
386 match_glyph_data (NULL
),
387 num_items (num_items_
),
390 matcher
.set_lookup_props (c
->lookup_props
);
391 /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
392 matcher
.set_ignore_zwnj (context_match
|| c
->table_index
== 1);
393 /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */
394 matcher
.set_ignore_zwj (context_match
|| c
->table_index
== 1 || c
->auto_zwj
);
396 matcher
.set_mask (c
->lookup_mask
);
397 matcher
.set_syllable (start_index_
== c
->buffer
->idx
? c
->buffer
->cur().syllable () : 0);
399 inline void set_lookup_props (unsigned int lookup_props
) { matcher
.set_lookup_props (lookup_props
); }
400 inline void set_syllable (unsigned int syllable
) { matcher
.set_syllable (syllable
); }
401 inline void set_match_func (matcher_t::match_func_t match_func
,
402 const void *match_data
,
403 const USHORT glyph_data
[])
405 matcher
.set_match_func (match_func
, match_data
);
406 match_glyph_data
= glyph_data
;
409 inline bool has_no_chance (void) const { return unlikely (num_items
&& idx
+ num_items
>= end
); }
410 inline void reject (void) { num_items
++; match_glyph_data
--; }
411 inline bool next (void)
413 assert (num_items
> 0);
414 while (!has_no_chance ())
417 const hb_glyph_info_t
&info
= c
->buffer
->info
[idx
];
419 matcher_t::may_skip_t skip
= matcher
.may_skip (c
, info
);
420 if (unlikely (skip
== matcher_t::SKIP_YES
))
423 matcher_t::may_match_t match
= matcher
.may_match (info
, match_glyph_data
);
424 if (match
== matcher_t::MATCH_YES
||
425 (match
== matcher_t::MATCH_MAYBE
&&
426 skip
== matcher_t::SKIP_NO
))
433 if (skip
== matcher_t::SKIP_NO
)
441 hb_apply_context_t
*c
;
443 const USHORT
*match_glyph_data
;
445 unsigned int num_items
;
449 struct skipping_backward_iterator_t
451 inline skipping_backward_iterator_t (hb_apply_context_t
*c_
,
452 unsigned int start_index_
,
453 unsigned int num_items_
,
454 bool context_match
= false) :
457 match_glyph_data (NULL
),
458 num_items (num_items_
)
460 matcher
.set_lookup_props (c
->lookup_props
);
461 /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
462 matcher
.set_ignore_zwnj (context_match
|| c
->table_index
== 1);
463 /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */
464 matcher
.set_ignore_zwj (context_match
|| c
->table_index
== 1 || c
->auto_zwj
);
466 matcher
.set_mask (c
->lookup_mask
);
467 matcher
.set_syllable (start_index_
== c
->buffer
->idx
? c
->buffer
->cur().syllable () : 0);
469 inline void set_lookup_props (unsigned int lookup_props
) { matcher
.set_lookup_props (lookup_props
); }
470 inline void set_syllable (unsigned int syllable
) { matcher
.set_syllable (syllable
); }
471 inline void set_match_func (matcher_t::match_func_t match_func
,
472 const void *match_data
,
473 const USHORT glyph_data
[])
475 matcher
.set_match_func (match_func
, match_data
);
476 match_glyph_data
= glyph_data
;
479 inline bool has_no_chance (void) const { return unlikely (idx
< num_items
); }
480 inline void reject (void) { num_items
++; }
481 inline bool prev (void)
483 assert (num_items
> 0);
484 while (!has_no_chance ())
487 const hb_glyph_info_t
&info
= c
->buffer
->out_info
[idx
];
489 matcher_t::may_skip_t skip
= matcher
.may_skip (c
, info
);
491 if (unlikely (skip
== matcher_t::SKIP_YES
))
494 matcher_t::may_match_t match
= matcher
.may_match (info
, match_glyph_data
);
495 if (match
== matcher_t::MATCH_YES
||
496 (match
== matcher_t::MATCH_MAYBE
&&
497 skip
== matcher_t::SKIP_NO
))
504 if (skip
== matcher_t::SKIP_NO
)
512 hb_apply_context_t
*c
;
514 const USHORT
*match_glyph_data
;
516 unsigned int num_items
;
520 match_properties_mark (hb_codepoint_t glyph
,
521 unsigned int glyph_props
,
522 unsigned int lookup_props
) const
524 /* If using mark filtering sets, the high short of
525 * lookup_props has the set index.
527 if (lookup_props
& LookupFlag::UseMarkFilteringSet
)
528 return gdef
.mark_set_covers (lookup_props
>> 16, glyph
);
530 /* The second byte of lookup_props has the meaning
531 * "ignore marks of attachment type different than
532 * the attachment type specified."
534 if (lookup_props
& LookupFlag::MarkAttachmentType
)
535 return (lookup_props
& LookupFlag::MarkAttachmentType
) == (glyph_props
& LookupFlag::MarkAttachmentType
);
541 match_properties (hb_codepoint_t glyph
,
542 unsigned int glyph_props
,
543 unsigned int lookup_props
) const
545 /* Not covered, if, for example, glyph class is ligature and
546 * lookup_props includes LookupFlags::IgnoreLigatures
548 if (glyph_props
& lookup_props
& LookupFlag::IgnoreFlags
)
551 if (unlikely (glyph_props
& HB_OT_LAYOUT_GLYPH_PROPS_MARK
))
552 return match_properties_mark (glyph
, glyph_props
, lookup_props
);
558 check_glyph_property (hb_glyph_info_t
*info
,
559 unsigned int lookup_props
) const
561 unsigned int property
;
563 property
= _hb_glyph_info_get_glyph_props (info
);
565 return match_properties (info
->codepoint
, property
, lookup_props
);
568 inline void _set_glyph_props (hb_codepoint_t glyph_index
,
569 unsigned int class_guess
= 0,
570 bool ligature
= false) const
572 unsigned int add_in
= _hb_glyph_info_get_glyph_props (&buffer
->cur()) &
573 HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE
;
574 add_in
|= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED
;
576 add_in
|= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED
;
577 if (likely (has_glyph_classes
))
578 _hb_glyph_info_set_glyph_props (&buffer
->cur(), add_in
| gdef
.get_glyph_props (glyph_index
));
579 else if (class_guess
)
580 _hb_glyph_info_set_glyph_props (&buffer
->cur(), add_in
| class_guess
);
583 inline void replace_glyph (hb_codepoint_t glyph_index
) const
585 _set_glyph_props (glyph_index
);
586 buffer
->replace_glyph (glyph_index
);
588 inline void replace_glyph_inplace (hb_codepoint_t glyph_index
) const
590 _set_glyph_props (glyph_index
);
591 buffer
->cur().codepoint
= glyph_index
;
593 inline void replace_glyph_with_ligature (hb_codepoint_t glyph_index
,
594 unsigned int class_guess
) const
596 _set_glyph_props (glyph_index
, class_guess
, true);
597 buffer
->replace_glyph (glyph_index
);
599 inline void output_glyph (hb_codepoint_t glyph_index
,
600 unsigned int class_guess
) const
602 _set_glyph_props (glyph_index
, class_guess
);
603 buffer
->output_glyph (glyph_index
);
609 typedef bool (*intersects_func_t
) (hb_set_t
*glyphs
, const USHORT
&value
, const void *data
);
610 typedef void (*collect_glyphs_func_t
) (hb_set_t
*glyphs
, const USHORT
&value
, const void *data
);
611 typedef bool (*match_func_t
) (hb_codepoint_t glyph_id
, const USHORT
&value
, const void *data
);
613 struct ContextClosureFuncs
615 intersects_func_t intersects
;
617 struct ContextCollectGlyphsFuncs
619 collect_glyphs_func_t collect
;
621 struct ContextApplyFuncs
627 static inline bool intersects_glyph (hb_set_t
*glyphs
, const USHORT
&value
, const void *data HB_UNUSED
)
629 return glyphs
->has (value
);
631 static inline bool intersects_class (hb_set_t
*glyphs
, const USHORT
&value
, const void *data
)
633 const ClassDef
&class_def
= *reinterpret_cast<const ClassDef
*>(data
);
634 return class_def
.intersects_class (glyphs
, value
);
636 static inline bool intersects_coverage (hb_set_t
*glyphs
, const USHORT
&value
, const void *data
)
638 const OffsetTo
<Coverage
> &coverage
= (const OffsetTo
<Coverage
>&)value
;
639 return (data
+coverage
).intersects (glyphs
);
642 static inline bool intersects_array (hb_closure_context_t
*c
,
644 const USHORT values
[],
645 intersects_func_t intersects_func
,
646 const void *intersects_data
)
648 for (unsigned int i
= 0; i
< count
; i
++)
649 if (likely (!intersects_func (c
->glyphs
, values
[i
], intersects_data
)))
655 static inline void collect_glyph (hb_set_t
*glyphs
, const USHORT
&value
, const void *data HB_UNUSED
)
659 static inline void collect_class (hb_set_t
*glyphs
, const USHORT
&value
, const void *data
)
661 const ClassDef
&class_def
= *reinterpret_cast<const ClassDef
*>(data
);
662 class_def
.add_class (glyphs
, value
);
664 static inline void collect_coverage (hb_set_t
*glyphs
, const USHORT
&value
, const void *data
)
666 const OffsetTo
<Coverage
> &coverage
= (const OffsetTo
<Coverage
>&)value
;
667 (data
+coverage
).add_coverage (glyphs
);
669 static inline void collect_array (hb_collect_glyphs_context_t
*c HB_UNUSED
,
672 const USHORT values
[],
673 collect_glyphs_func_t collect_func
,
674 const void *collect_data
)
676 for (unsigned int i
= 0; i
< count
; i
++)
677 collect_func (glyphs
, values
[i
], collect_data
);
681 static inline bool match_glyph (hb_codepoint_t glyph_id
, const USHORT
&value
, const void *data HB_UNUSED
)
683 return glyph_id
== value
;
685 static inline bool match_class (hb_codepoint_t glyph_id
, const USHORT
&value
, const void *data
)
687 const ClassDef
&class_def
= *reinterpret_cast<const ClassDef
*>(data
);
688 return class_def
.get_class (glyph_id
) == value
;
690 static inline bool match_coverage (hb_codepoint_t glyph_id
, const USHORT
&value
, const void *data
)
692 const OffsetTo
<Coverage
> &coverage
= (const OffsetTo
<Coverage
>&)value
;
693 return (data
+coverage
).get_coverage (glyph_id
) != NOT_COVERED
;
696 static inline bool would_match_input (hb_would_apply_context_t
*c
,
697 unsigned int count
, /* Including the first glyph (not matched) */
698 const USHORT input
[], /* Array of input values--start with second glyph */
699 match_func_t match_func
,
700 const void *match_data
)
705 for (unsigned int i
= 1; i
< count
; i
++)
706 if (likely (!match_func (c
->glyphs
[i
], input
[i
- 1], match_data
)))
711 static inline bool match_input (hb_apply_context_t
*c
,
712 unsigned int count
, /* Including the first glyph (not matched) */
713 const USHORT input
[], /* Array of input values--start with second glyph */
714 match_func_t match_func
,
715 const void *match_data
,
716 unsigned int *end_offset
,
717 unsigned int match_positions
[MAX_CONTEXT_LENGTH
],
718 bool *p_is_mark_ligature
= NULL
,
719 unsigned int *p_total_component_count
= NULL
)
723 if (unlikely (count
> MAX_CONTEXT_LENGTH
)) TRACE_RETURN (false);
725 hb_buffer_t
*buffer
= c
->buffer
;
727 hb_apply_context_t::skipping_forward_iterator_t
skippy_iter (c
, buffer
->idx
, count
- 1);
728 skippy_iter
.set_match_func (match_func
, match_data
, input
);
729 if (skippy_iter
.has_no_chance ()) return TRACE_RETURN (false);
732 * This is perhaps the trickiest part of OpenType... Remarks:
734 * - If all components of the ligature were marks, we call this a mark ligature.
736 * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize
737 * it as a ligature glyph.
739 * - Ligatures cannot be formed across glyphs attached to different components
740 * of previous ligatures. Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
741 * LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
742 * However, it would be wrong to ligate that SHADDA,FATHA sequence.o
743 * There is an exception to this: If a ligature tries ligating with marks that
744 * belong to it itself, go ahead, assuming that the font designer knows what
745 * they are doing (otherwise it can break Indic stuff when a matra wants to
746 * ligate with a conjunct...)
749 bool is_mark_ligature
= _hb_glyph_info_is_mark (&buffer
->cur());
751 unsigned int total_component_count
= 0;
752 total_component_count
+= _hb_glyph_info_get_lig_num_comps (&buffer
->cur());
754 unsigned int first_lig_id
= _hb_glyph_info_get_lig_id (&buffer
->cur());
755 unsigned int first_lig_comp
= _hb_glyph_info_get_lig_comp (&buffer
->cur());
757 match_positions
[0] = buffer
->idx
;
758 for (unsigned int i
= 1; i
< count
; i
++)
760 if (!skippy_iter
.next ()) return TRACE_RETURN (false);
762 match_positions
[i
] = skippy_iter
.idx
;
764 unsigned int this_lig_id
= _hb_glyph_info_get_lig_id (&buffer
->info
[skippy_iter
.idx
]);
765 unsigned int this_lig_comp
= _hb_glyph_info_get_lig_comp (&buffer
->info
[skippy_iter
.idx
]);
767 if (first_lig_id
&& first_lig_comp
) {
768 /* If first component was attached to a previous ligature component,
769 * all subsequent components should be attached to the same ligature
770 * component, otherwise we shouldn't ligate them. */
771 if (first_lig_id
!= this_lig_id
|| first_lig_comp
!= this_lig_comp
)
772 return TRACE_RETURN (false);
774 /* If first component was NOT attached to a previous ligature component,
775 * all subsequent components should also NOT be attached to any ligature
776 * component, unless they are attached to the first component itself! */
777 if (this_lig_id
&& this_lig_comp
&& (this_lig_id
!= first_lig_id
))
778 return TRACE_RETURN (false);
781 is_mark_ligature
= is_mark_ligature
&& _hb_glyph_info_is_mark (&buffer
->info
[skippy_iter
.idx
]);
782 total_component_count
+= _hb_glyph_info_get_lig_num_comps (&buffer
->info
[skippy_iter
.idx
]);
785 *end_offset
= skippy_iter
.idx
- buffer
->idx
+ 1;
787 if (p_is_mark_ligature
)
788 *p_is_mark_ligature
= is_mark_ligature
;
790 if (p_total_component_count
)
791 *p_total_component_count
= total_component_count
;
793 return TRACE_RETURN (true);
795 static inline void ligate_input (hb_apply_context_t
*c
,
796 unsigned int count
, /* Including the first glyph */
797 unsigned int match_positions
[MAX_CONTEXT_LENGTH
], /* Including the first glyph */
798 unsigned int match_length
,
799 hb_codepoint_t lig_glyph
,
800 bool is_mark_ligature
,
801 unsigned int total_component_count
)
805 hb_buffer_t
*buffer
= c
->buffer
;
807 buffer
->merge_clusters (buffer
->idx
, buffer
->idx
+ match_length
);
810 * - If it *is* a mark ligature, we don't allocate a new ligature id, and leave
811 * the ligature to keep its old ligature id. This will allow it to attach to
812 * a base ligature in GPOS. Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
813 * and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA wit a
814 * ligature id and component value of 2. Then if SHADDA,FATHA form a ligature
815 * later, we don't want them to lose their ligature id/component, otherwise
816 * GPOS will fail to correctly position the mark ligature on top of the
817 * LAM,LAM,HEH ligature. See:
818 * https://bugzilla.gnome.org/show_bug.cgi?id=676343
820 * - If a ligature is formed of components that some of which are also ligatures
821 * themselves, and those ligature components had marks attached to *their*
822 * components, we have to attach the marks to the new ligature component
823 * positions! Now *that*'s tricky! And these marks may be following the
824 * last component of the whole sequence, so we should loop forward looking
825 * for them and update them.
827 * Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a
828 * 'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature
829 * id and component == 1. Now, during 'liga', the LAM and the LAM-HEH ligature
830 * form a LAM-LAM-HEH ligature. We need to reassign the SHADDA and FATHA to
831 * the new ligature with a component value of 2.
833 * This in fact happened to a font... See:
834 * https://bugzilla.gnome.org/show_bug.cgi?id=437633
837 unsigned int klass
= is_mark_ligature
? 0 : HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE
;
838 unsigned int lig_id
= is_mark_ligature
? 0 : _hb_allocate_lig_id (buffer
);
839 unsigned int last_lig_id
= _hb_glyph_info_get_lig_id (&buffer
->cur());
840 unsigned int last_num_components
= _hb_glyph_info_get_lig_num_comps (&buffer
->cur());
841 unsigned int components_so_far
= last_num_components
;
843 if (!is_mark_ligature
)
845 _hb_glyph_info_set_lig_props_for_ligature (&buffer
->cur(), lig_id
, total_component_count
);
846 if (_hb_glyph_info_get_general_category (&buffer
->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK
)
848 _hb_glyph_info_set_general_category (&buffer
->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER
);
849 _hb_glyph_info_set_modified_combining_class (&buffer
->cur(), 0);
852 c
->replace_glyph_with_ligature (lig_glyph
, klass
);
854 for (unsigned int i
= 1; i
< count
; i
++)
856 while (buffer
->idx
< match_positions
[i
])
858 if (!is_mark_ligature
) {
859 unsigned int new_lig_comp
= components_so_far
- last_num_components
+
860 MIN (MAX (_hb_glyph_info_get_lig_comp (&buffer
->cur()), 1u), last_num_components
);
861 _hb_glyph_info_set_lig_props_for_mark (&buffer
->cur(), lig_id
, new_lig_comp
);
863 buffer
->next_glyph ();
866 last_lig_id
= _hb_glyph_info_get_lig_id (&buffer
->cur());
867 last_num_components
= _hb_glyph_info_get_lig_num_comps (&buffer
->cur());
868 components_so_far
+= last_num_components
;
870 /* Skip the base glyph */
874 if (!is_mark_ligature
&& last_lig_id
) {
875 /* Re-adjust components for any marks following. */
876 for (unsigned int i
= buffer
->idx
; i
< buffer
->len
; i
++) {
877 if (last_lig_id
== _hb_glyph_info_get_lig_id (&buffer
->info
[i
])) {
878 unsigned int new_lig_comp
= components_so_far
- last_num_components
+
879 MIN (MAX (_hb_glyph_info_get_lig_comp (&buffer
->info
[i
]), 1u), last_num_components
);
880 _hb_glyph_info_set_lig_props_for_mark (&buffer
->info
[i
], lig_id
, new_lig_comp
);
887 static inline bool match_backtrack (hb_apply_context_t
*c
,
889 const USHORT backtrack
[],
890 match_func_t match_func
,
891 const void *match_data
)
895 hb_apply_context_t::skipping_backward_iterator_t
skippy_iter (c
, c
->buffer
->backtrack_len (), count
, true);
896 skippy_iter
.set_match_func (match_func
, match_data
, backtrack
);
897 if (skippy_iter
.has_no_chance ()) return TRACE_RETURN (false);
899 for (unsigned int i
= 0; i
< count
; i
++)
900 if (!skippy_iter
.prev ())
901 return TRACE_RETURN (false);
903 return TRACE_RETURN (true);
906 static inline bool match_lookahead (hb_apply_context_t
*c
,
908 const USHORT lookahead
[],
909 match_func_t match_func
,
910 const void *match_data
,
915 hb_apply_context_t::skipping_forward_iterator_t
skippy_iter (c
, c
->buffer
->idx
+ offset
- 1, count
, true);
916 skippy_iter
.set_match_func (match_func
, match_data
, lookahead
);
917 if (skippy_iter
.has_no_chance ()) return TRACE_RETURN (false);
919 for (unsigned int i
= 0; i
< count
; i
++)
920 if (!skippy_iter
.next ())
921 return TRACE_RETURN (false);
923 return TRACE_RETURN (true);
930 inline bool sanitize (hb_sanitize_context_t
*c
) {
931 TRACE_SANITIZE (this);
932 return TRACE_RETURN (c
->check_struct (this));
935 USHORT sequenceIndex
; /* Index into current glyph
936 * sequence--first glyph = 0 */
937 USHORT lookupListIndex
; /* Lookup to apply to that
938 * position--zero--based */
940 DEFINE_SIZE_STATIC (4);
944 template <typename context_t
>
945 static inline void recurse_lookups (context_t
*c
,
946 unsigned int lookupCount
,
947 const LookupRecord lookupRecord
[] /* Array of LookupRecords--in design order */)
949 for (unsigned int i
= 0; i
< lookupCount
; i
++)
950 c
->recurse (lookupRecord
[i
].lookupListIndex
);
953 static inline bool apply_lookup (hb_apply_context_t
*c
,
954 unsigned int count
, /* Including the first glyph */
955 unsigned int match_positions
[MAX_CONTEXT_LENGTH
], /* Including the first glyph */
956 unsigned int lookupCount
,
957 const LookupRecord lookupRecord
[], /* Array of LookupRecords--in design order */
958 unsigned int match_length
)
962 hb_buffer_t
*buffer
= c
->buffer
;
965 /* All positions are distance from beginning of *output* buffer.
968 unsigned int bl
= buffer
->backtrack_len ();
969 end
= bl
+ match_length
;
971 int delta
= bl
- buffer
->idx
;
972 /* Convert positions to new indexing. */
973 for (unsigned int j
= 0; j
< count
; j
++)
974 match_positions
[j
] += delta
;
977 for (unsigned int i
= 0; i
< lookupCount
; i
++)
979 unsigned int idx
= lookupRecord
[i
].sequenceIndex
;
983 buffer
->move_to (match_positions
[idx
]);
985 unsigned int orig_len
= buffer
->backtrack_len () + buffer
->lookahead_len ();
986 if (!c
->recurse (lookupRecord
[i
].lookupListIndex
))
989 unsigned int new_len
= buffer
->backtrack_len () + buffer
->lookahead_len ();
990 int delta
= new_len
- orig_len
;
995 /* Recursed lookup changed buffer len. Adjust. */
997 /* end can't go back past the current match position. */
998 end
= MAX ((int) match_positions
[idx
] + 1, int (end
) + delta
);
1000 unsigned int next
= idx
+ 1; /* next now is the position after the recursed lookup. */
1004 if (unlikely (delta
+ count
> MAX_CONTEXT_LENGTH
))
1009 /* NOTE: delta is negative. */
1010 delta
= MAX (delta
, (int) next
- (int) count
);
1015 memmove (match_positions
+ next
+ delta
, match_positions
+ next
,
1016 (count
- next
) * sizeof (match_positions
[0]));
1020 /* Fill in new entries. */
1021 for (unsigned int j
= idx
+ 1; j
< next
; j
++)
1022 match_positions
[j
] = match_positions
[j
- 1] + 1;
1024 /* And fixup the rest. */
1025 for (; next
< count
; next
++)
1026 match_positions
[next
] += delta
;
1029 buffer
->move_to (end
);
1031 return TRACE_RETURN (true);
1036 /* Contextual lookups */
1038 struct ContextClosureLookupContext
1040 ContextClosureFuncs funcs
;
1041 const void *intersects_data
;
1044 struct ContextCollectGlyphsLookupContext
1046 ContextCollectGlyphsFuncs funcs
;
1047 const void *collect_data
;
1050 struct ContextApplyLookupContext
1052 ContextApplyFuncs funcs
;
1053 const void *match_data
;
1056 static inline void context_closure_lookup (hb_closure_context_t
*c
,
1057 unsigned int inputCount
, /* Including the first glyph (not matched) */
1058 const USHORT input
[], /* Array of input values--start with second glyph */
1059 unsigned int lookupCount
,
1060 const LookupRecord lookupRecord
[],
1061 ContextClosureLookupContext
&lookup_context
)
1063 if (intersects_array (c
,
1064 inputCount
? inputCount
- 1 : 0, input
,
1065 lookup_context
.funcs
.intersects
, lookup_context
.intersects_data
))
1067 lookupCount
, lookupRecord
);
1070 static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t
*c
,
1071 unsigned int inputCount
, /* Including the first glyph (not matched) */
1072 const USHORT input
[], /* Array of input values--start with second glyph */
1073 unsigned int lookupCount
,
1074 const LookupRecord lookupRecord
[],
1075 ContextCollectGlyphsLookupContext
&lookup_context
)
1077 collect_array (c
, c
->input
,
1078 inputCount
? inputCount
- 1 : 0, input
,
1079 lookup_context
.funcs
.collect
, lookup_context
.collect_data
);
1081 lookupCount
, lookupRecord
);
1084 static inline bool context_would_apply_lookup (hb_would_apply_context_t
*c
,
1085 unsigned int inputCount
, /* Including the first glyph (not matched) */
1086 const USHORT input
[], /* Array of input values--start with second glyph */
1087 unsigned int lookupCount HB_UNUSED
,
1088 const LookupRecord lookupRecord
[] HB_UNUSED
,
1089 ContextApplyLookupContext
&lookup_context
)
1091 return would_match_input (c
,
1093 lookup_context
.funcs
.match
, lookup_context
.match_data
);
1095 static inline bool context_apply_lookup (hb_apply_context_t
*c
,
1096 unsigned int inputCount
, /* Including the first glyph (not matched) */
1097 const USHORT input
[], /* Array of input values--start with second glyph */
1098 unsigned int lookupCount
,
1099 const LookupRecord lookupRecord
[],
1100 ContextApplyLookupContext
&lookup_context
)
1102 unsigned int match_length
= 0;
1103 unsigned int match_positions
[MAX_CONTEXT_LENGTH
];
1104 return match_input (c
,
1106 lookup_context
.funcs
.match
, lookup_context
.match_data
,
1107 &match_length
, match_positions
)
1109 inputCount
, match_positions
,
1110 lookupCount
, lookupRecord
,
1116 inline void closure (hb_closure_context_t
*c
, ContextClosureLookupContext
&lookup_context
) const
1118 TRACE_CLOSURE (this);
1119 const LookupRecord
*lookupRecord
= &StructAtOffset
<LookupRecord
> (input
, input
[0].static_size
* (inputCount
? inputCount
- 1 : 0));
1120 context_closure_lookup (c
,
1122 lookupCount
, lookupRecord
,
1126 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
, ContextCollectGlyphsLookupContext
&lookup_context
) const
1128 TRACE_COLLECT_GLYPHS (this);
1129 const LookupRecord
*lookupRecord
= &StructAtOffset
<LookupRecord
> (input
, input
[0].static_size
* (inputCount
? inputCount
- 1 : 0));
1130 context_collect_glyphs_lookup (c
,
1132 lookupCount
, lookupRecord
,
1136 inline bool would_apply (hb_would_apply_context_t
*c
, ContextApplyLookupContext
&lookup_context
) const
1138 TRACE_WOULD_APPLY (this);
1139 const LookupRecord
*lookupRecord
= &StructAtOffset
<LookupRecord
> (input
, input
[0].static_size
* (inputCount
? inputCount
- 1 : 0));
1140 return TRACE_RETURN (context_would_apply_lookup (c
, inputCount
, input
, lookupCount
, lookupRecord
, lookup_context
));
1143 inline bool apply (hb_apply_context_t
*c
, ContextApplyLookupContext
&lookup_context
) const
1146 const LookupRecord
*lookupRecord
= &StructAtOffset
<LookupRecord
> (input
, input
[0].static_size
* (inputCount
? inputCount
- 1 : 0));
1147 return TRACE_RETURN (context_apply_lookup (c
, inputCount
, input
, lookupCount
, lookupRecord
, lookup_context
));
1151 inline bool sanitize (hb_sanitize_context_t
*c
) {
1152 TRACE_SANITIZE (this);
1153 return inputCount
.sanitize (c
)
1154 && lookupCount
.sanitize (c
)
1155 && c
->check_range (input
,
1156 input
[0].static_size
* inputCount
1157 + lookupRecordX
[0].static_size
* lookupCount
);
1161 USHORT inputCount
; /* Total number of glyphs in input
1162 * glyph sequence--includes the first
1164 USHORT lookupCount
; /* Number of LookupRecords */
1165 USHORT input
[VAR
]; /* Array of match inputs--start with
1167 LookupRecord lookupRecordX
[VAR
]; /* Array of LookupRecords--in
1170 DEFINE_SIZE_ARRAY2 (4, input
, lookupRecordX
);
1175 inline void closure (hb_closure_context_t
*c
, ContextClosureLookupContext
&lookup_context
) const
1177 TRACE_CLOSURE (this);
1178 unsigned int num_rules
= rule
.len
;
1179 for (unsigned int i
= 0; i
< num_rules
; i
++)
1180 (this+rule
[i
]).closure (c
, lookup_context
);
1183 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
, ContextCollectGlyphsLookupContext
&lookup_context
) const
1185 TRACE_COLLECT_GLYPHS (this);
1186 unsigned int num_rules
= rule
.len
;
1187 for (unsigned int i
= 0; i
< num_rules
; i
++)
1188 (this+rule
[i
]).collect_glyphs (c
, lookup_context
);
1191 inline bool would_apply (hb_would_apply_context_t
*c
, ContextApplyLookupContext
&lookup_context
) const
1193 TRACE_WOULD_APPLY (this);
1194 unsigned int num_rules
= rule
.len
;
1195 for (unsigned int i
= 0; i
< num_rules
; i
++)
1197 if ((this+rule
[i
]).would_apply (c
, lookup_context
))
1198 return TRACE_RETURN (true);
1200 return TRACE_RETURN (false);
1203 inline bool apply (hb_apply_context_t
*c
, ContextApplyLookupContext
&lookup_context
) const
1206 unsigned int num_rules
= rule
.len
;
1207 for (unsigned int i
= 0; i
< num_rules
; i
++)
1209 if ((this+rule
[i
]).apply (c
, lookup_context
))
1210 return TRACE_RETURN (true);
1212 return TRACE_RETURN (false);
1215 inline bool sanitize (hb_sanitize_context_t
*c
) {
1216 TRACE_SANITIZE (this);
1217 return TRACE_RETURN (rule
.sanitize (c
, this));
1222 rule
; /* Array of Rule tables
1223 * ordered by preference */
1225 DEFINE_SIZE_ARRAY (2, rule
);
1229 struct ContextFormat1
1231 inline void closure (hb_closure_context_t
*c
) const
1233 TRACE_CLOSURE (this);
1235 const Coverage
&cov
= (this+coverage
);
1237 struct ContextClosureLookupContext lookup_context
= {
1242 unsigned int count
= ruleSet
.len
;
1243 for (unsigned int i
= 0; i
< count
; i
++)
1244 if (cov
.intersects_coverage (c
->glyphs
, i
)) {
1245 const RuleSet
&rule_set
= this+ruleSet
[i
];
1246 rule_set
.closure (c
, lookup_context
);
1250 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
1252 TRACE_COLLECT_GLYPHS (this);
1253 (this+coverage
).add_coverage (c
->input
);
1255 struct ContextCollectGlyphsLookupContext lookup_context
= {
1260 unsigned int count
= ruleSet
.len
;
1261 for (unsigned int i
= 0; i
< count
; i
++)
1262 (this+ruleSet
[i
]).collect_glyphs (c
, lookup_context
);
1265 inline bool would_apply (hb_would_apply_context_t
*c
) const
1267 TRACE_WOULD_APPLY (this);
1269 const RuleSet
&rule_set
= this+ruleSet
[(this+coverage
).get_coverage (c
->glyphs
[0])];
1270 struct ContextApplyLookupContext lookup_context
= {
1274 return TRACE_RETURN (rule_set
.would_apply (c
, lookup_context
));
1277 inline const Coverage
&get_coverage (void) const
1279 return this+coverage
;
1282 inline bool apply (hb_apply_context_t
*c
) const
1285 unsigned int index
= (this+coverage
).get_coverage (c
->buffer
->cur().codepoint
);
1286 if (likely (index
== NOT_COVERED
))
1287 return TRACE_RETURN (false);
1289 const RuleSet
&rule_set
= this+ruleSet
[index
];
1290 struct ContextApplyLookupContext lookup_context
= {
1294 return TRACE_RETURN (rule_set
.apply (c
, lookup_context
));
1297 inline bool sanitize (hb_sanitize_context_t
*c
) {
1298 TRACE_SANITIZE (this);
1299 return TRACE_RETURN (coverage
.sanitize (c
, this) && ruleSet
.sanitize (c
, this));
1303 USHORT format
; /* Format identifier--format = 1 */
1305 coverage
; /* Offset to Coverage table--from
1306 * beginning of table */
1307 OffsetArrayOf
<RuleSet
>
1308 ruleSet
; /* Array of RuleSet tables
1309 * ordered by Coverage Index */
1311 DEFINE_SIZE_ARRAY (6, ruleSet
);
1315 struct ContextFormat2
1317 inline void closure (hb_closure_context_t
*c
) const
1319 TRACE_CLOSURE (this);
1320 if (!(this+coverage
).intersects (c
->glyphs
))
1323 const ClassDef
&class_def
= this+classDef
;
1325 struct ContextClosureLookupContext lookup_context
= {
1330 unsigned int count
= ruleSet
.len
;
1331 for (unsigned int i
= 0; i
< count
; i
++)
1332 if (class_def
.intersects_class (c
->glyphs
, i
)) {
1333 const RuleSet
&rule_set
= this+ruleSet
[i
];
1334 rule_set
.closure (c
, lookup_context
);
1338 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
1340 TRACE_COLLECT_GLYPHS (this);
1341 (this+coverage
).add_coverage (c
->input
);
1343 const ClassDef
&class_def
= this+classDef
;
1344 struct ContextCollectGlyphsLookupContext lookup_context
= {
1349 unsigned int count
= ruleSet
.len
;
1350 for (unsigned int i
= 0; i
< count
; i
++)
1351 (this+ruleSet
[i
]).collect_glyphs (c
, lookup_context
);
1354 inline bool would_apply (hb_would_apply_context_t
*c
) const
1356 TRACE_WOULD_APPLY (this);
1358 const ClassDef
&class_def
= this+classDef
;
1359 unsigned int index
= class_def
.get_class (c
->glyphs
[0]);
1360 const RuleSet
&rule_set
= this+ruleSet
[index
];
1361 struct ContextApplyLookupContext lookup_context
= {
1365 return TRACE_RETURN (rule_set
.would_apply (c
, lookup_context
));
1368 inline const Coverage
&get_coverage (void) const
1370 return this+coverage
;
1373 inline bool apply (hb_apply_context_t
*c
) const
1376 unsigned int index
= (this+coverage
).get_coverage (c
->buffer
->cur().codepoint
);
1377 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
1379 const ClassDef
&class_def
= this+classDef
;
1380 index
= class_def
.get_class (c
->buffer
->cur().codepoint
);
1381 const RuleSet
&rule_set
= this+ruleSet
[index
];
1382 struct ContextApplyLookupContext lookup_context
= {
1386 return TRACE_RETURN (rule_set
.apply (c
, lookup_context
));
1389 inline bool sanitize (hb_sanitize_context_t
*c
) {
1390 TRACE_SANITIZE (this);
1391 return TRACE_RETURN (coverage
.sanitize (c
, this) && classDef
.sanitize (c
, this) && ruleSet
.sanitize (c
, this));
1395 USHORT format
; /* Format identifier--format = 2 */
1397 coverage
; /* Offset to Coverage table--from
1398 * beginning of table */
1400 classDef
; /* Offset to glyph ClassDef table--from
1401 * beginning of table */
1402 OffsetArrayOf
<RuleSet
>
1403 ruleSet
; /* Array of RuleSet tables
1404 * ordered by class */
1406 DEFINE_SIZE_ARRAY (8, ruleSet
);
1410 struct ContextFormat3
1412 inline void closure (hb_closure_context_t
*c
) const
1414 TRACE_CLOSURE (this);
1415 if (!(this+coverage
[0]).intersects (c
->glyphs
))
1418 const LookupRecord
*lookupRecord
= &StructAtOffset
<LookupRecord
> (coverage
, coverage
[0].static_size
* glyphCount
);
1419 struct ContextClosureLookupContext lookup_context
= {
1420 {intersects_coverage
},
1423 context_closure_lookup (c
,
1424 glyphCount
, (const USHORT
*) (coverage
+ 1),
1425 lookupCount
, lookupRecord
,
1429 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
1431 TRACE_COLLECT_GLYPHS (this);
1432 (this+coverage
[0]).add_coverage (c
->input
);
1434 const LookupRecord
*lookupRecord
= &StructAtOffset
<LookupRecord
> (coverage
, coverage
[0].static_size
* glyphCount
);
1435 struct ContextCollectGlyphsLookupContext lookup_context
= {
1440 context_collect_glyphs_lookup (c
,
1441 glyphCount
, (const USHORT
*) (coverage
+ 1),
1442 lookupCount
, lookupRecord
,
1446 inline bool would_apply (hb_would_apply_context_t
*c
) const
1448 TRACE_WOULD_APPLY (this);
1450 const LookupRecord
*lookupRecord
= &StructAtOffset
<LookupRecord
> (coverage
, coverage
[0].static_size
* glyphCount
);
1451 struct ContextApplyLookupContext lookup_context
= {
1455 return TRACE_RETURN (context_would_apply_lookup (c
, glyphCount
, (const USHORT
*) (coverage
+ 1), lookupCount
, lookupRecord
, lookup_context
));
1458 inline const Coverage
&get_coverage (void) const
1460 return this+coverage
[0];
1463 inline bool apply (hb_apply_context_t
*c
) const
1466 unsigned int index
= (this+coverage
[0]).get_coverage (c
->buffer
->cur().codepoint
);
1467 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
1469 const LookupRecord
*lookupRecord
= &StructAtOffset
<LookupRecord
> (coverage
, coverage
[0].static_size
* glyphCount
);
1470 struct ContextApplyLookupContext lookup_context
= {
1474 return TRACE_RETURN (context_apply_lookup (c
, glyphCount
, (const USHORT
*) (coverage
+ 1), lookupCount
, lookupRecord
, lookup_context
));
1477 inline bool sanitize (hb_sanitize_context_t
*c
) {
1478 TRACE_SANITIZE (this);
1479 if (!c
->check_struct (this)) return TRACE_RETURN (false);
1480 unsigned int count
= glyphCount
;
1481 if (!c
->check_array (coverage
, coverage
[0].static_size
, count
)) return TRACE_RETURN (false);
1482 for (unsigned int i
= 0; i
< count
; i
++)
1483 if (!coverage
[i
].sanitize (c
, this)) return TRACE_RETURN (false);
1484 LookupRecord
*lookupRecord
= &StructAtOffset
<LookupRecord
> (coverage
, coverage
[0].static_size
* count
);
1485 return TRACE_RETURN (c
->check_array (lookupRecord
, lookupRecord
[0].static_size
, lookupCount
));
1489 USHORT format
; /* Format identifier--format = 3 */
1490 USHORT glyphCount
; /* Number of glyphs in the input glyph
1492 USHORT lookupCount
; /* Number of LookupRecords */
1494 coverage
[VAR
]; /* Array of offsets to Coverage
1495 * table in glyph sequence order */
1496 LookupRecord lookupRecordX
[VAR
]; /* Array of LookupRecords--in
1499 DEFINE_SIZE_ARRAY2 (6, coverage
, lookupRecordX
);
1504 template <typename context_t
>
1505 inline typename
context_t::return_t
dispatch (context_t
*c
) const
1507 TRACE_DISPATCH (this);
1509 case 1: return TRACE_RETURN (c
->dispatch (u
.format1
));
1510 case 2: return TRACE_RETURN (c
->dispatch (u
.format2
));
1511 case 3: return TRACE_RETURN (c
->dispatch (u
.format3
));
1512 default:return TRACE_RETURN (c
->default_return_value ());
1516 inline bool sanitize (hb_sanitize_context_t
*c
) {
1517 TRACE_SANITIZE (this);
1518 if (!u
.format
.sanitize (c
)) return TRACE_RETURN (false);
1520 case 1: return TRACE_RETURN (u
.format1
.sanitize (c
));
1521 case 2: return TRACE_RETURN (u
.format2
.sanitize (c
));
1522 case 3: return TRACE_RETURN (u
.format3
.sanitize (c
));
1523 default:return TRACE_RETURN (true);
1529 USHORT format
; /* Format identifier */
1530 ContextFormat1 format1
;
1531 ContextFormat2 format2
;
1532 ContextFormat3 format3
;
1537 /* Chaining Contextual lookups */
1539 struct ChainContextClosureLookupContext
1541 ContextClosureFuncs funcs
;
1542 const void *intersects_data
[3];
1545 struct ChainContextCollectGlyphsLookupContext
1547 ContextCollectGlyphsFuncs funcs
;
1548 const void *collect_data
[3];
1551 struct ChainContextApplyLookupContext
1553 ContextApplyFuncs funcs
;
1554 const void *match_data
[3];
1557 static inline void chain_context_closure_lookup (hb_closure_context_t
*c
,
1558 unsigned int backtrackCount
,
1559 const USHORT backtrack
[],
1560 unsigned int inputCount
, /* Including the first glyph (not matched) */
1561 const USHORT input
[], /* Array of input values--start with second glyph */
1562 unsigned int lookaheadCount
,
1563 const USHORT lookahead
[],
1564 unsigned int lookupCount
,
1565 const LookupRecord lookupRecord
[],
1566 ChainContextClosureLookupContext
&lookup_context
)
1568 if (intersects_array (c
,
1569 backtrackCount
, backtrack
,
1570 lookup_context
.funcs
.intersects
, lookup_context
.intersects_data
[0])
1571 && intersects_array (c
,
1572 inputCount
? inputCount
- 1 : 0, input
,
1573 lookup_context
.funcs
.intersects
, lookup_context
.intersects_data
[1])
1574 && intersects_array (c
,
1575 lookaheadCount
, lookahead
,
1576 lookup_context
.funcs
.intersects
, lookup_context
.intersects_data
[2]))
1578 lookupCount
, lookupRecord
);
1581 static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t
*c
,
1582 unsigned int backtrackCount
,
1583 const USHORT backtrack
[],
1584 unsigned int inputCount
, /* Including the first glyph (not matched) */
1585 const USHORT input
[], /* Array of input values--start with second glyph */
1586 unsigned int lookaheadCount
,
1587 const USHORT lookahead
[],
1588 unsigned int lookupCount
,
1589 const LookupRecord lookupRecord
[],
1590 ChainContextCollectGlyphsLookupContext
&lookup_context
)
1592 collect_array (c
, c
->before
,
1593 backtrackCount
, backtrack
,
1594 lookup_context
.funcs
.collect
, lookup_context
.collect_data
[0]);
1595 collect_array (c
, c
->input
,
1596 inputCount
? inputCount
- 1 : 0, input
,
1597 lookup_context
.funcs
.collect
, lookup_context
.collect_data
[1]);
1598 collect_array (c
, c
->after
,
1599 lookaheadCount
, lookahead
,
1600 lookup_context
.funcs
.collect
, lookup_context
.collect_data
[2]);
1602 lookupCount
, lookupRecord
);
1605 static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t
*c
,
1606 unsigned int backtrackCount
,
1607 const USHORT backtrack
[] HB_UNUSED
,
1608 unsigned int inputCount
, /* Including the first glyph (not matched) */
1609 const USHORT input
[], /* Array of input values--start with second glyph */
1610 unsigned int lookaheadCount
,
1611 const USHORT lookahead
[] HB_UNUSED
,
1612 unsigned int lookupCount HB_UNUSED
,
1613 const LookupRecord lookupRecord
[] HB_UNUSED
,
1614 ChainContextApplyLookupContext
&lookup_context
)
1616 return (c
->zero_context
? !backtrackCount
&& !lookaheadCount
: true)
1617 && would_match_input (c
,
1619 lookup_context
.funcs
.match
, lookup_context
.match_data
[1]);
1622 static inline bool chain_context_apply_lookup (hb_apply_context_t
*c
,
1623 unsigned int backtrackCount
,
1624 const USHORT backtrack
[],
1625 unsigned int inputCount
, /* Including the first glyph (not matched) */
1626 const USHORT input
[], /* Array of input values--start with second glyph */
1627 unsigned int lookaheadCount
,
1628 const USHORT lookahead
[],
1629 unsigned int lookupCount
,
1630 const LookupRecord lookupRecord
[],
1631 ChainContextApplyLookupContext
&lookup_context
)
1633 unsigned int match_length
= 0;
1634 unsigned int match_positions
[MAX_CONTEXT_LENGTH
];
1635 return match_input (c
,
1637 lookup_context
.funcs
.match
, lookup_context
.match_data
[1],
1638 &match_length
, match_positions
)
1639 && match_backtrack (c
,
1640 backtrackCount
, backtrack
,
1641 lookup_context
.funcs
.match
, lookup_context
.match_data
[0])
1642 && match_lookahead (c
,
1643 lookaheadCount
, lookahead
,
1644 lookup_context
.funcs
.match
, lookup_context
.match_data
[2],
1647 inputCount
, match_positions
,
1648 lookupCount
, lookupRecord
,
1654 inline void closure (hb_closure_context_t
*c
, ChainContextClosureLookupContext
&lookup_context
) const
1656 TRACE_CLOSURE (this);
1657 const HeadlessArrayOf
<USHORT
> &input
= StructAfter
<HeadlessArrayOf
<USHORT
> > (backtrack
);
1658 const ArrayOf
<USHORT
> &lookahead
= StructAfter
<ArrayOf
<USHORT
> > (input
);
1659 const ArrayOf
<LookupRecord
> &lookup
= StructAfter
<ArrayOf
<LookupRecord
> > (lookahead
);
1660 chain_context_closure_lookup (c
,
1661 backtrack
.len
, backtrack
.array
,
1662 input
.len
, input
.array
,
1663 lookahead
.len
, lookahead
.array
,
1664 lookup
.len
, lookup
.array
,
1668 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
, ChainContextCollectGlyphsLookupContext
&lookup_context
) const
1670 TRACE_COLLECT_GLYPHS (this);
1671 const HeadlessArrayOf
<USHORT
> &input
= StructAfter
<HeadlessArrayOf
<USHORT
> > (backtrack
);
1672 const ArrayOf
<USHORT
> &lookahead
= StructAfter
<ArrayOf
<USHORT
> > (input
);
1673 const ArrayOf
<LookupRecord
> &lookup
= StructAfter
<ArrayOf
<LookupRecord
> > (lookahead
);
1674 chain_context_collect_glyphs_lookup (c
,
1675 backtrack
.len
, backtrack
.array
,
1676 input
.len
, input
.array
,
1677 lookahead
.len
, lookahead
.array
,
1678 lookup
.len
, lookup
.array
,
1682 inline bool would_apply (hb_would_apply_context_t
*c
, ChainContextApplyLookupContext
&lookup_context
) const
1684 TRACE_WOULD_APPLY (this);
1685 const HeadlessArrayOf
<USHORT
> &input
= StructAfter
<HeadlessArrayOf
<USHORT
> > (backtrack
);
1686 const ArrayOf
<USHORT
> &lookahead
= StructAfter
<ArrayOf
<USHORT
> > (input
);
1687 const ArrayOf
<LookupRecord
> &lookup
= StructAfter
<ArrayOf
<LookupRecord
> > (lookahead
);
1688 return TRACE_RETURN (chain_context_would_apply_lookup (c
,
1689 backtrack
.len
, backtrack
.array
,
1690 input
.len
, input
.array
,
1691 lookahead
.len
, lookahead
.array
, lookup
.len
,
1692 lookup
.array
, lookup_context
));
1695 inline bool apply (hb_apply_context_t
*c
, ChainContextApplyLookupContext
&lookup_context
) const
1698 const HeadlessArrayOf
<USHORT
> &input
= StructAfter
<HeadlessArrayOf
<USHORT
> > (backtrack
);
1699 const ArrayOf
<USHORT
> &lookahead
= StructAfter
<ArrayOf
<USHORT
> > (input
);
1700 const ArrayOf
<LookupRecord
> &lookup
= StructAfter
<ArrayOf
<LookupRecord
> > (lookahead
);
1701 return TRACE_RETURN (chain_context_apply_lookup (c
,
1702 backtrack
.len
, backtrack
.array
,
1703 input
.len
, input
.array
,
1704 lookahead
.len
, lookahead
.array
, lookup
.len
,
1705 lookup
.array
, lookup_context
));
1708 inline bool sanitize (hb_sanitize_context_t
*c
) {
1709 TRACE_SANITIZE (this);
1710 if (!backtrack
.sanitize (c
)) return TRACE_RETURN (false);
1711 HeadlessArrayOf
<USHORT
> &input
= StructAfter
<HeadlessArrayOf
<USHORT
> > (backtrack
);
1712 if (!input
.sanitize (c
)) return TRACE_RETURN (false);
1713 ArrayOf
<USHORT
> &lookahead
= StructAfter
<ArrayOf
<USHORT
> > (input
);
1714 if (!lookahead
.sanitize (c
)) return TRACE_RETURN (false);
1715 ArrayOf
<LookupRecord
> &lookup
= StructAfter
<ArrayOf
<LookupRecord
> > (lookahead
);
1716 return TRACE_RETURN (lookup
.sanitize (c
));
1721 backtrack
; /* Array of backtracking values
1722 * (to be matched before the input
1724 HeadlessArrayOf
<USHORT
>
1725 inputX
; /* Array of input values (start with
1728 lookaheadX
; /* Array of lookahead values's (to be
1729 * matched after the input sequence) */
1730 ArrayOf
<LookupRecord
>
1731 lookupX
; /* Array of LookupRecords--in
1734 DEFINE_SIZE_MIN (8);
1739 inline void closure (hb_closure_context_t
*c
, ChainContextClosureLookupContext
&lookup_context
) const
1741 TRACE_CLOSURE (this);
1742 unsigned int num_rules
= rule
.len
;
1743 for (unsigned int i
= 0; i
< num_rules
; i
++)
1744 (this+rule
[i
]).closure (c
, lookup_context
);
1747 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
, ChainContextCollectGlyphsLookupContext
&lookup_context
) const
1749 TRACE_COLLECT_GLYPHS (this);
1750 unsigned int num_rules
= rule
.len
;
1751 for (unsigned int i
= 0; i
< num_rules
; i
++)
1752 (this+rule
[i
]).collect_glyphs (c
, lookup_context
);
1755 inline bool would_apply (hb_would_apply_context_t
*c
, ChainContextApplyLookupContext
&lookup_context
) const
1757 TRACE_WOULD_APPLY (this);
1758 unsigned int num_rules
= rule
.len
;
1759 for (unsigned int i
= 0; i
< num_rules
; i
++)
1760 if ((this+rule
[i
]).would_apply (c
, lookup_context
))
1761 return TRACE_RETURN (true);
1763 return TRACE_RETURN (false);
1766 inline bool apply (hb_apply_context_t
*c
, ChainContextApplyLookupContext
&lookup_context
) const
1769 unsigned int num_rules
= rule
.len
;
1770 for (unsigned int i
= 0; i
< num_rules
; i
++)
1771 if ((this+rule
[i
]).apply (c
, lookup_context
))
1772 return TRACE_RETURN (true);
1774 return TRACE_RETURN (false);
1777 inline bool sanitize (hb_sanitize_context_t
*c
) {
1778 TRACE_SANITIZE (this);
1779 return TRACE_RETURN (rule
.sanitize (c
, this));
1783 OffsetArrayOf
<ChainRule
>
1784 rule
; /* Array of ChainRule tables
1785 * ordered by preference */
1787 DEFINE_SIZE_ARRAY (2, rule
);
1790 struct ChainContextFormat1
1792 inline void closure (hb_closure_context_t
*c
) const
1794 TRACE_CLOSURE (this);
1795 const Coverage
&cov
= (this+coverage
);
1797 struct ChainContextClosureLookupContext lookup_context
= {
1802 unsigned int count
= ruleSet
.len
;
1803 for (unsigned int i
= 0; i
< count
; i
++)
1804 if (cov
.intersects_coverage (c
->glyphs
, i
)) {
1805 const ChainRuleSet
&rule_set
= this+ruleSet
[i
];
1806 rule_set
.closure (c
, lookup_context
);
1810 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
1812 TRACE_COLLECT_GLYPHS (this);
1813 (this+coverage
).add_coverage (c
->input
);
1815 struct ChainContextCollectGlyphsLookupContext lookup_context
= {
1820 unsigned int count
= ruleSet
.len
;
1821 for (unsigned int i
= 0; i
< count
; i
++)
1822 (this+ruleSet
[i
]).collect_glyphs (c
, lookup_context
);
1825 inline bool would_apply (hb_would_apply_context_t
*c
) const
1827 TRACE_WOULD_APPLY (this);
1829 const ChainRuleSet
&rule_set
= this+ruleSet
[(this+coverage
).get_coverage (c
->glyphs
[0])];
1830 struct ChainContextApplyLookupContext lookup_context
= {
1834 return TRACE_RETURN (rule_set
.would_apply (c
, lookup_context
));
1837 inline const Coverage
&get_coverage (void) const
1839 return this+coverage
;
1842 inline bool apply (hb_apply_context_t
*c
) const
1845 unsigned int index
= (this+coverage
).get_coverage (c
->buffer
->cur().codepoint
);
1846 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
1848 const ChainRuleSet
&rule_set
= this+ruleSet
[index
];
1849 struct ChainContextApplyLookupContext lookup_context
= {
1853 return TRACE_RETURN (rule_set
.apply (c
, lookup_context
));
1856 inline bool sanitize (hb_sanitize_context_t
*c
) {
1857 TRACE_SANITIZE (this);
1858 return TRACE_RETURN (coverage
.sanitize (c
, this) && ruleSet
.sanitize (c
, this));
1862 USHORT format
; /* Format identifier--format = 1 */
1864 coverage
; /* Offset to Coverage table--from
1865 * beginning of table */
1866 OffsetArrayOf
<ChainRuleSet
>
1867 ruleSet
; /* Array of ChainRuleSet tables
1868 * ordered by Coverage Index */
1870 DEFINE_SIZE_ARRAY (6, ruleSet
);
1873 struct ChainContextFormat2
1875 inline void closure (hb_closure_context_t
*c
) const
1877 TRACE_CLOSURE (this);
1878 if (!(this+coverage
).intersects (c
->glyphs
))
1881 const ClassDef
&backtrack_class_def
= this+backtrackClassDef
;
1882 const ClassDef
&input_class_def
= this+inputClassDef
;
1883 const ClassDef
&lookahead_class_def
= this+lookaheadClassDef
;
1885 struct ChainContextClosureLookupContext lookup_context
= {
1887 {&backtrack_class_def
,
1889 &lookahead_class_def
}
1892 unsigned int count
= ruleSet
.len
;
1893 for (unsigned int i
= 0; i
< count
; i
++)
1894 if (input_class_def
.intersects_class (c
->glyphs
, i
)) {
1895 const ChainRuleSet
&rule_set
= this+ruleSet
[i
];
1896 rule_set
.closure (c
, lookup_context
);
1900 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
1902 TRACE_COLLECT_GLYPHS (this);
1903 (this+coverage
).add_coverage (c
->input
);
1905 const ClassDef
&backtrack_class_def
= this+backtrackClassDef
;
1906 const ClassDef
&input_class_def
= this+inputClassDef
;
1907 const ClassDef
&lookahead_class_def
= this+lookaheadClassDef
;
1909 struct ChainContextCollectGlyphsLookupContext lookup_context
= {
1911 {&backtrack_class_def
,
1913 &lookahead_class_def
}
1916 unsigned int count
= ruleSet
.len
;
1917 for (unsigned int i
= 0; i
< count
; i
++)
1918 (this+ruleSet
[i
]).collect_glyphs (c
, lookup_context
);
1921 inline bool would_apply (hb_would_apply_context_t
*c
) const
1923 TRACE_WOULD_APPLY (this);
1925 const ClassDef
&backtrack_class_def
= this+backtrackClassDef
;
1926 const ClassDef
&input_class_def
= this+inputClassDef
;
1927 const ClassDef
&lookahead_class_def
= this+lookaheadClassDef
;
1929 unsigned int index
= input_class_def
.get_class (c
->glyphs
[0]);
1930 const ChainRuleSet
&rule_set
= this+ruleSet
[index
];
1931 struct ChainContextApplyLookupContext lookup_context
= {
1933 {&backtrack_class_def
,
1935 &lookahead_class_def
}
1937 return TRACE_RETURN (rule_set
.would_apply (c
, lookup_context
));
1940 inline const Coverage
&get_coverage (void) const
1942 return this+coverage
;
1945 inline bool apply (hb_apply_context_t
*c
) const
1948 unsigned int index
= (this+coverage
).get_coverage (c
->buffer
->cur().codepoint
);
1949 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
1951 const ClassDef
&backtrack_class_def
= this+backtrackClassDef
;
1952 const ClassDef
&input_class_def
= this+inputClassDef
;
1953 const ClassDef
&lookahead_class_def
= this+lookaheadClassDef
;
1955 index
= input_class_def
.get_class (c
->buffer
->cur().codepoint
);
1956 const ChainRuleSet
&rule_set
= this+ruleSet
[index
];
1957 struct ChainContextApplyLookupContext lookup_context
= {
1959 {&backtrack_class_def
,
1961 &lookahead_class_def
}
1963 return TRACE_RETURN (rule_set
.apply (c
, lookup_context
));
1966 inline bool sanitize (hb_sanitize_context_t
*c
) {
1967 TRACE_SANITIZE (this);
1968 return TRACE_RETURN (coverage
.sanitize (c
, this) && backtrackClassDef
.sanitize (c
, this) &&
1969 inputClassDef
.sanitize (c
, this) && lookaheadClassDef
.sanitize (c
, this) &&
1970 ruleSet
.sanitize (c
, this));
1974 USHORT format
; /* Format identifier--format = 2 */
1976 coverage
; /* Offset to Coverage table--from
1977 * beginning of table */
1979 backtrackClassDef
; /* Offset to glyph ClassDef table
1980 * containing backtrack sequence
1981 * data--from beginning of table */
1983 inputClassDef
; /* Offset to glyph ClassDef
1984 * table containing input sequence
1985 * data--from beginning of table */
1987 lookaheadClassDef
; /* Offset to glyph ClassDef table
1988 * containing lookahead sequence
1989 * data--from beginning of table */
1990 OffsetArrayOf
<ChainRuleSet
>
1991 ruleSet
; /* Array of ChainRuleSet tables
1992 * ordered by class */
1994 DEFINE_SIZE_ARRAY (12, ruleSet
);
1997 struct ChainContextFormat3
1999 inline void closure (hb_closure_context_t
*c
) const
2001 TRACE_CLOSURE (this);
2002 const OffsetArrayOf
<Coverage
> &input
= StructAfter
<OffsetArrayOf
<Coverage
> > (backtrack
);
2004 if (!(this+input
[0]).intersects (c
->glyphs
))
2007 const OffsetArrayOf
<Coverage
> &lookahead
= StructAfter
<OffsetArrayOf
<Coverage
> > (input
);
2008 const ArrayOf
<LookupRecord
> &lookup
= StructAfter
<ArrayOf
<LookupRecord
> > (lookahead
);
2009 struct ChainContextClosureLookupContext lookup_context
= {
2010 {intersects_coverage
},
2013 chain_context_closure_lookup (c
,
2014 backtrack
.len
, (const USHORT
*) backtrack
.array
,
2015 input
.len
, (const USHORT
*) input
.array
+ 1,
2016 lookahead
.len
, (const USHORT
*) lookahead
.array
,
2017 lookup
.len
, lookup
.array
,
2021 inline void collect_glyphs (hb_collect_glyphs_context_t
*c
) const
2023 TRACE_COLLECT_GLYPHS (this);
2024 const OffsetArrayOf
<Coverage
> &input
= StructAfter
<OffsetArrayOf
<Coverage
> > (backtrack
);
2026 (this+input
[0]).add_coverage (c
->input
);
2028 const OffsetArrayOf
<Coverage
> &lookahead
= StructAfter
<OffsetArrayOf
<Coverage
> > (input
);
2029 const ArrayOf
<LookupRecord
> &lookup
= StructAfter
<ArrayOf
<LookupRecord
> > (lookahead
);
2030 struct ChainContextCollectGlyphsLookupContext lookup_context
= {
2034 chain_context_collect_glyphs_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 bool would_apply (hb_would_apply_context_t
*c
) const
2044 TRACE_WOULD_APPLY (this);
2046 const OffsetArrayOf
<Coverage
> &input
= StructAfter
<OffsetArrayOf
<Coverage
> > (backtrack
);
2047 const OffsetArrayOf
<Coverage
> &lookahead
= StructAfter
<OffsetArrayOf
<Coverage
> > (input
);
2048 const ArrayOf
<LookupRecord
> &lookup
= StructAfter
<ArrayOf
<LookupRecord
> > (lookahead
);
2049 struct ChainContextApplyLookupContext lookup_context
= {
2053 return TRACE_RETURN (chain_context_would_apply_lookup (c
,
2054 backtrack
.len
, (const USHORT
*) backtrack
.array
,
2055 input
.len
, (const USHORT
*) input
.array
+ 1,
2056 lookahead
.len
, (const USHORT
*) lookahead
.array
,
2057 lookup
.len
, lookup
.array
, lookup_context
));
2060 inline const Coverage
&get_coverage (void) const
2062 const OffsetArrayOf
<Coverage
> &input
= StructAfter
<OffsetArrayOf
<Coverage
> > (backtrack
);
2063 return this+input
[0];
2066 inline bool apply (hb_apply_context_t
*c
) const
2069 const OffsetArrayOf
<Coverage
> &input
= StructAfter
<OffsetArrayOf
<Coverage
> > (backtrack
);
2071 unsigned int index
= (this+input
[0]).get_coverage (c
->buffer
->cur().codepoint
);
2072 if (likely (index
== NOT_COVERED
)) return TRACE_RETURN (false);
2074 const OffsetArrayOf
<Coverage
> &lookahead
= StructAfter
<OffsetArrayOf
<Coverage
> > (input
);
2075 const ArrayOf
<LookupRecord
> &lookup
= StructAfter
<ArrayOf
<LookupRecord
> > (lookahead
);
2076 struct ChainContextApplyLookupContext lookup_context
= {
2080 return TRACE_RETURN (chain_context_apply_lookup (c
,
2081 backtrack
.len
, (const USHORT
*) backtrack
.array
,
2082 input
.len
, (const USHORT
*) input
.array
+ 1,
2083 lookahead
.len
, (const USHORT
*) lookahead
.array
,
2084 lookup
.len
, lookup
.array
, lookup_context
));
2087 inline bool sanitize (hb_sanitize_context_t
*c
) {
2088 TRACE_SANITIZE (this);
2089 if (!backtrack
.sanitize (c
, this)) return TRACE_RETURN (false);
2090 OffsetArrayOf
<Coverage
> &input
= StructAfter
<OffsetArrayOf
<Coverage
> > (backtrack
);
2091 if (!input
.sanitize (c
, this)) return TRACE_RETURN (false);
2092 OffsetArrayOf
<Coverage
> &lookahead
= StructAfter
<OffsetArrayOf
<Coverage
> > (input
);
2093 if (!lookahead
.sanitize (c
, this)) return TRACE_RETURN (false);
2094 ArrayOf
<LookupRecord
> &lookup
= StructAfter
<ArrayOf
<LookupRecord
> > (lookahead
);
2095 return TRACE_RETURN (lookup
.sanitize (c
));
2099 USHORT format
; /* Format identifier--format = 3 */
2100 OffsetArrayOf
<Coverage
>
2101 backtrack
; /* Array of coverage tables
2102 * in backtracking sequence, in glyph
2104 OffsetArrayOf
<Coverage
>
2105 inputX
; /* Array of coverage
2106 * tables in input sequence, in glyph
2108 OffsetArrayOf
<Coverage
>
2109 lookaheadX
; /* Array of coverage tables
2110 * in lookahead sequence, in glyph
2112 ArrayOf
<LookupRecord
>
2113 lookupX
; /* Array of LookupRecords--in
2116 DEFINE_SIZE_MIN (10);
2121 template <typename context_t
>
2122 inline typename
context_t::return_t
dispatch (context_t
*c
) const
2124 TRACE_DISPATCH (this);
2126 case 1: return TRACE_RETURN (c
->dispatch (u
.format1
));
2127 case 2: return TRACE_RETURN (c
->dispatch (u
.format2
));
2128 case 3: return TRACE_RETURN (c
->dispatch (u
.format3
));
2129 default:return TRACE_RETURN (c
->default_return_value ());
2133 inline bool sanitize (hb_sanitize_context_t
*c
) {
2134 TRACE_SANITIZE (this);
2135 if (!u
.format
.sanitize (c
)) return TRACE_RETURN (false);
2137 case 1: return TRACE_RETURN (u
.format1
.sanitize (c
));
2138 case 2: return TRACE_RETURN (u
.format2
.sanitize (c
));
2139 case 3: return TRACE_RETURN (u
.format3
.sanitize (c
));
2140 default:return TRACE_RETURN (true);
2146 USHORT format
; /* Format identifier */
2147 ChainContextFormat1 format1
;
2148 ChainContextFormat2 format2
;
2149 ChainContextFormat3 format3
;
2154 struct ExtensionFormat1
2156 inline unsigned int get_type (void) const { return extensionLookupType
; }
2157 inline unsigned int get_offset (void) const { return extensionOffset
; }
2159 inline bool sanitize (hb_sanitize_context_t
*c
) {
2160 TRACE_SANITIZE (this);
2161 return TRACE_RETURN (c
->check_struct (this));
2165 USHORT format
; /* Format identifier. Set to 1. */
2166 USHORT extensionLookupType
; /* Lookup type of subtable referenced
2167 * by ExtensionOffset (i.e. the
2168 * extension subtable). */
2169 ULONG extensionOffset
; /* Offset to the extension subtable,
2170 * of lookup type subtable. */
2172 DEFINE_SIZE_STATIC (8);
2175 template <typename T
>
2178 inline unsigned int get_type (void) const
2181 case 1: return u
.format1
.get_type ();
2185 inline unsigned int get_offset (void) const
2188 case 1: return u
.format1
.get_offset ();
2193 template <typename X
>
2194 inline const X
& get_subtable (void) const
2196 unsigned int offset
= get_offset ();
2197 if (unlikely (!offset
)) return Null(typename
T::LookupSubTable
);
2198 return StructAtOffset
<typename
T::LookupSubTable
> (this, offset
);
2201 template <typename context_t
>
2202 inline typename
context_t::return_t
dispatch (context_t
*c
) const
2204 return get_subtable
<typename
T::LookupSubTable
> ().dispatch (c
, get_type ());
2207 inline bool sanitize_self (hb_sanitize_context_t
*c
) {
2208 TRACE_SANITIZE (this);
2209 if (!u
.format
.sanitize (c
)) return TRACE_RETURN (false);
2211 case 1: return TRACE_RETURN (u
.format1
.sanitize (c
));
2212 default:return TRACE_RETURN (true);
2216 inline bool sanitize (hb_sanitize_context_t
*c
) {
2217 TRACE_SANITIZE (this);
2218 if (!sanitize_self (c
)) return TRACE_RETURN (false);
2219 unsigned int offset
= get_offset ();
2220 if (unlikely (!offset
)) return TRACE_RETURN (true);
2221 return TRACE_RETURN (StructAtOffset
<typename
T::LookupSubTable
> (this, offset
).sanitize (c
, get_type ()));
2226 USHORT format
; /* Format identifier */
2227 ExtensionFormat1 format1
;
2238 static const hb_tag_t GSUBTag
= HB_OT_TAG_GSUB
;
2239 static const hb_tag_t GPOSTag
= HB_OT_TAG_GPOS
;
2241 inline unsigned int get_script_count (void) const
2242 { return (this+scriptList
).len
; }
2243 inline const Tag
& get_script_tag (unsigned int i
) const
2244 { return (this+scriptList
).get_tag (i
); }
2245 inline unsigned int get_script_tags (unsigned int start_offset
,
2246 unsigned int *script_count
/* IN/OUT */,
2247 hb_tag_t
*script_tags
/* OUT */) const
2248 { return (this+scriptList
).get_tags (start_offset
, script_count
, script_tags
); }
2249 inline const Script
& get_script (unsigned int i
) const
2250 { return (this+scriptList
)[i
]; }
2251 inline bool find_script_index (hb_tag_t tag
, unsigned int *index
) const
2252 { return (this+scriptList
).find_index (tag
, index
); }
2254 inline unsigned int get_feature_count (void) const
2255 { return (this+featureList
).len
; }
2256 inline const Tag
& get_feature_tag (unsigned int i
) const
2257 { return (this+featureList
).get_tag (i
); }
2258 inline unsigned int get_feature_tags (unsigned int start_offset
,
2259 unsigned int *feature_count
/* IN/OUT */,
2260 hb_tag_t
*feature_tags
/* OUT */) const
2261 { return (this+featureList
).get_tags (start_offset
, feature_count
, feature_tags
); }
2262 inline const Feature
& get_feature (unsigned int i
) const
2263 { return (this+featureList
)[i
]; }
2264 inline bool find_feature_index (hb_tag_t tag
, unsigned int *index
) const
2265 { return (this+featureList
).find_index (tag
, index
); }
2267 inline unsigned int get_lookup_count (void) const
2268 { return (this+lookupList
).len
; }
2269 inline const Lookup
& get_lookup (unsigned int i
) const
2270 { return (this+lookupList
)[i
]; }
2272 inline bool sanitize (hb_sanitize_context_t
*c
) {
2273 TRACE_SANITIZE (this);
2274 return TRACE_RETURN (version
.sanitize (c
) && likely (version
.major
== 1) &&
2275 scriptList
.sanitize (c
, this) &&
2276 featureList
.sanitize (c
, this) &&
2277 lookupList
.sanitize (c
, this));
2281 FixedVersion version
; /* Version of the GSUB/GPOS table--initially set
2283 OffsetTo
<ScriptList
>
2284 scriptList
; /* ScriptList table */
2285 OffsetTo
<FeatureList
>
2286 featureList
; /* FeatureList table */
2287 OffsetTo
<LookupList
>
2288 lookupList
; /* LookupList table */
2290 DEFINE_SIZE_STATIC (10);
2294 } /* namespace OT */
2297 #endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */