[subset] Limit the iterations of the closure algorithm. Prevents O(n^2) run times.
diff --git a/src/hb-ot-layout-common-private.hh b/src/hb-ot-layout-common-private.hh index 21caf9e..7ff0dbe 100644 --- a/src/hb-ot-layout-common-private.hh +++ b/src/hb-ot-layout-common-private.hh
@@ -41,6 +41,13 @@ #ifndef HB_MAX_CONTEXT_LENGTH #define HB_MAX_CONTEXT_LENGTH 64 #endif +#ifndef HB_CLOSURE_MAX_STAGES +/* + * The maximum number of times a lookup can be applied during shaping. + * Used to limit the number of iterations of the closure algorithm. + */ +#define HB_CLOSURE_MAX_STAGES 8 +#endif namespace OT {
diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc index 0eba88a..01ca514 100644 --- a/src/hb-ot-layout.cc +++ b/src/hb-ot-layout.cc
@@ -971,6 +971,7 @@ OT::hb_closure_context_t c (face, glyphs, &done_lookups); const OT::GSUB& gsub = _get_gsub (face); + unsigned int iteration_count = 0; unsigned int glyphs_length; do { @@ -985,7 +986,9 @@ for (unsigned int i = 0; i < gsub.get_lookup_count (); i++) gsub.get_lookup (i).closure (&c, i); } - } while (glyphs_length != glyphs->get_population ()); + iteration_count++; + } while (iteration_count <= HB_CLOSURE_MAX_STAGES + && glyphs_length != glyphs->get_population ()); } /*