Add intersects() method to GSUB/GPOS lookups

This commit is contained in:
Behdad Esfahbod 2018-09-02 19:47:50 -07:00
parent 61ce62e554
commit 7c9cfa2b40
4 changed files with 528 additions and 163 deletions

View File

@ -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 <typename set_t>
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 <typename set_t>
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<Coverage::Iter> 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 <typename set_t>
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 <typename set_t>
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);

View File

@ -459,6 +459,9 @@ struct MarkArray : ArrayOf<MarkRecord> /* 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<PairValueRecord> (arrayZ);
unsigned int count = len;
for (unsigned int i = 0; i < count; i++)
{
if (glyphs->has (record->secondGlyph))
return true;
record = &StructAtOffset<const PairValueRecord> (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<Coverage::Iter> 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<LigatureAttach> 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);

View File

@ -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);
@ -348,9 +351,7 @@ struct MultipleSubstFormat1
}
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]);
}
typedef ArrayOf<GlyphID> AlternateSet; /* Array of alternate GlyphIDs--in
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]);
return_trace (true);
}
inline bool serialize (hb_serialize_context_t *c,
Supplier<GlyphID> &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<GlyphID>
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<Coverage::Iter> 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<ExtensionSubst>
struct ReverseChainSingleSubstFormat1
{
inline bool intersects (const hb_set_t *glyphs) const
{
if (!(this+coverage).intersects (glyphs))
return false;
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (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
{
@ -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<GSUB> ();
//struct GSUB *out = c->serializer->start_embed<GSUB> ();
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);

View File

@ -40,6 +40,23 @@
namespace OT {
struct hb_intersects_context_t :
hb_dispatch_context_t<hb_intersects_context_t, bool, 0>
{
inline const char *get_name (void) { return "INTERSECTS"; }
template <typename T>
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<hb_closure_context_t, hb_void_t, HB_DEBUG_CLOSURE>
{
@ -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 <typename set_t>
struct hb_add_coverage_context_t :
hb_dispatch_context_t<hb_add_coverage_context_t<set_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<const ClassDef *>(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> &coverage = (const OffsetTo<Coverage>&)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,22 +1352,41 @@ 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<Coverage::Iter> 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<Coverage::Iter> 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);
}
}
@ -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,
if (chain_context_intersects (c->glyphs,
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,
inputCount, input,
lookaheadCount, lookahead,
lookup_context.funcs.intersects, lookup_context.intersects_data[2]))
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<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (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<Coverage::Iter> 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,10 +2023,12 @@ 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<Coverage::Iter> 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);
}
}
@ -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<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
if (!(this+input[0]).intersects (glyphs))
return false;
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (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);