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)); return_trace (c->check_struct (this));
} }
inline bool intersects (const hb_set_t *glyphs) const { inline bool intersects (const hb_set_t *glyphs) const
return glyphs->intersects (start, end); { return glyphs->intersects (start, end); }
}
template <typename set_t> template <typename set_t>
inline bool add_coverage (set_t *glyphs) const { inline bool add_coverage (set_t *glyphs) const {
@ -767,9 +766,17 @@ struct CoverageFormat1
return_trace (glyphArray.sanitize (c)); return_trace (glyphArray.sanitize (c));
} }
inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { inline bool intersects (const hb_set_t *glyphs) const
return glyphs->has (glyphArray[index]); {
/* 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> template <typename set_t>
inline bool add_coverage (set_t *glyphs) const { inline bool add_coverage (set_t *glyphs) const {
@ -857,7 +864,17 @@ struct CoverageFormat2
return_trace (rangeRecord.sanitize (c)); 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 i;
unsigned int count = rangeRecord.len; unsigned int count = rangeRecord.len;
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
@ -985,13 +1002,13 @@ struct Coverage
inline bool intersects (const hb_set_t *glyphs) const inline bool intersects (const hb_set_t *glyphs) const
{ {
/* TODO speed this up */ switch (u.format)
for (hb_auto_t<Coverage::Iter> iter (*this); iter.more (); iter.next ()) {
if (glyphs->has (iter.get_glyph ())) case 1: return u.format1.intersects (glyphs);
return true; case 2: return u.format2.intersects (glyphs);
return false; default:return false;
}
} }
inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
{ {
switch (u.format) switch (u.format)
@ -1141,6 +1158,17 @@ struct ClassDefFormat1
return true; 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 { inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
unsigned int count = classValue.len; unsigned int count = classValue.len;
if (klass == 0) if (klass == 0)
@ -1191,7 +1219,8 @@ struct ClassDefFormat2
} }
template <typename set_t> 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; unsigned int count = rangeRecord.len;
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
if (rangeRecord[i].value) if (rangeRecord[i].value)
@ -1201,7 +1230,8 @@ struct ClassDefFormat2
} }
template <typename set_t> 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; unsigned int count = rangeRecord.len;
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
{ {
@ -1212,7 +1242,17 @@ struct ClassDefFormat2
return true; 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; unsigned int count = rangeRecord.len;
if (klass == 0) 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 { inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
switch (u.format) { switch (u.format) {
case 1: return u.format1.intersects_class (glyphs, klass); 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 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 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
{ {
TRACE_COLLECT_GLYPHS (this); TRACE_COLLECT_GLYPHS (this);
@ -466,9 +469,7 @@ struct SinglePosFormat1
} }
inline const Coverage &get_coverage (void) const inline const Coverage &get_coverage (void) const
{ { return this+coverage; }
return this+coverage;
}
inline bool apply (hb_ot_apply_context_t *c) const inline bool apply (hb_ot_apply_context_t *c) const
{ {
@ -507,6 +508,9 @@ struct SinglePosFormat1
struct SinglePosFormat2 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 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
{ {
TRACE_COLLECT_GLYPHS (this); TRACE_COLLECT_GLYPHS (this);
@ -514,9 +518,7 @@ struct SinglePosFormat2
} }
inline const Coverage &get_coverage (void) const inline const Coverage &get_coverage (void) const
{ { return this+coverage; }
return this+coverage;
}
inline bool apply (hb_ot_apply_context_t *c) const inline bool apply (hb_ot_apply_context_t *c) const
{ {
@ -598,6 +600,24 @@ struct PairSet
{ {
friend struct PairPosFormat1; 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, inline void collect_glyphs (hb_collect_glyphs_context_t *c,
const ValueFormat *valueFormats) const const ValueFormat *valueFormats) const
{ {
@ -652,7 +672,8 @@ struct PairSet
return_trace (false); return_trace (false);
} }
struct sanitize_closure_t { struct sanitize_closure_t
{
const void *base; const void *base;
const ValueFormat *valueFormats; const ValueFormat *valueFormats;
unsigned int len1; /* valueFormats[0].get_len() */ unsigned int len1; /* valueFormats[0].get_len() */
@ -681,6 +702,20 @@ struct PairSet
struct PairPosFormat1 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 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
{ {
TRACE_COLLECT_GLYPHS (this); TRACE_COLLECT_GLYPHS (this);
@ -691,9 +726,7 @@ struct PairPosFormat1
} }
inline const Coverage &get_coverage (void) const inline const Coverage &get_coverage (void) const
{ { return this+coverage; }
return this+coverage;
}
inline bool apply (hb_ot_apply_context_t *c) const 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 len1 = valueFormat[0].get_len ();
unsigned int len2 = valueFormat[1].get_len (); unsigned int len2 = valueFormat[1].get_len ();
PairSet::sanitize_closure_t closure = { PairSet::sanitize_closure_t closure =
{
this, this,
valueFormat, valueFormat,
len1, len1,
@ -747,6 +781,12 @@ struct PairPosFormat1
struct PairPosFormat2 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 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
{ {
TRACE_COLLECT_GLYPHS (this); TRACE_COLLECT_GLYPHS (this);
@ -755,9 +795,7 @@ struct PairPosFormat2
} }
inline const Coverage &get_coverage (void) const inline const Coverage &get_coverage (void) const
{ { return this+coverage; }
return this+coverage;
}
inline bool apply (hb_ot_apply_context_t *c) const 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 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 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
{ {
TRACE_COLLECT_GLYPHS (this); TRACE_COLLECT_GLYPHS (this);
@ -896,9 +937,7 @@ struct CursivePosFormat1
} }
inline const Coverage &get_coverage (void) const inline const Coverage &get_coverage (void) const
{ { return this+coverage; }
return this+coverage;
}
inline bool apply (hb_ot_apply_context_t *c) const inline bool apply (hb_ot_apply_context_t *c) const
{ {
@ -1047,6 +1086,10 @@ typedef AnchorMatrix BaseArray; /* base-major--
struct MarkBasePosFormat1 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 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
{ {
TRACE_COLLECT_GLYPHS (this); TRACE_COLLECT_GLYPHS (this);
@ -1055,9 +1098,7 @@ struct MarkBasePosFormat1
} }
inline const Coverage &get_coverage (void) const inline const Coverage &get_coverage (void) const
{ { return this+markCoverage; }
return this+markCoverage;
}
inline bool apply (hb_ot_apply_context_t *c) const inline bool apply (hb_ot_apply_context_t *c) const
{ {
@ -1161,6 +1202,10 @@ typedef OffsetListOf<LigatureAttach> LigatureArray;
struct MarkLigPosFormat1 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 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
{ {
TRACE_COLLECT_GLYPHS (this); TRACE_COLLECT_GLYPHS (this);
@ -1169,9 +1214,7 @@ struct MarkLigPosFormat1
} }
inline const Coverage &get_coverage (void) const inline const Coverage &get_coverage (void) const
{ { return this+markCoverage; }
return this+markCoverage;
}
inline bool apply (hb_ot_apply_context_t *c) const inline bool apply (hb_ot_apply_context_t *c) const
{ {
@ -1274,6 +1317,10 @@ typedef AnchorMatrix Mark2Array; /* mark2-major--
struct MarkMarkPosFormat1 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 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
{ {
TRACE_COLLECT_GLYPHS (this); TRACE_COLLECT_GLYPHS (this);
@ -1282,9 +1329,7 @@ struct MarkMarkPosFormat1
} }
inline const Coverage &get_coverage (void) const inline const Coverage &get_coverage (void) const
{ { return this+mark1Coverage; }
return this+mark1Coverage;
}
inline bool apply (hb_ot_apply_context_t *c) const inline bool apply (hb_ot_apply_context_t *c) const
{ {
@ -1467,6 +1512,12 @@ struct PosLookup : Lookup
return_trace (dispatch (c)); 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 inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
{ {
TRACE_COLLECT_GLYPHS (this); TRACE_COLLECT_GLYPHS (this);

View File

@ -37,6 +37,9 @@ namespace OT {
struct SingleSubstFormat1 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 inline void closure (hb_closure_context_t *c) const
{ {
TRACE_CLOSURE (this); TRACE_CLOSURE (this);
@ -64,9 +67,7 @@ struct SingleSubstFormat1
} }
inline const Coverage &get_coverage (void) const inline const Coverage &get_coverage (void) const
{ { return this+coverage; }
return this+coverage;
}
inline bool would_apply (hb_would_apply_context_t *c) const inline bool would_apply (hb_would_apply_context_t *c) const
{ {
@ -120,6 +121,9 @@ struct SingleSubstFormat1
struct SingleSubstFormat2 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 inline void closure (hb_closure_context_t *c) const
{ {
TRACE_CLOSURE (this); TRACE_CLOSURE (this);
@ -147,9 +151,7 @@ struct SingleSubstFormat2
} }
inline const Coverage &get_coverage (void) const inline const Coverage &get_coverage (void) const
{ { return this+coverage; }
return this+coverage;
}
inline bool would_apply (hb_would_apply_context_t *c) const 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 inline bool apply (hb_ot_apply_context_t *c) const
{ {
TRACE_APPLY (this); TRACE_APPLY (this);
hb_codepoint_t glyph_id = c->buffer->cur().codepoint; unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
unsigned int index = (this+coverage).get_coverage (glyph_id);
if (likely (index == NOT_COVERED)) return_trace (false); if (likely (index == NOT_COVERED)) return_trace (false);
if (unlikely (index >= substitute.len)) return_trace (false); if (unlikely (index >= substitute.len)) return_trace (false);
glyph_id = substitute[index]; c->replace_glyph (substitute[index]);
c->replace_glyph (glyph_id);
return_trace (true); return_trace (true);
} }
@ -325,6 +325,9 @@ struct Sequence
struct MultipleSubstFormat1 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 inline void closure (hb_closure_context_t *c) const
{ {
TRACE_CLOSURE (this); TRACE_CLOSURE (this);
@ -344,13 +347,11 @@ struct MultipleSubstFormat1
if (unlikely (!(this+coverage).add_coverage (c->input))) return; if (unlikely (!(this+coverage).add_coverage (c->input))) return;
unsigned int count = sequence.len; unsigned int count = sequence.len;
for (unsigned int i = 0; i < count; i++) 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 inline const Coverage &get_coverage (void) const
{ { return this+coverage; }
return this+coverage;
}
inline bool would_apply (hb_would_apply_context_t *c) const inline bool would_apply (hb_would_apply_context_t *c) const
{ {
@ -440,12 +441,72 @@ struct MultipleSubst
} u; } 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 */ * arbitrary order */
public:
DEFINE_SIZE_ARRAY (2, alternates);
};
struct AlternateSubstFormat1 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 inline void closure (hb_closure_context_t *c) const
{ {
TRACE_CLOSURE (this); TRACE_CLOSURE (this);
@ -454,12 +515,8 @@ struct AlternateSubstFormat1
{ {
if (unlikely (iter.get_coverage () >= count)) if (unlikely (iter.get_coverage () >= count))
break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
if (c->glyphs->has (iter.get_glyph ())) { if (c->glyphs->has (iter.get_glyph ()))
const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()]; (this+alternateSet[iter.get_coverage ()]).closure (c);
unsigned int count = alt_set.len;
for (unsigned int i = 0; i < count; i++)
c->out->add (alt_set[i]);
}
} }
} }
@ -472,15 +529,12 @@ struct AlternateSubstFormat1
{ {
if (unlikely (iter.get_coverage () >= count)) if (unlikely (iter.get_coverage () >= count))
break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()]; (this+alternateSet[iter.get_coverage ()]).collect_glyphs (c);
c->output->add_array (alt_set.arrayZ, alt_set.len);
} }
} }
inline const Coverage &get_coverage (void) const inline const Coverage &get_coverage (void) const
{ { return this+coverage; }
return this+coverage;
}
inline bool would_apply (hb_would_apply_context_t *c) const 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 inline bool apply (hb_ot_apply_context_t *c) const
{ {
TRACE_APPLY (this); 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 (likely (index == NOT_COVERED)) return_trace (false);
const AlternateSet &alt_set = this+alternateSet[index]; return_trace ((this+alternateSet[index]).apply (c));
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);
} }
inline bool serialize (hb_serialize_context_t *c, inline bool serialize (hb_serialize_context_t *c,
@ -591,6 +627,15 @@ struct AlternateSubst
struct Ligature 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 inline void closure (hb_closure_context_t *c) const
{ {
TRACE_CLOSURE (this); TRACE_CLOSURE (this);
@ -694,6 +739,15 @@ struct Ligature
struct LigatureSet 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 inline void closure (hb_closure_context_t *c) const
{ {
TRACE_CLOSURE (this); TRACE_CLOSURE (this);
@ -771,6 +825,20 @@ struct LigatureSet
struct LigatureSubstFormat1 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 inline void closure (hb_closure_context_t *c) const
{ {
TRACE_CLOSURE (this); TRACE_CLOSURE (this);
@ -798,9 +866,7 @@ struct LigatureSubstFormat1
} }
inline const Coverage &get_coverage (void) const inline const Coverage &get_coverage (void) const
{ { return this+coverage; }
return this+coverage;
}
inline bool would_apply (hb_would_apply_context_t *c) const 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 inline bool apply (hb_ot_apply_context_t *c) const
{ {
TRACE_APPLY (this); 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 (likely (index == NOT_COVERED)) return_trace (false);
const LigatureSet &lig_set = this+ligatureSet[index]; const LigatureSet &lig_set = this+ligatureSet[index];
@ -923,6 +988,28 @@ struct ExtensionSubst : Extension<ExtensionSubst>
struct ReverseChainSingleSubstFormat1 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 inline void closure (hb_closure_context_t *c) const
{ {
TRACE_CLOSURE (this); TRACE_CLOSURE (this);
@ -973,9 +1060,7 @@ struct ReverseChainSingleSubstFormat1
} }
inline const Coverage &get_coverage (void) const inline const Coverage &get_coverage (void) const
{ { return this+coverage; }
return this+coverage;
}
inline bool would_apply (hb_would_apply_context_t *c) const inline bool would_apply (hb_would_apply_context_t *c) const
{ {
@ -1035,7 +1120,7 @@ struct ReverseChainSingleSubstFormat1
* beginning of table */ * beginning of table */
OffsetArrayOf<Coverage> OffsetArrayOf<Coverage>
backtrack; /* Array of coverage tables backtrack; /* Array of coverage tables
* in backtracking sequence, in glyph * in backtracking sequence, in glyph
* sequence order */ * sequence order */
OffsetArrayOf<Coverage> OffsetArrayOf<Coverage>
lookaheadX; /* Array of coverage tables lookaheadX; /* Array of coverage tables
@ -1146,6 +1231,12 @@ struct SubstLookup : Lookup
return_trace (dispatch (c)); 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 inline hb_closure_context_t::return_t closure (hb_closure_context_t *c, unsigned int this_index) const
{ {
TRACE_CLOSURE (this); TRACE_CLOSURE (this);
@ -1311,11 +1402,11 @@ struct GSUB : GSUBGPOS
inline bool subset (hb_subset_context_t *c) const inline bool subset (hb_subset_context_t *c) const
{ {
TRACE_SUBSET (this); 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); if (unlikely (!GSUBGPOS::subset (c))) return_trace (false);
/* TODO Replace following with c->iter_copy_and_subset()ish. */ /* TODO Replace following with c->iter_copy_and_subset()ish. */
unsigned int count = get_lookup_count (); unsigned int count = get_lookup_count ();
LookupList &outLookupList = out+out->lookupList; //LookupList &outLookupList = out+out->lookupList;
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
//XXX if (unlikely (!outLookupList.arrayZ[i].subset (c, get_lookup (i), &outLookupList))) //XXX if (unlikely (!outLookupList.arrayZ[i].subset (c, get_lookup (i), &outLookupList)))
return_trace (false); return_trace (false);

View File

@ -40,6 +40,23 @@
namespace OT { 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 : struct hb_closure_context_t :
hb_dispatch_context_t<hb_closure_context_t, hb_void_t, HB_DEBUG_CLOSURE> 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; } inline return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; }
static return_t default_return_value (void) { 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; } 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)) if (unlikely (nesting_level_left == 0 || !recurse_func))
return default_return_value (); return;
nesting_level_left--; nesting_level_left--;
recurse_func (this, lookup_index); recurse_func (this, lookup_index);
nesting_level_left++; nesting_level_left++;
return HB_VOID;
} }
bool should_visit_lookup (unsigned int lookup_index) 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; } inline return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; }
static return_t default_return_value (void) { 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; } 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)) 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 /* 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 * 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 ()) if (output == hb_set_get_empty ())
return HB_VOID; return;
/* Return if new lookup was recursed to before. */ /* Return if new lookup was recursed to before. */
if (recursed_lookups->has (lookup_index)) if (recursed_lookups->has (lookup_index))
return HB_VOID; return;
hb_set_t *old_before = before; hb_set_t *old_before = before;
hb_set_t *old_input = input; hb_set_t *old_input = input;
@ -183,7 +199,7 @@ struct hb_collect_glyphs_context_t :
recursed_lookups->add (lookup_index); recursed_lookups->add (lookup_index);
return HB_VOID; return;
} }
hb_face_t *face; hb_face_t *face;
@ -208,24 +224,16 @@ struct hb_collect_glyphs_context_t :
after (glyphs_after ? glyphs_after : hb_set_get_empty ()), after (glyphs_after ? glyphs_after : hb_set_get_empty ()),
output (glyphs_output ? glyphs_output : hb_set_get_empty ()), output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
recurse_func (nullptr), recurse_func (nullptr),
recursed_lookups (nullptr), recursed_lookups (hb_set_create ()),
nesting_level_left (nesting_level_left_), nesting_level_left (nesting_level_left_),
debug_depth (0) debug_depth (0) {}
{ ~hb_collect_glyphs_context_t (void) { hb_set_destroy (recursed_lookups); }
recursed_lookups = hb_set_create ();
}
~hb_collect_glyphs_context_t (void)
{
hb_set_destroy (recursed_lookups);
}
void set_recurse_func (recurse_func_t func) { recurse_func = func; } void set_recurse_func (recurse_func_t func) { recurse_func = func; }
}; };
/* XXX Can we remove this? */
template <typename set_t> template <typename set_t>
struct hb_add_coverage_context_t : struct hb_add_coverage_context_t :
hb_dispatch_context_t<hb_add_coverage_context_t<set_t>, const Coverage &, HB_DEBUG_GET_COVERAGE> 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 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); 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); 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); const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
return class_def.intersects_class (glyphs, value); 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; const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
return (data+coverage).intersects (glyphs); 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, unsigned int count,
const HBUINT16 values[], const HBUINT16 values[],
intersects_func_t intersects_func, intersects_func_t intersects_func,
const void *intersects_data) const void *intersects_data)
{ {
for (unsigned int i = 0; i < count; i++) 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 false;
return true; return true;
} }
@ -1140,6 +1148,16 @@ struct ContextApplyLookupContext
const void *match_data; 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, static inline void context_closure_lookup (hb_closure_context_t *c,
unsigned int inputCount, /* Including the first glyph (not matched) */ unsigned int inputCount, /* Including the first glyph (not matched) */
const HBUINT16 input[], /* Array of input values--start with second glyph */ 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[], const LookupRecord lookupRecord[],
ContextClosureLookupContext &lookup_context) ContextClosureLookupContext &lookup_context)
{ {
if (intersects_array (c, if (context_intersects (c->glyphs,
inputCount ? inputCount - 1 : 0, input, inputCount, input,
lookup_context.funcs.intersects, lookup_context.intersects_data)) lookup_context))
recurse_lookups (c, recurse_lookups (c,
lookupCount, lookupRecord); lookupCount, lookupRecord);
} }
@ -1201,6 +1219,13 @@ static inline bool context_apply_lookup (hb_ot_apply_context_t *c,
struct Rule 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 inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
{ {
TRACE_CLOSURE (this); TRACE_CLOSURE (this);
@ -1261,6 +1286,15 @@ struct Rule
struct RuleSet 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 inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
{ {
TRACE_CLOSURE (this); TRACE_CLOSURE (this);
@ -1318,23 +1352,42 @@ struct RuleSet
struct ContextFormat1 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 inline void closure (hb_closure_context_t *c) const
{ {
TRACE_CLOSURE (this); TRACE_CLOSURE (this);
const Coverage &cov = (this+coverage);
struct ContextClosureLookupContext lookup_context = { struct ContextClosureLookupContext lookup_context = {
{intersects_glyph}, {intersects_glyph},
nullptr nullptr
}; };
unsigned int count = ruleSet.len; unsigned int count = ruleSet.len;
for (unsigned int i = 0; i < count; i++) for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
if (cov.intersects_coverage (c->glyphs, i)) { {
const RuleSet &rule_set = this+ruleSet[i]; if (unlikely (iter.get_coverage () >= count))
rule_set.closure (c, lookup_context); 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 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
@ -1365,9 +1418,7 @@ struct ContextFormat1
} }
inline const Coverage &get_coverage (void) const inline const Coverage &get_coverage (void) const
{ { return this+coverage; }
return this+coverage;
}
inline bool apply (hb_ot_apply_context_t *c) const inline bool apply (hb_ot_apply_context_t *c) const
{ {
@ -1405,6 +1456,27 @@ struct ContextFormat1
struct ContextFormat2 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 inline void closure (hb_closure_context_t *c) const
{ {
TRACE_CLOSURE (this); TRACE_CLOSURE (this);
@ -1457,9 +1529,7 @@ struct ContextFormat2
} }
inline const Coverage &get_coverage (void) const inline const Coverage &get_coverage (void) const
{ { return this+coverage; }
return this+coverage;
}
inline bool apply (hb_ot_apply_context_t *c) const inline bool apply (hb_ot_apply_context_t *c) const
{ {
@ -1501,6 +1571,20 @@ struct ContextFormat2
struct ContextFormat3 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 inline void closure (hb_closure_context_t *c) const
{ {
TRACE_CLOSURE (this); TRACE_CLOSURE (this);
@ -1548,9 +1632,7 @@ struct ContextFormat3
} }
inline const Coverage &get_coverage (void) const 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 inline bool apply (hb_ot_apply_context_t *c) const
{ {
@ -1638,6 +1720,26 @@ struct ChainContextApplyLookupContext
const void *match_data[3]; 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, static inline void chain_context_closure_lookup (hb_closure_context_t *c,
unsigned int backtrackCount, unsigned int backtrackCount,
const HBUINT16 backtrack[], const HBUINT16 backtrack[],
@ -1649,15 +1751,11 @@ static inline void chain_context_closure_lookup (hb_closure_context_t *c,
const LookupRecord lookupRecord[], const LookupRecord lookupRecord[],
ChainContextClosureLookupContext &lookup_context) ChainContextClosureLookupContext &lookup_context)
{ {
if (intersects_array (c, if (chain_context_intersects (c->glyphs,
backtrackCount, backtrack, backtrackCount, backtrack,
lookup_context.funcs.intersects, lookup_context.intersects_data[0]) inputCount, input,
&& intersects_array (c, lookaheadCount, lookahead,
inputCount ? inputCount - 1 : 0, input, lookup_context))
lookup_context.funcs.intersects, lookup_context.intersects_data[1])
&& intersects_array (c,
lookaheadCount, lookahead,
lookup_context.funcs.intersects, lookup_context.intersects_data[2]))
recurse_lookups (c, recurse_lookups (c,
lookupCount, lookupRecord); lookupCount, lookupRecord);
} }
@ -1737,6 +1835,17 @@ static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
struct ChainRule 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 inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
{ {
TRACE_CLOSURE (this); TRACE_CLOSURE (this);
@ -1823,6 +1932,14 @@ struct ChainRule
struct ChainRuleSet 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 inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
{ {
TRACE_CLOSURE (this); TRACE_CLOSURE (this);
@ -1877,10 +1994,28 @@ struct ChainRuleSet
struct ChainContextFormat1 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 inline void closure (hb_closure_context_t *c) const
{ {
TRACE_CLOSURE (this); TRACE_CLOSURE (this);
const Coverage &cov = (this+coverage);
struct ChainContextClosureLookupContext lookup_context = { struct ChainContextClosureLookupContext lookup_context = {
{intersects_glyph}, {intersects_glyph},
@ -1888,11 +2023,13 @@ struct ChainContextFormat1
}; };
unsigned int count = ruleSet.len; unsigned int count = ruleSet.len;
for (unsigned int i = 0; i < count; i++) for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
if (cov.intersects_coverage (c->glyphs, i)) { {
const ChainRuleSet &rule_set = this+ruleSet[i]; if (unlikely (iter.get_coverage () >= count))
rule_set.closure (c, lookup_context); 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 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
@ -1923,9 +2060,7 @@ struct ChainContextFormat1
} }
inline const Coverage &get_coverage (void) const inline const Coverage &get_coverage (void) const
{ { return this+coverage; }
return this+coverage;
}
inline bool apply (hb_ot_apply_context_t *c) const inline bool apply (hb_ot_apply_context_t *c) const
{ {
@ -1961,6 +2096,30 @@ struct ChainContextFormat1
struct ChainContextFormat2 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 inline void closure (hb_closure_context_t *c) const
{ {
TRACE_CLOSURE (this); TRACE_CLOSURE (this);
@ -2027,9 +2186,7 @@ struct ChainContextFormat2
} }
inline const Coverage &get_coverage (void) const inline const Coverage &get_coverage (void) const
{ { return this+coverage; }
return this+coverage;
}
inline bool apply (hb_ot_apply_context_t *c) const inline bool apply (hb_ot_apply_context_t *c) const
{ {
@ -2088,6 +2245,25 @@ struct ChainContextFormat2
struct ChainContextFormat3 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 inline void closure (hb_closure_context_t *c) const
{ {
TRACE_CLOSURE (this); TRACE_CLOSURE (this);