diff --git a/src/hb-aat-layout-common-private.hh b/src/hb-aat-layout-common-private.hh index 4ed2d3a18..37a84bef6 100644 --- a/src/hb-aat-layout-common-private.hh +++ b/src/hb-aat-layout-common-private.hh @@ -614,15 +614,23 @@ struct StateTableDriver machine (machine_), buffer (buffer_), num_glyphs (face_->get_num_glyphs ()), - state (0), - last_zero (0) {} + last_zero (0) + { + dont_advance_set.init (); + } + + inline ~StateTableDriver (void) + { + dont_advance_set.finish (); + } template inline void drive (context_t *c) { hb_glyph_info_t *info = buffer->info; unsigned int count = buffer->len; - + unsigned int state = 0; + bool last_was_dont_advance = false; for (buffer->idx = 0; buffer->idx <= count; buffer->idx++) { if (!state) @@ -637,8 +645,22 @@ struct StateTableDriver c->transition (this, entry); + if (entry->flags & context_t::DontAdvance) - buffer->idx--; /* TODO Detect infinite loop. */ + { + if (!last_was_dont_advance) + dont_advance_set.clear (); + + unsigned int key = info[buffer->idx].codepoint | (state << 16); + if (likely (!dont_advance_set.has (key))) + { + dont_advance_set.add (key); + buffer->idx--; + last_was_dont_advance = true; + } + } + else + last_was_dont_advance = false; state = entry->newState; } @@ -649,11 +671,11 @@ struct StateTableDriver public: const StateTable &machine; hb_buffer_t *buffer; - unsigned int num_glyphs; - - unsigned int state; unsigned int last_zero; + + private: + hb_set_t dont_advance_set; /* Infinite-loop detection */ };