diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh index c8020d87c..94055b343 100644 --- a/src/hb-ot-layout-gpos-table.hh +++ b/src/hb-ot-layout-gpos-table.hh @@ -1333,7 +1333,7 @@ struct PosLookupSubTable case MarkBase: return TRACE_RETURN (u.markBase.apply (c)); case MarkLig: return TRACE_RETURN (u.markLig.apply (c)); case MarkMark: return TRACE_RETURN (u.markMark.apply (c)); - case Context: return TRACE_RETURN (u.c.apply (c)); + case Context: return TRACE_RETURN (u.context.apply (c)); case ChainContext: return TRACE_RETURN (u.chainContext.apply (c)); case Extension: return TRACE_RETURN (u.extension.apply (c)); default: return TRACE_RETURN (false); @@ -1352,7 +1352,7 @@ struct PosLookupSubTable case MarkBase: return TRACE_RETURN (u.markBase.sanitize (c)); case MarkLig: return TRACE_RETURN (u.markLig.sanitize (c)); case MarkMark: return TRACE_RETURN (u.markMark.sanitize (c)); - case Context: return TRACE_RETURN (u.c.sanitize (c)); + case Context: return TRACE_RETURN (u.context.sanitize (c)); case ChainContext: return TRACE_RETURN (u.chainContext.sanitize (c)); case Extension: return TRACE_RETURN (u.extension.sanitize (c)); default: return TRACE_RETURN (true); @@ -1371,7 +1371,7 @@ struct PosLookupSubTable MarkBasePos markBase; MarkLigPos markLig; MarkMarkPos markMark; - ContextPos c; + ContextPos context; ChainContextPos chainContext; ExtensionPos extension; } u; diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh index 8a0bc3cec..9a72c236b 100644 --- a/src/hb-ot-layout-gsub-table.hh +++ b/src/hb-ot-layout-gsub-table.hh @@ -50,9 +50,9 @@ struct SingleSubstFormat1 } } - inline bool would_apply (hb_codepoint_t glyph_id) const + inline bool would_apply (hb_would_apply_context_t *c) const { - return (this+coverage) (glyph_id) != NOT_COVERED; + return c->len == 1 && (this+coverage) (c->first) != NOT_COVERED; } inline bool apply (hb_apply_context_t *c) const @@ -102,9 +102,9 @@ struct SingleSubstFormat2 } } - inline bool would_apply (hb_codepoint_t glyph_id) const + inline bool would_apply (hb_would_apply_context_t *c) const { - return (this+coverage) (glyph_id) != NOT_COVERED; + return c->len == 1 && (this+coverage) (c->first) != NOT_COVERED; } inline bool apply (hb_apply_context_t *c) const @@ -155,11 +155,11 @@ struct SingleSubst } } - inline bool would_apply (hb_codepoint_t glyph_id) const + inline bool would_apply (hb_would_apply_context_t *c) const { switch (u.format) { - case 1: return u.format1.would_apply (glyph_id); - case 2: return u.format2.would_apply (glyph_id); + case 1: return u.format1.would_apply (c); + case 2: return u.format2.would_apply (c); default:return false; } } @@ -252,9 +252,9 @@ struct MultipleSubstFormat1 } } - inline bool would_apply (hb_codepoint_t glyph_id) const + inline bool would_apply (hb_would_apply_context_t *c) const { - return (this+coverage) (glyph_id) != NOT_COVERED; + return c->len == 1 && (this+coverage) (c->first) != NOT_COVERED; } inline bool apply (hb_apply_context_t *c) const @@ -299,10 +299,10 @@ struct MultipleSubst } } - inline bool would_apply (hb_codepoint_t glyph_id) const + inline bool would_apply (hb_would_apply_context_t *c) const { switch (u.format) { - case 1: return u.format1.would_apply (glyph_id); + case 1: return u.format1.would_apply (c); default:return false; } } @@ -356,9 +356,9 @@ struct AlternateSubstFormat1 } } - inline bool would_apply (hb_codepoint_t glyph_id) const + inline bool would_apply (hb_would_apply_context_t *c) const { - return (this+coverage) (glyph_id) != NOT_COVERED; + return c->len == 1 && (this+coverage) (c->first) != NOT_COVERED; } inline bool apply (hb_apply_context_t *c) const @@ -421,10 +421,10 @@ struct AlternateSubst } } - inline bool would_apply (hb_codepoint_t glyph_id) const + inline bool would_apply (hb_would_apply_context_t *c) const { switch (u.format) { - case 1: return u.format1.would_apply (glyph_id); + case 1: return u.format1.would_apply (c); default:return false; } } @@ -471,9 +471,9 @@ struct Ligature c->glyphs->add (ligGlyph); } - inline bool would_apply (hb_codepoint_t second) const + inline bool would_apply (hb_would_apply_context_t *c) const { - return component.len == 2 && component[1] == second; + return c->len == 1 || (c->len == 2 && component.len == 2 && component[1] == c->second); } inline bool apply (hb_apply_context_t *c) const @@ -568,13 +568,13 @@ struct LigatureSet (this+ligature[i]).closure (c); } - inline bool would_apply (hb_codepoint_t second) const + inline bool would_apply (hb_would_apply_context_t *c) const { unsigned int num_ligs = ligature.len; for (unsigned int i = 0; i < num_ligs; i++) { const Ligature &lig = this+ligature[i]; - if (lig.would_apply (second)) + if (lig.would_apply (c)) return true; } return false; @@ -623,11 +623,11 @@ struct LigatureSubstFormat1 } } - inline bool would_apply (hb_codepoint_t first, hb_codepoint_t second) const + inline bool would_apply (hb_would_apply_context_t *c) const { unsigned int index; - return (index = (this+coverage) (first)) != NOT_COVERED && - (this+ligatureSet[index]).would_apply (second); + return (index = (this+coverage) (c->first)) != NOT_COVERED && + (this+ligatureSet[index]).would_apply (c); } inline bool apply (hb_apply_context_t *c) const @@ -674,10 +674,10 @@ struct LigatureSubst } } - inline bool would_apply (hb_codepoint_t first, hb_codepoint_t second) const + inline bool would_apply (hb_would_apply_context_t *c) const { switch (u.format) { - case 1: return u.format1.would_apply (first, second); + case 1: return u.format1.would_apply (c); default:return false; } } @@ -764,8 +764,7 @@ struct ExtensionSubst : Extension } inline void closure (hb_closure_context_t *c) const; - inline bool would_apply (hb_codepoint_t glyph_id) const; - inline bool would_apply (hb_codepoint_t first, hb_codepoint_t second) const; + inline bool would_apply (hb_would_apply_context_t *c) const; inline bool apply (hb_apply_context_t *c) const; @@ -935,7 +934,7 @@ struct SubstLookupSubTable case Multiple: u.multiple.closure (c); break; case Alternate: u.alternate.closure (c); break; case Ligature: u.ligature.closure (c); break; - case Context: u.c.closure (c); break; + case Context: u.context.closure (c); break; case ChainContext: u.chainContext.closure (c); break; case Extension: u.extension.closure (c); break; case ReverseChainSingle: u.reverseChainContextSingle.closure (c); break; @@ -943,28 +942,6 @@ struct SubstLookupSubTable } } - inline bool would_apply (hb_codepoint_t glyph_id, - unsigned int lookup_type) const - { - switch (lookup_type) { - case Single: return u.single.would_apply (glyph_id); - case Multiple: return u.multiple.would_apply (glyph_id); - case Alternate: return u.alternate.would_apply (glyph_id); - case Extension: return u.extension.would_apply (glyph_id); - default: return false; - } - } - inline bool would_apply (hb_codepoint_t first, - hb_codepoint_t second, - unsigned int lookup_type) const - { - switch (lookup_type) { - case Ligature: return u.ligature.would_apply (first, second); - case Extension: return u.extension.would_apply (first, second); - default: return false; - } - } - inline bool can_use_fast_path (unsigned int lookup_type) const { /* Fast path, for those that have coverage in the same place. @@ -975,6 +952,26 @@ struct SubstLookupSubTable hb_in_range (u.header.sub_format, 1, 2)); } + inline bool would_apply (hb_would_apply_context_t *c, + unsigned int lookup_type) const + { + TRACE_WOULD_APPLY (); + if (can_use_fast_path (lookup_type)) + { + unsigned int index = (this+u.header.coverage) (c->first); + if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); + } + switch (lookup_type) { + case Single: return u.single.would_apply (c); + case Multiple: return u.multiple.would_apply (c); + case Alternate: return u.alternate.would_apply (c); + case Context: return u.context.would_apply (c); + case ChainContext: return u.chainContext.would_apply (c); + case Extension: return u.extension.would_apply (c); + default: return false; + } + } + inline bool apply (hb_apply_context_t *c, unsigned int lookup_type) const { TRACE_APPLY (); @@ -989,7 +986,7 @@ struct SubstLookupSubTable case Multiple: return TRACE_RETURN (u.multiple.apply (c)); case Alternate: return TRACE_RETURN (u.alternate.apply (c)); case Ligature: return TRACE_RETURN (u.ligature.apply (c)); - case Context: return TRACE_RETURN (u.c.apply (c)); + case Context: return TRACE_RETURN (u.context.apply (c)); case ChainContext: return TRACE_RETURN (u.chainContext.apply (c)); case Extension: return TRACE_RETURN (u.extension.apply (c)); case ReverseChainSingle: return TRACE_RETURN (u.reverseChainContextSingle.apply (c)); @@ -1007,7 +1004,7 @@ struct SubstLookupSubTable case Multiple: return TRACE_RETURN (u.multiple.sanitize (c)); case Alternate: return TRACE_RETURN (u.alternate.sanitize (c)); case Ligature: return TRACE_RETURN (u.ligature.sanitize (c)); - case Context: return TRACE_RETURN (u.c.sanitize (c)); + case Context: return TRACE_RETURN (u.context.sanitize (c)); case ChainContext: return TRACE_RETURN (u.chainContext.sanitize (c)); case Extension: return TRACE_RETURN (u.extension.sanitize (c)); case ReverseChainSingle: return TRACE_RETURN (u.reverseChainContextSingle.sanitize (c)); @@ -1025,7 +1022,7 @@ struct SubstLookupSubTable MultipleSubst multiple; AlternateSubst alternate; LigatureSubst ligature; - ContextSubst c; + ContextSubst context; ChainContextSubst chainContext; ExtensionSubst extension; ReverseChainSingleSubst reverseChainContextSingle; @@ -1059,21 +1056,12 @@ struct SubstLookup : Lookup get_subtable (i).closure (c, lookup_type); } - inline bool would_apply (hb_codepoint_t glyph_id) const + inline bool would_apply (hb_would_apply_context_t *c) const { unsigned int lookup_type = get_type (); unsigned int count = get_subtable_count (); for (unsigned int i = 0; i < count; i++) - if (get_subtable (i).would_apply (glyph_id, lookup_type)) - return true; - return false; - } - inline bool would_apply (hb_codepoint_t first, hb_codepoint_t second) const - { - unsigned int lookup_type = get_type (); - unsigned int count = get_subtable_count (); - for (unsigned int i = 0; i < count; i++) - if (get_subtable (i).would_apply (first, second, lookup_type)) + if (get_subtable (i).would_apply (c, lookup_type)) return true; return false; } @@ -1173,6 +1161,9 @@ struct GSUB : GSUBGPOS inline const SubstLookup& get_lookup (unsigned int i) const { return CastR (GSUBGPOS::get_lookup (i)); } + inline bool would_substitute_lookup (hb_would_apply_context_t *c, unsigned int lookup_index) const + { return get_lookup (lookup_index).would_apply (c); } + inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index) const { return get_lookup (lookup_index).apply_string (c); } @@ -1219,14 +1210,9 @@ inline void ExtensionSubst::closure (hb_closure_context_t *c) const get_subtable ().closure (c, get_type ()); } -inline bool ExtensionSubst::would_apply (hb_codepoint_t glyph_id) const +inline bool ExtensionSubst::would_apply (hb_would_apply_context_t *c) const { - return get_subtable ().would_apply (glyph_id, get_type ()); -} - -inline bool ExtensionSubst::would_apply (hb_codepoint_t first, hb_codepoint_t second) const -{ - return get_subtable ().would_apply (first, second, get_type ()); + return get_subtable ().would_apply (c, get_type ()); } inline bool ExtensionSubst::apply (hb_apply_context_t *c) const diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh index 06049ecac..7e7b08385 100644 --- a/src/hb-ot-layout-gsubgpos-private.hh +++ b/src/hb-ot-layout-gsubgpos-private.hh @@ -69,7 +69,13 @@ static inline uint8_t allocate_lig_id (hb_buffer_t *buffer) { hb_auto_trace_t trace (&c->debug_depth, "CLOSURE", this, HB_FUNC, ""); -/* TODO Add TRACE_RETURN annotation for would_apply */ +/* TODO Add TRACE_RETURN annotation to gsub. */ +#ifndef HB_DEBUG_WOULD_APPLY +#define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0) +#endif + +#define TRACE_WOULD_APPLY() \ + hb_auto_trace_t trace (&c->debug_depth, "WOULD_APPLY", this, HB_FUNC, "first %u second %u", c->first, c->second); struct hb_closure_context_t @@ -83,13 +89,32 @@ struct hb_closure_context_t hb_closure_context_t (hb_face_t *face_, hb_set_t *glyphs_, unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) : - face (face_), glyphs (glyphs_), + face (face_), + glyphs (glyphs_), nesting_level_left (nesting_level_left_), debug_depth (0) {} }; + +struct hb_would_apply_context_t +{ + hb_face_t *face; + hb_codepoint_t first; + hb_codepoint_t second; + unsigned int len; + unsigned int debug_depth; + + hb_would_apply_context_t (hb_face_t *face_, + hb_codepoint_t first_, + hb_codepoint_t second_ = -1) : + face (face_), + first (first_), second (second_), len (second == (hb_codepoint_t) -1 ? 1 : 2), + debug_depth (0) {}; +}; + + #ifndef HB_DEBUG_APPLY #define HB_DEBUG_APPLY (HB_DEBUG+0) #endif @@ -320,6 +345,21 @@ static inline bool match_coverage (hb_codepoint_t glyph_id, const USHORT &value, } +static inline bool would_match_input (hb_would_apply_context_t *c, + unsigned int count, /* Including the first glyph (not matched) */ + const USHORT input[], /* Array of input values--start with second glyph */ + match_func_t match_func, + const void *match_data) +{ + if (count != c->len) + return false; + + for (unsigned int i = 1; i < count; i++) + if (likely (!match_func (c->second, input[i - 1], match_data))) + return false; + + return true; +} static inline bool match_input (hb_apply_context_t *c, unsigned int count, /* Including the first glyph (not matched) */ const USHORT input[], /* Array of input values--start with second glyph */ @@ -508,6 +548,17 @@ static inline void context_closure_lookup (hb_closure_context_t *c, } +static inline bool context_would_apply_lookup (hb_would_apply_context_t *c, + unsigned int inputCount, /* Including the first glyph (not matched) */ + const USHORT input[], /* Array of input values--start with second glyph */ + unsigned int lookupCount, + const LookupRecord lookupRecord[], + ContextApplyLookupContext &lookup_context) +{ + return would_match_input (c, + inputCount, input, + lookup_context.funcs.match, lookup_context.match_data); +} static inline bool context_apply_lookup (hb_apply_context_t *c, unsigned int inputCount, /* Including the first glyph (not matched) */ const USHORT input[], /* Array of input values--start with second glyph */ @@ -540,6 +591,13 @@ struct Rule lookup_context); } + inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const + { + TRACE_WOULD_APPLY (); + const LookupRecord *lookupRecord = &StructAtOffset (input, input[0].static_size * (inputCount ? inputCount - 1 : 0)); + return TRACE_RETURN (context_would_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context)); + } + inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const { TRACE_APPLY (); @@ -580,6 +638,18 @@ struct RuleSet (this+rule[i]).closure (c, lookup_context); } + inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const + { + TRACE_WOULD_APPLY (); + unsigned int num_rules = rule.len; + for (unsigned int i = 0; i < num_rules; i++) + { + if ((this+rule[i]).would_apply (c, lookup_context)) + return TRACE_RETURN (true); + } + return TRACE_RETURN (false); + } + inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const { TRACE_APPLY (); @@ -631,6 +701,21 @@ struct ContextFormat1 } } + inline bool would_apply (hb_would_apply_context_t *c) const + { + TRACE_WOULD_APPLY (); + unsigned int index = (this+coverage) (c->first); + if (likely (index == NOT_COVERED)) + return TRACE_RETURN (false); + + const RuleSet &rule_set = this+ruleSet[index]; + struct ContextApplyLookupContext lookup_context = { + {match_glyph, NULL}, + NULL + }; + return TRACE_RETURN (rule_set.would_apply (c, lookup_context)); + } + inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const { TRACE_APPLY (); @@ -691,6 +776,22 @@ struct ContextFormat2 } } + inline bool would_apply (hb_would_apply_context_t *c) const + { + TRACE_WOULD_APPLY (); + unsigned int index = (this+coverage) (c->first); + if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); + + const ClassDef &class_def = this+classDef; + index = class_def (c->first); + const RuleSet &rule_set = this+ruleSet[index]; + struct ContextApplyLookupContext lookup_context = { + {match_class, NULL}, + &class_def + }; + return TRACE_RETURN (rule_set.would_apply (c, lookup_context)); + } + inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const { TRACE_APPLY (); @@ -751,6 +852,20 @@ struct ContextFormat3 lookup_context); } + inline bool would_apply (hb_would_apply_context_t *c) const + { + TRACE_WOULD_APPLY (); + unsigned int index = (this+coverage[0]) (c->first); + if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); + + const LookupRecord *lookupRecord = &StructAtOffset (coverage, coverage[0].static_size * glyphCount); + struct ContextApplyLookupContext lookup_context = { + {match_coverage, NULL}, + this + }; + return TRACE_RETURN (context_would_apply_lookup (c, glyphCount, (const USHORT *) (coverage + 1), lookupCount, lookupRecord, lookup_context)); + } + inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const { TRACE_APPLY (); @@ -805,6 +920,16 @@ struct Context } } + inline bool would_apply (hb_would_apply_context_t *c) const + { + switch (u.format) { + case 1: return u.format1.would_apply (c); + case 2: return u.format2.would_apply (c); + case 3: return u.format3.would_apply (c); + default:return false; + } + } + inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const { TRACE_APPLY (); @@ -876,6 +1001,24 @@ static inline void chain_context_closure_lookup (hb_closure_context_t *c, lookup_context.funcs.closure); } +static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c, + unsigned int backtrackCount, + const USHORT backtrack[], + unsigned int inputCount, /* Including the first glyph (not matched) */ + const USHORT input[], /* Array of input values--start with second glyph */ + unsigned int lookaheadCount, + const USHORT lookahead[], + unsigned int lookupCount, + const LookupRecord lookupRecord[], + ChainContextApplyLookupContext &lookup_context) +{ + return !backtrackCount + && !lookaheadCount + && would_match_input (c, + inputCount, input, + lookup_context.funcs.match, lookup_context.match_data[1]); +} + static inline bool chain_context_apply_lookup (hb_apply_context_t *c, unsigned int backtrackCount, const USHORT backtrack[], @@ -925,6 +1068,19 @@ struct ChainRule lookup_context); } + inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const + { + TRACE_WOULD_APPLY (); + const HeadlessArrayOf &input = StructAfter > (backtrack); + const ArrayOf &lookahead = StructAfter > (input); + const ArrayOf &lookup = StructAfter > (lookahead); + return TRACE_RETURN (chain_context_would_apply_lookup (c, + backtrack.len, backtrack.array, + input.len, input.array, + lookahead.len, lookahead.array, lookup.len, + lookup.array, lookup_context)); + } + inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const { TRACE_APPLY (); @@ -978,6 +1134,17 @@ struct ChainRuleSet (this+rule[i]).closure (c, lookup_context); } + inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const + { + TRACE_WOULD_APPLY (); + unsigned int num_rules = rule.len; + for (unsigned int i = 0; i < num_rules; i++) + if ((this+rule[i]).would_apply (c, lookup_context)) + return TRACE_RETURN (true); + + return TRACE_RETURN (false); + } + inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const { TRACE_APPLY (); @@ -1026,6 +1193,20 @@ struct ChainContextFormat1 } } + inline bool would_apply (hb_would_apply_context_t *c) const + { + TRACE_WOULD_APPLY (); + unsigned int index = (this+coverage) (c->first); + if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); + + const ChainRuleSet &rule_set = this+ruleSet[index]; + struct ChainContextApplyLookupContext lookup_context = { + {match_glyph, NULL}, + {NULL, NULL, NULL} + }; + return TRACE_RETURN (rule_set.would_apply (c, lookup_context)); + } + inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const { TRACE_APPLY (); @@ -1088,6 +1269,23 @@ struct ChainContextFormat2 } } + inline bool would_apply (hb_would_apply_context_t *c) const + { + TRACE_WOULD_APPLY (); + unsigned int index = (this+coverage) (c->first); + if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); + + const ClassDef &input_class_def = this+inputClassDef; + + index = input_class_def (c->first); + const ChainRuleSet &rule_set = this+ruleSet[index]; + struct ChainContextApplyLookupContext lookup_context = { + {match_class, NULL}, + {NULL, &input_class_def, NULL} + }; + return TRACE_RETURN (rule_set.would_apply (c, lookup_context)); + } + inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const { TRACE_APPLY (); @@ -1168,6 +1366,27 @@ struct ChainContextFormat3 lookup_context); } + inline bool would_apply (hb_would_apply_context_t *c) const + { + TRACE_WOULD_APPLY (); + const OffsetArrayOf &input = StructAfter > (backtrack); + + unsigned int index = (this+input[0]) (c->first); + if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); + + const OffsetArrayOf &lookahead = StructAfter > (input); + const ArrayOf &lookup = StructAfter > (lookahead); + struct ChainContextApplyLookupContext lookup_context = { + {match_coverage, NULL}, + {this, this, this} + }; + return TRACE_RETURN (chain_context_would_apply_lookup (c, + backtrack.len, (const USHORT *) backtrack.array, + input.len, (const USHORT *) input.array + 1, + lookahead.len, (const USHORT *) lookahead.array, + lookup.len, lookup.array, lookup_context)); + } + inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const { TRACE_APPLY (); @@ -1236,6 +1455,16 @@ struct ChainContext } } + inline bool would_apply (hb_would_apply_context_t *c) const + { + switch (u.format) { + case 1: return u.format1.would_apply (c); + case 2: return u.format2.would_apply (c); + case 3: return u.format3.would_apply (c); + default:return false; + } + } + inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const { TRACE_APPLY (); diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc index 10811d0b5..c6de75c89 100644 --- a/src/hb-ot-layout.cc +++ b/src/hb-ot-layout.cc @@ -458,6 +458,17 @@ hb_ot_layout_has_substitution (hb_face_t *face) return &_get_gsub (face) != &Null(GSUB); } +hb_bool_t +hb_ot_layout_would_substitute_lookup (hb_face_t *face, + const hb_codepoint_t *glyphs, + unsigned int glyphs_length, + unsigned int lookup_index) +{ + if (unlikely (glyphs_length < 1 || glyphs_length > 2)) return false; + hb_would_apply_context_t c (face, glyphs[0], glyphs_length == 2 ? glyphs[1] : -1); + return _get_gsub (face).would_substitute_lookup (&c, lookup_index); +} + void hb_ot_layout_substitute_start (hb_buffer_t *buffer) { diff --git a/src/hb-ot-layout.h b/src/hb-ot-layout.h index b8b5baf3b..cf178b761 100644 --- a/src/hb-ot-layout.h +++ b/src/hb-ot-layout.h @@ -168,6 +168,13 @@ hb_ot_layout_feature_get_lookup_indexes (hb_face_t *face, hb_bool_t hb_ot_layout_has_substitution (hb_face_t *face); +/* Supports length 1 or 2 right now. */ +hb_bool_t +hb_ot_layout_would_substitute_lookup (hb_face_t *face, + const hb_codepoint_t *glyphs, + unsigned int glyphs_length, + unsigned int lookup_index); + /* Should be called before all the substitute_lookup's are done. */ void hb_ot_layout_substitute_start (hb_buffer_t *buffer);