From 7c9cfa2b4002c18585a26134ab987ceb7ebc97a2 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sun, 2 Sep 2018 19:47:50 -0700 Subject: [PATCH] Add intersects() method to GSUB/GPOS lookups --- src/hb-ot-layout-common.hh | 77 +++++++-- src/hb-ot-layout-gpos-table.hh | 103 ++++++++--- src/hb-ot-layout-gsub-table.hh | 205 ++++++++++++++++------ src/hb-ot-layout-gsubgpos.hh | 306 ++++++++++++++++++++++++++------- 4 files changed, 528 insertions(+), 163 deletions(-) diff --git a/src/hb-ot-layout-common.hh b/src/hb-ot-layout-common.hh index da8669d96..de01bb415 100644 --- a/src/hb-ot-layout-common.hh +++ b/src/hb-ot-layout-common.hh @@ -168,9 +168,8 @@ struct RangeRecord return_trace (c->check_struct (this)); } - inline bool intersects (const hb_set_t *glyphs) const { - return glyphs->intersects (start, end); - } + inline bool intersects (const hb_set_t *glyphs) const + { return glyphs->intersects (start, end); } template inline bool add_coverage (set_t *glyphs) const { @@ -767,9 +766,17 @@ struct CoverageFormat1 return_trace (glyphArray.sanitize (c)); } - inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { - return glyphs->has (glyphArray[index]); + inline bool intersects (const hb_set_t *glyphs) const + { + /* TODO Speed up, using hb_set_next() and bsearch()? */ + unsigned int count = glyphArray.len; + for (unsigned int i = 0; i < count; i++) + if (glyphs->has (glyphArray[i])) + return true; + return false; } + inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const + { return glyphs->has (glyphArray[index]); } template inline bool add_coverage (set_t *glyphs) const { @@ -857,7 +864,17 @@ struct CoverageFormat2 return_trace (rangeRecord.sanitize (c)); } - inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { + inline bool intersects (const hb_set_t *glyphs) const + { + /* TODO Speed up, using hb_set_next() and bsearch()? */ + unsigned int count = rangeRecord.len; + for (unsigned int i = 0; i < count; i++) + if (rangeRecord[i].intersects (glyphs)) + return true; + return false; + } + inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const + { unsigned int i; unsigned int count = rangeRecord.len; for (i = 0; i < count; i++) { @@ -985,13 +1002,13 @@ struct Coverage inline bool intersects (const hb_set_t *glyphs) const { - /* TODO speed this up */ - for (hb_auto_t iter (*this); iter.more (); iter.next ()) - if (glyphs->has (iter.get_glyph ())) - return true; - return false; + switch (u.format) + { + case 1: return u.format1.intersects (glyphs); + case 2: return u.format2.intersects (glyphs); + default:return false; + } } - inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { switch (u.format) @@ -1141,6 +1158,17 @@ struct ClassDefFormat1 return true; } + inline bool intersects (const hb_set_t *glyphs) const + { + /* TODO Speed up, using hb_set_next()? */ + hb_codepoint_t start = startGlyph; + hb_codepoint_t end = startGlyph + classValue.len; + for (hb_codepoint_t iter = startGlyph - 1; + hb_set_next (glyphs, &iter) && iter < end;) + if (classValue[iter - start]) + return true; + return false; + } inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const { unsigned int count = classValue.len; if (klass == 0) @@ -1191,7 +1219,8 @@ struct ClassDefFormat2 } template - inline bool add_coverage (set_t *glyphs) const { + inline bool add_coverage (set_t *glyphs) const + { unsigned int count = rangeRecord.len; for (unsigned int i = 0; i < count; i++) if (rangeRecord[i].value) @@ -1201,7 +1230,8 @@ struct ClassDefFormat2 } template - inline bool add_class (set_t *glyphs, unsigned int klass) const { + inline bool add_class (set_t *glyphs, unsigned int klass) const + { unsigned int count = rangeRecord.len; for (unsigned int i = 0; i < count; i++) { @@ -1212,7 +1242,17 @@ struct ClassDefFormat2 return true; } - inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const { + inline bool intersects (const hb_set_t *glyphs) const + { + /* TODO Speed up, using hb_set_next() and bsearch()? */ + unsigned int count = rangeRecord.len; + for (unsigned int i = 0; i < count; i++) + if (rangeRecord[i].intersects (glyphs)) + return true; + return false; + } + inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const + { unsigned int count = rangeRecord.len; if (klass == 0) { @@ -1289,6 +1329,13 @@ struct ClassDef } } + inline bool intersects (const hb_set_t *glyphs) const { + switch (u.format) { + case 1: return u.format1.intersects (glyphs); + case 2: return u.format2.intersects (glyphs); + default:return false; + } + } inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const { switch (u.format) { case 1: return u.format1.intersects_class (glyphs, klass); diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh index 16b547939..641d16d8c 100644 --- a/src/hb-ot-layout-gpos-table.hh +++ b/src/hb-ot-layout-gpos-table.hh @@ -459,6 +459,9 @@ struct MarkArray : ArrayOf /* Array of MarkRecords--in Coverage orde struct SinglePosFormat1 { + inline bool intersects (const hb_set_t *glyphs) const + { return (this+coverage).intersects (glyphs); } + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const { TRACE_COLLECT_GLYPHS (this); @@ -466,9 +469,7 @@ struct SinglePosFormat1 } inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + { return this+coverage; } inline bool apply (hb_ot_apply_context_t *c) const { @@ -507,6 +508,9 @@ struct SinglePosFormat1 struct SinglePosFormat2 { + inline bool intersects (const hb_set_t *glyphs) const + { return (this+coverage).intersects (glyphs); } + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const { TRACE_COLLECT_GLYPHS (this); @@ -514,9 +518,7 @@ struct SinglePosFormat2 } inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + { return this+coverage; } inline bool apply (hb_ot_apply_context_t *c) const { @@ -598,6 +600,24 @@ struct PairSet { friend struct PairPosFormat1; + inline bool intersects (const hb_set_t *glyphs, + const ValueFormat *valueFormats) const + { + unsigned int len1 = valueFormats[0].get_len (); + unsigned int len2 = valueFormats[1].get_len (); + unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2); + + const PairValueRecord *record = CastP (arrayZ); + unsigned int count = len; + for (unsigned int i = 0; i < count; i++) + { + if (glyphs->has (record->secondGlyph)) + return true; + record = &StructAtOffset (record, record_size); + } + return false; + } + inline void collect_glyphs (hb_collect_glyphs_context_t *c, const ValueFormat *valueFormats) const { @@ -652,7 +672,8 @@ struct PairSet return_trace (false); } - struct sanitize_closure_t { + struct sanitize_closure_t + { const void *base; const ValueFormat *valueFormats; unsigned int len1; /* valueFormats[0].get_len() */ @@ -681,6 +702,20 @@ struct PairSet struct PairPosFormat1 { + inline bool intersects (const hb_set_t *glyphs) const + { + unsigned int count = pairSet.len; + for (hb_auto_t iter (this+coverage); iter.more (); iter.next ()) + { + if (unlikely (iter.get_coverage () >= count)) + break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ + if (glyphs->has (iter.get_glyph ()) && + (this+pairSet[iter.get_coverage ()]).intersects (glyphs, valueFormat)) + return true; + } + return false; + } + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const { TRACE_COLLECT_GLYPHS (this); @@ -691,9 +726,7 @@ struct PairPosFormat1 } inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + { return this+coverage; } inline bool apply (hb_ot_apply_context_t *c) const { @@ -717,7 +750,8 @@ struct PairPosFormat1 unsigned int len1 = valueFormat[0].get_len (); unsigned int len2 = valueFormat[1].get_len (); - PairSet::sanitize_closure_t closure = { + PairSet::sanitize_closure_t closure = + { this, valueFormat, len1, @@ -747,6 +781,12 @@ struct PairPosFormat1 struct PairPosFormat2 { + inline bool intersects (const hb_set_t *glyphs) const + { + return (this+coverage).intersects (glyphs) && + (this+classDef2).intersects (glyphs); + } + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const { TRACE_COLLECT_GLYPHS (this); @@ -755,9 +795,7 @@ struct PairPosFormat2 } inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + { return this+coverage; } inline bool apply (hb_ot_apply_context_t *c) const { @@ -889,6 +927,9 @@ reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direc struct CursivePosFormat1 { + inline bool intersects (const hb_set_t *glyphs) const + { return (this+coverage).intersects (glyphs); } + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const { TRACE_COLLECT_GLYPHS (this); @@ -896,9 +937,7 @@ struct CursivePosFormat1 } inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + { return this+coverage; } inline bool apply (hb_ot_apply_context_t *c) const { @@ -1047,6 +1086,10 @@ typedef AnchorMatrix BaseArray; /* base-major-- struct MarkBasePosFormat1 { + inline bool intersects (const hb_set_t *glyphs) const + { return (this+markCoverage).intersects (glyphs) && + (this+baseCoverage).intersects (glyphs); } + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const { TRACE_COLLECT_GLYPHS (this); @@ -1055,9 +1098,7 @@ struct MarkBasePosFormat1 } inline const Coverage &get_coverage (void) const - { - return this+markCoverage; - } + { return this+markCoverage; } inline bool apply (hb_ot_apply_context_t *c) const { @@ -1161,6 +1202,10 @@ typedef OffsetListOf LigatureArray; struct MarkLigPosFormat1 { + inline bool intersects (const hb_set_t *glyphs) const + { return (this+markCoverage).intersects (glyphs) && + (this+ligatureCoverage).intersects (glyphs); } + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const { TRACE_COLLECT_GLYPHS (this); @@ -1169,9 +1214,7 @@ struct MarkLigPosFormat1 } inline const Coverage &get_coverage (void) const - { - return this+markCoverage; - } + { return this+markCoverage; } inline bool apply (hb_ot_apply_context_t *c) const { @@ -1274,6 +1317,10 @@ typedef AnchorMatrix Mark2Array; /* mark2-major-- struct MarkMarkPosFormat1 { + inline bool intersects (const hb_set_t *glyphs) const + { return (this+mark1Coverage).intersects (glyphs) && + (this+mark2Coverage).intersects (glyphs); } + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const { TRACE_COLLECT_GLYPHS (this); @@ -1282,9 +1329,7 @@ struct MarkMarkPosFormat1 } inline const Coverage &get_coverage (void) const - { - return this+mark1Coverage; - } + { return this+mark1Coverage; } inline bool apply (hb_ot_apply_context_t *c) const { @@ -1467,6 +1512,12 @@ struct PosLookup : Lookup return_trace (dispatch (c)); } + inline bool intersects (const hb_set_t *glyphs) const + { + hb_intersects_context_t c (glyphs); + return dispatch (&c); + } + inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const { TRACE_COLLECT_GLYPHS (this); diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh index c108e165e..d6518b9c1 100644 --- a/src/hb-ot-layout-gsub-table.hh +++ b/src/hb-ot-layout-gsub-table.hh @@ -37,6 +37,9 @@ namespace OT { struct SingleSubstFormat1 { + inline bool intersects (const hb_set_t *glyphs) const + { return (this+coverage).intersects (glyphs); } + inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); @@ -64,9 +67,7 @@ struct SingleSubstFormat1 } inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + { return this+coverage; } inline bool would_apply (hb_would_apply_context_t *c) const { @@ -120,6 +121,9 @@ struct SingleSubstFormat1 struct SingleSubstFormat2 { + inline bool intersects (const hb_set_t *glyphs) const + { return (this+coverage).intersects (glyphs); } + inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); @@ -147,9 +151,7 @@ struct SingleSubstFormat2 } inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + { return this+coverage; } inline bool would_apply (hb_would_apply_context_t *c) const { @@ -160,14 +162,12 @@ struct SingleSubstFormat2 inline bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); - hb_codepoint_t glyph_id = c->buffer->cur().codepoint; - unsigned int index = (this+coverage).get_coverage (glyph_id); + unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); if (likely (index == NOT_COVERED)) return_trace (false); if (unlikely (index >= substitute.len)) return_trace (false); - glyph_id = substitute[index]; - c->replace_glyph (glyph_id); + c->replace_glyph (substitute[index]); return_trace (true); } @@ -325,6 +325,9 @@ struct Sequence struct MultipleSubstFormat1 { + inline bool intersects (const hb_set_t *glyphs) const + { return (this+coverage).intersects (glyphs); } + inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); @@ -344,13 +347,11 @@ struct MultipleSubstFormat1 if (unlikely (!(this+coverage).add_coverage (c->input))) return; unsigned int count = sequence.len; for (unsigned int i = 0; i < count; i++) - (this+sequence[i]).collect_glyphs (c); + (this+sequence[i]).collect_glyphs (c); } inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + { return this+coverage; } inline bool would_apply (hb_would_apply_context_t *c) const { @@ -440,12 +441,72 @@ struct MultipleSubst } u; }; +struct AlternateSet +{ + inline void closure (hb_closure_context_t *c) const + { + TRACE_CLOSURE (this); + unsigned int count = alternates.len; + for (unsigned int i = 0; i < count; i++) + c->out->add (alternates[i]); + } + + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + { + TRACE_COLLECT_GLYPHS (this); + c->output->add_array (alternates.arrayZ, alternates.len); + } + + inline bool apply (hb_ot_apply_context_t *c) const + { + TRACE_APPLY (this); + unsigned int count = alternates.len; + + if (unlikely (!count)) return_trace (false); + + hb_mask_t glyph_mask = c->buffer->cur().mask; + hb_mask_t lookup_mask = c->lookup_mask; + + /* Note: This breaks badly if two features enabled this lookup together. */ + unsigned int shift = hb_ctz (lookup_mask); + unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift); + + if (unlikely (alt_index > count || alt_index == 0)) return_trace (false); + + c->replace_glyph (alternates[alt_index - 1]); -typedef ArrayOf AlternateSet; /* Array of alternate GlyphIDs--in + return_trace (true); + } + + inline bool serialize (hb_serialize_context_t *c, + Supplier &glyphs, + unsigned int num_glyphs) + { + TRACE_SERIALIZE (this); + if (unlikely (!c->extend_min (*this))) return_trace (false); + if (unlikely (!alternates.serialize (c, glyphs, num_glyphs))) return_trace (false); + return_trace (true); + } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (alternates.sanitize (c)); + } + + protected: + ArrayOf + alternates; /* Array of alternate GlyphIDs--in * arbitrary order */ + public: + DEFINE_SIZE_ARRAY (2, alternates); +}; struct AlternateSubstFormat1 { + inline bool intersects (const hb_set_t *glyphs) const + { return (this+coverage).intersects (glyphs); } + inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); @@ -454,12 +515,8 @@ struct AlternateSubstFormat1 { if (unlikely (iter.get_coverage () >= count)) break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ - if (c->glyphs->has (iter.get_glyph ())) { - const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()]; - unsigned int count = alt_set.len; - for (unsigned int i = 0; i < count; i++) - c->out->add (alt_set[i]); - } + if (c->glyphs->has (iter.get_glyph ())) + (this+alternateSet[iter.get_coverage ()]).closure (c); } } @@ -472,15 +529,12 @@ struct AlternateSubstFormat1 { if (unlikely (iter.get_coverage () >= count)) break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ - const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()]; - c->output->add_array (alt_set.arrayZ, alt_set.len); + (this+alternateSet[iter.get_coverage ()]).collect_glyphs (c); } } inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + { return this+coverage; } inline bool would_apply (hb_would_apply_context_t *c) const { @@ -491,29 +545,11 @@ struct AlternateSubstFormat1 inline bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); - hb_codepoint_t glyph_id = c->buffer->cur().codepoint; - unsigned int index = (this+coverage).get_coverage (glyph_id); + unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); if (likely (index == NOT_COVERED)) return_trace (false); - const AlternateSet &alt_set = this+alternateSet[index]; - - if (unlikely (!alt_set.len)) return_trace (false); - - hb_mask_t glyph_mask = c->buffer->cur().mask; - hb_mask_t lookup_mask = c->lookup_mask; - - /* Note: This breaks badly if two features enabled this lookup together. */ - unsigned int shift = hb_ctz (lookup_mask); - unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift); - - if (unlikely (alt_index > alt_set.len || alt_index == 0)) return_trace (false); - - glyph_id = alt_set[alt_index - 1]; - - c->replace_glyph (glyph_id); - - return_trace (true); + return_trace ((this+alternateSet[index]).apply (c)); } inline bool serialize (hb_serialize_context_t *c, @@ -591,6 +627,15 @@ struct AlternateSubst struct Ligature { + inline bool intersects (const hb_set_t *glyphs) const + { + unsigned int count = component.len; + for (unsigned int i = 1; i < count; i++) + if (!glyphs->has (component[i])) + return false; + return true; + } + inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); @@ -694,6 +739,15 @@ struct Ligature struct LigatureSet { + inline bool intersects (const hb_set_t *glyphs) const + { + unsigned int num_ligs = ligature.len; + for (unsigned int i = 0; i < num_ligs; i++) + if ((this+ligature[i]).intersects (glyphs)) + return true; + return false; + } + inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); @@ -771,6 +825,20 @@ struct LigatureSet struct LigatureSubstFormat1 { + inline bool intersects (const hb_set_t *glyphs) const + { + unsigned int count = ligatureSet.len; + for (hb_auto_t iter (this+coverage); iter.more (); iter.next ()) + { + if (unlikely (iter.get_coverage () >= count)) + break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ + if (glyphs->has (iter.get_glyph ()) && + (this+ligatureSet[iter.get_coverage ()]).intersects (glyphs)) + return true; + } + return false; + } + inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); @@ -798,9 +866,7 @@ struct LigatureSubstFormat1 } inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + { return this+coverage; } inline bool would_apply (hb_would_apply_context_t *c) const { @@ -815,9 +881,8 @@ struct LigatureSubstFormat1 inline bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); - hb_codepoint_t glyph_id = c->buffer->cur().codepoint; - unsigned int index = (this+coverage).get_coverage (glyph_id); + unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); if (likely (index == NOT_COVERED)) return_trace (false); const LigatureSet &lig_set = this+ligatureSet[index]; @@ -923,6 +988,28 @@ struct ExtensionSubst : Extension struct ReverseChainSingleSubstFormat1 { + inline bool intersects (const hb_set_t *glyphs) const + { + if (!(this+coverage).intersects (glyphs)) + return false; + + const OffsetArrayOf &lookahead = StructAfter > (backtrack); + + unsigned int count; + + count = backtrack.len; + for (unsigned int i = 0; i < count; i++) + if (!(this+backtrack[i]).intersects (glyphs)) + return false; + + count = lookahead.len; + for (unsigned int i = 0; i < count; i++) + if (!(this+lookahead[i]).intersects (glyphs)) + return false; + + return true; + } + inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); @@ -973,9 +1060,7 @@ struct ReverseChainSingleSubstFormat1 } inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + { return this+coverage; } inline bool would_apply (hb_would_apply_context_t *c) const { @@ -1035,7 +1120,7 @@ struct ReverseChainSingleSubstFormat1 * beginning of table */ OffsetArrayOf backtrack; /* Array of coverage tables - * in backtracking sequence, in glyph + * in backtracking sequence, in glyph * sequence order */ OffsetArrayOf lookaheadX; /* Array of coverage tables @@ -1146,6 +1231,12 @@ struct SubstLookup : Lookup return_trace (dispatch (c)); } + inline bool intersects (const hb_set_t *glyphs) const + { + hb_intersects_context_t c (glyphs); + return dispatch (&c); + } + inline hb_closure_context_t::return_t closure (hb_closure_context_t *c, unsigned int this_index) const { TRACE_CLOSURE (this); @@ -1311,11 +1402,11 @@ struct GSUB : GSUBGPOS inline bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - struct GSUB *out = c->serializer->start_embed (); + //struct GSUB *out = c->serializer->start_embed (); if (unlikely (!GSUBGPOS::subset (c))) return_trace (false); /* TODO Replace following with c->iter_copy_and_subset()ish. */ unsigned int count = get_lookup_count (); - LookupList &outLookupList = out+out->lookupList; + //LookupList &outLookupList = out+out->lookupList; for (unsigned int i = 0; i < count; i++) //XXX if (unlikely (!outLookupList.arrayZ[i].subset (c, get_lookup (i), &outLookupList))) return_trace (false); diff --git a/src/hb-ot-layout-gsubgpos.hh b/src/hb-ot-layout-gsubgpos.hh index 5bdbf9a56..e4399aea5 100644 --- a/src/hb-ot-layout-gsubgpos.hh +++ b/src/hb-ot-layout-gsubgpos.hh @@ -40,6 +40,23 @@ namespace OT { +struct hb_intersects_context_t : + hb_dispatch_context_t +{ + inline const char *get_name (void) { return "INTERSECTS"; } + template + inline return_t dispatch (const T &obj) { return obj.intersects (this->glyphs); } + static return_t default_return_value (void) { return false; } + bool stop_sublookup_iteration (return_t r) const { return r; } + + const hb_set_t *glyphs; + unsigned int debug_depth; + + hb_intersects_context_t (const hb_set_t *glyphs_) : + glyphs (glyphs_), + debug_depth (0) {} +}; + struct hb_closure_context_t : hb_dispatch_context_t { @@ -49,15 +66,14 @@ struct hb_closure_context_t : inline return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; } static return_t default_return_value (void) { return HB_VOID; } bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; } - return_t recurse (unsigned int lookup_index) + void recurse (unsigned int lookup_index) { if (unlikely (nesting_level_left == 0 || !recurse_func)) - return default_return_value (); + return; nesting_level_left--; recurse_func (this, lookup_index); nesting_level_left++; - return HB_VOID; } bool should_visit_lookup (unsigned int lookup_index) @@ -146,10 +162,10 @@ struct hb_collect_glyphs_context_t : inline return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; } static return_t default_return_value (void) { return HB_VOID; } bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; } - return_t recurse (unsigned int lookup_index) + void recurse (unsigned int lookup_index) { if (unlikely (nesting_level_left == 0 || !recurse_func)) - return default_return_value (); + return; /* Note that GPOS sets recurse_func to nullptr already, so it doesn't get * past the previous check. For GSUB, we only want to collect the output @@ -162,11 +178,11 @@ struct hb_collect_glyphs_context_t : */ if (output == hb_set_get_empty ()) - return HB_VOID; + return; /* Return if new lookup was recursed to before. */ if (recursed_lookups->has (lookup_index)) - return HB_VOID; + return; hb_set_t *old_before = before; hb_set_t *old_input = input; @@ -183,7 +199,7 @@ struct hb_collect_glyphs_context_t : recursed_lookups->add (lookup_index); - return HB_VOID; + return; } hb_face_t *face; @@ -208,24 +224,16 @@ struct hb_collect_glyphs_context_t : after (glyphs_after ? glyphs_after : hb_set_get_empty ()), output (glyphs_output ? glyphs_output : hb_set_get_empty ()), recurse_func (nullptr), - recursed_lookups (nullptr), + recursed_lookups (hb_set_create ()), nesting_level_left (nesting_level_left_), - debug_depth (0) - { - recursed_lookups = hb_set_create (); - } - ~hb_collect_glyphs_context_t (void) - { - hb_set_destroy (recursed_lookups); - } + debug_depth (0) {} + ~hb_collect_glyphs_context_t (void) { hb_set_destroy (recursed_lookups); } void set_recurse_func (recurse_func_t func) { recurse_func = func; } }; -/* XXX Can we remove this? */ - template struct hb_add_coverage_context_t : hb_dispatch_context_t, const Coverage &, HB_DEBUG_GET_COVERAGE> @@ -599,7 +607,7 @@ struct hb_ot_apply_context_t : -typedef bool (*intersects_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data); +typedef bool (*intersects_func_t) (const hb_set_t *glyphs, const HBUINT16 &value, const void *data); typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data); typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data); @@ -617,29 +625,29 @@ struct ContextApplyFuncs }; -static inline bool intersects_glyph (hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED) +static inline bool intersects_glyph (const hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED) { return glyphs->has (value); } -static inline bool intersects_class (hb_set_t *glyphs, const HBUINT16 &value, const void *data) +static inline bool intersects_class (const hb_set_t *glyphs, const HBUINT16 &value, const void *data) { const ClassDef &class_def = *reinterpret_cast(data); return class_def.intersects_class (glyphs, value); } -static inline bool intersects_coverage (hb_set_t *glyphs, const HBUINT16 &value, const void *data) +static inline bool intersects_coverage (const hb_set_t *glyphs, const HBUINT16 &value, const void *data) { const OffsetTo &coverage = (const OffsetTo&)value; return (data+coverage).intersects (glyphs); } -static inline bool intersects_array (hb_closure_context_t *c, +static inline bool intersects_array (const hb_set_t *glyphs, unsigned int count, const HBUINT16 values[], intersects_func_t intersects_func, const void *intersects_data) { for (unsigned int i = 0; i < count; i++) - if (likely (!intersects_func (c->glyphs, values[i], intersects_data))) + if (likely (!intersects_func (glyphs, values[i], intersects_data))) return false; return true; } @@ -1140,6 +1148,16 @@ struct ContextApplyLookupContext const void *match_data; }; +static inline bool context_intersects (const hb_set_t *glyphs, + unsigned int inputCount, /* Including the first glyph (not matched) */ + const HBUINT16 input[], /* Array of input values--start with second glyph */ + ContextClosureLookupContext &lookup_context) +{ + return intersects_array (glyphs, + inputCount ? inputCount - 1 : 0, input, + lookup_context.funcs.intersects, lookup_context.intersects_data); +} + static inline void context_closure_lookup (hb_closure_context_t *c, unsigned int inputCount, /* Including the first glyph (not matched) */ const HBUINT16 input[], /* Array of input values--start with second glyph */ @@ -1147,9 +1165,9 @@ static inline void context_closure_lookup (hb_closure_context_t *c, const LookupRecord lookupRecord[], ContextClosureLookupContext &lookup_context) { - if (intersects_array (c, - inputCount ? inputCount - 1 : 0, input, - lookup_context.funcs.intersects, lookup_context.intersects_data)) + if (context_intersects (c->glyphs, + inputCount, input, + lookup_context)) recurse_lookups (c, lookupCount, lookupRecord); } @@ -1201,6 +1219,13 @@ static inline bool context_apply_lookup (hb_ot_apply_context_t *c, struct Rule { + inline bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const + { + return context_intersects (glyphs, + inputCount, inputZ, + lookup_context); + } + inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const { TRACE_CLOSURE (this); @@ -1261,6 +1286,15 @@ struct Rule struct RuleSet { + inline bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const + { + unsigned int num_rules = rule.len; + for (unsigned int i = 0; i < num_rules; i++) + if ((this+rule[i]).intersects (glyphs, lookup_context)) + return true; + return false; + } + inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const { TRACE_CLOSURE (this); @@ -1318,23 +1352,42 @@ struct RuleSet struct ContextFormat1 { + inline bool intersects (const hb_set_t *glyphs) const + { + struct ContextClosureLookupContext lookup_context = { + {intersects_glyph}, + nullptr + }; + + unsigned int count = ruleSet.len; + for (hb_auto_t iter (this+coverage); iter.more (); iter.next ()) + { + if (unlikely (iter.get_coverage () >= count)) + break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ + if (glyphs->has (iter.get_glyph ()) && + (this+ruleSet[iter.get_coverage ()]).intersects (glyphs, lookup_context)) + return true; + } + return false; + } + inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); - const Coverage &cov = (this+coverage); - struct ContextClosureLookupContext lookup_context = { {intersects_glyph}, nullptr }; unsigned int count = ruleSet.len; - for (unsigned int i = 0; i < count; i++) - if (cov.intersects_coverage (c->glyphs, i)) { - const RuleSet &rule_set = this+ruleSet[i]; - rule_set.closure (c, lookup_context); - } + for (hb_auto_t iter (this+coverage); iter.more (); iter.next ()) + { + if (unlikely (iter.get_coverage () >= count)) + break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ + if (c->glyphs->has (iter.get_glyph ())) + (this+ruleSet[iter.get_coverage ()]).closure (c, lookup_context); + } } inline void collect_glyphs (hb_collect_glyphs_context_t *c) const @@ -1365,9 +1418,7 @@ struct ContextFormat1 } inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + { return this+coverage; } inline bool apply (hb_ot_apply_context_t *c) const { @@ -1405,6 +1456,27 @@ struct ContextFormat1 struct ContextFormat2 { + inline bool intersects (const hb_set_t *glyphs) const + { + if (!(this+coverage).intersects (glyphs)) + return false; + + const ClassDef &class_def = this+classDef; + + struct ContextClosureLookupContext lookup_context = { + {intersects_class}, + &class_def + }; + + unsigned int count = ruleSet.len; + for (unsigned int i = 0; i < count; i++) + if (class_def.intersects_class (glyphs, i) && + (this+ruleSet[i]).intersects (glyphs, lookup_context)) + return true; + + return false; + } + inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); @@ -1457,9 +1529,7 @@ struct ContextFormat2 } inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + { return this+coverage; } inline bool apply (hb_ot_apply_context_t *c) const { @@ -1501,6 +1571,20 @@ struct ContextFormat2 struct ContextFormat3 { + inline bool intersects (const hb_set_t *glyphs) const + { + if (!(this+coverageZ[0]).intersects (glyphs)) + return false; + + struct ContextClosureLookupContext lookup_context = { + {intersects_coverage}, + this + }; + return context_intersects (glyphs, + glyphCount, (const HBUINT16 *) (coverageZ + 1), + lookup_context); + } + inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); @@ -1548,9 +1632,7 @@ struct ContextFormat3 } inline const Coverage &get_coverage (void) const - { - return this+coverageZ[0]; - } + { return this+coverageZ[0]; } inline bool apply (hb_ot_apply_context_t *c) const { @@ -1638,6 +1720,26 @@ struct ChainContextApplyLookupContext const void *match_data[3]; }; +static inline bool chain_context_intersects (const hb_set_t *glyphs, + unsigned int backtrackCount, + const HBUINT16 backtrack[], + unsigned int inputCount, /* Including the first glyph (not matched) */ + const HBUINT16 input[], /* Array of input values--start with second glyph */ + unsigned int lookaheadCount, + const HBUINT16 lookahead[], + ChainContextClosureLookupContext &lookup_context) +{ + return intersects_array (glyphs, + backtrackCount, backtrack, + lookup_context.funcs.intersects, lookup_context.intersects_data[0]) + && intersects_array (glyphs, + inputCount ? inputCount - 1 : 0, input, + lookup_context.funcs.intersects, lookup_context.intersects_data[1]) + && intersects_array (glyphs, + lookaheadCount, lookahead, + lookup_context.funcs.intersects, lookup_context.intersects_data[2]); +} + static inline void chain_context_closure_lookup (hb_closure_context_t *c, unsigned int backtrackCount, const HBUINT16 backtrack[], @@ -1649,15 +1751,11 @@ static inline void chain_context_closure_lookup (hb_closure_context_t *c, const LookupRecord lookupRecord[], ChainContextClosureLookupContext &lookup_context) { - if (intersects_array (c, - backtrackCount, backtrack, - lookup_context.funcs.intersects, lookup_context.intersects_data[0]) - && intersects_array (c, - inputCount ? inputCount - 1 : 0, input, - lookup_context.funcs.intersects, lookup_context.intersects_data[1]) - && intersects_array (c, - lookaheadCount, lookahead, - lookup_context.funcs.intersects, lookup_context.intersects_data[2])) + if (chain_context_intersects (c->glyphs, + backtrackCount, backtrack, + inputCount, input, + lookaheadCount, lookahead, + lookup_context)) recurse_lookups (c, lookupCount, lookupRecord); } @@ -1737,6 +1835,17 @@ static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c, struct ChainRule { + inline bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const + { + const HeadlessArrayOf &input = StructAfter > (backtrack); + const ArrayOf &lookahead = StructAfter > (input); + return chain_context_intersects (glyphs, + backtrack.len, backtrack.arrayZ, + input.len, input.arrayZ, + lookahead.len, lookahead.arrayZ, + lookup_context); + } + inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const { TRACE_CLOSURE (this); @@ -1823,6 +1932,14 @@ struct ChainRule struct ChainRuleSet { + inline bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const + { + unsigned int num_rules = rule.len; + for (unsigned int i = 0; i < num_rules; i++) + if ((this+rule[i]).intersects (glyphs, lookup_context)) + return true; + return false; + } inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const { TRACE_CLOSURE (this); @@ -1877,10 +1994,28 @@ struct ChainRuleSet struct ChainContextFormat1 { + inline bool intersects (const hb_set_t *glyphs) const + { + struct ChainContextClosureLookupContext lookup_context = { + {intersects_glyph}, + {nullptr, nullptr, nullptr} + }; + + unsigned int count = ruleSet.len; + for (hb_auto_t iter (this+coverage); iter.more (); iter.next ()) + { + if (unlikely (iter.get_coverage () >= count)) + break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ + if (glyphs->has (iter.get_glyph ()) && + (this+ruleSet[iter.get_coverage ()]).intersects (glyphs, lookup_context)) + return true; + } + return false; + } + inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); - const Coverage &cov = (this+coverage); struct ChainContextClosureLookupContext lookup_context = { {intersects_glyph}, @@ -1888,11 +2023,13 @@ struct ChainContextFormat1 }; unsigned int count = ruleSet.len; - for (unsigned int i = 0; i < count; i++) - if (cov.intersects_coverage (c->glyphs, i)) { - const ChainRuleSet &rule_set = this+ruleSet[i]; - rule_set.closure (c, lookup_context); - } + for (hb_auto_t iter (this+coverage); iter.more (); iter.next ()) + { + if (unlikely (iter.get_coverage () >= count)) + break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ + if (c->glyphs->has (iter.get_glyph ())) + (this+ruleSet[iter.get_coverage ()]).closure (c, lookup_context); + } } inline void collect_glyphs (hb_collect_glyphs_context_t *c) const @@ -1923,9 +2060,7 @@ struct ChainContextFormat1 } inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + { return this+coverage; } inline bool apply (hb_ot_apply_context_t *c) const { @@ -1961,6 +2096,30 @@ struct ChainContextFormat1 struct ChainContextFormat2 { + inline bool intersects (const hb_set_t *glyphs) const + { + if (!(this+coverage).intersects (glyphs)) + return false; + + const ClassDef &backtrack_class_def = this+backtrackClassDef; + const ClassDef &input_class_def = this+inputClassDef; + const ClassDef &lookahead_class_def = this+lookaheadClassDef; + + struct ChainContextClosureLookupContext lookup_context = { + {intersects_class}, + {&backtrack_class_def, + &input_class_def, + &lookahead_class_def} + }; + + unsigned int count = ruleSet.len; + for (unsigned int i = 0; i < count; i++) + if (input_class_def.intersects_class (glyphs, i) && + (this+ruleSet[i]).intersects (glyphs, lookup_context)) + return true; + + return false; + } inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); @@ -2027,9 +2186,7 @@ struct ChainContextFormat2 } inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + { return this+coverage; } inline bool apply (hb_ot_apply_context_t *c) const { @@ -2088,6 +2245,25 @@ struct ChainContextFormat2 struct ChainContextFormat3 { + inline bool intersects (const hb_set_t *glyphs) const + { + const OffsetArrayOf &input = StructAfter > (backtrack); + + if (!(this+input[0]).intersects (glyphs)) + return false; + + const OffsetArrayOf &lookahead = StructAfter > (input); + struct ChainContextClosureLookupContext lookup_context = { + {intersects_coverage}, + {this, this, this} + }; + return chain_context_intersects (glyphs, + backtrack.len, (const HBUINT16 *) backtrack.arrayZ, + input.len, (const HBUINT16 *) input.arrayZ + 1, + lookahead.len, (const HBUINT16 *) lookahead.arrayZ, + lookup_context); + } + inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this);