[morx] Speed up unsafe-to-break

This is a port of https://github.com/harfbuzz/harfrust/pull/241
but crashes (with LucidaGrande for example), because, unlike HarfRust,
in HarfBuzz it's not safe to access states up to 64 without checking.

In HarfBuzz we do that check in sanitize() but don't keep the max
state number. Also, we allow negative states.

All considered, looks like this optimization is not worth implementing
in HB, specially since our .entry() is much faster than in HarfRust.
diff --git a/src/hb-aat-layout-common.hh b/src/hb-aat-layout-common.hh
index e108cea..0496d7b 100644
--- a/src/hb-aat-layout-common.hh
+++ b/src/hb-aat-layout-common.hh
@@ -126,12 +126,14 @@
   const OT::GDEF &gdef;
   bool has_glyph_classes;
   const hb_sorted_vector_t<hb_aat_map_t::range_flags_t> *range_flags = nullptr;
+  hb_mask_t subtable_flags = 0;
+  // Caches
   bool using_buffer_glyph_set = false;
   hb_bit_set_t *buffer_glyph_set = nullptr;
   const hb_bit_set_t *first_set = nullptr;
   const hb_bit_set_t *second_set = nullptr;
   hb_aat_class_cache_t *machine_class_cache = nullptr;
-  hb_mask_t subtable_flags = 0;
+  uint64_t start_end_safe_to_break = 0;
 
   /* Unused. For debug tracing only. */
   unsigned int lookup_index;
@@ -889,6 +891,21 @@
     (this+classTable).collect_glyphs_filtered (glyphs, num_glyphs, filter);
   }
 
+  template <typename table_t>
+  uint64_t collect_start_end_safe_to_break (const table_t &table) const
+  {
+    uint64_t result = 0;
+    for (unsigned state = 0; state < 64; state++)
+    {
+      const auto &entry = get_entry (state, (unsigned) CLASS_END_OF_TEXT);
+      bool bit = !table.is_actionable (entry);
+      if (bit) {
+	result |= 1 << state;
+      }
+    }
+    return result;
+  }
+
   int new_state (unsigned int newState) const
   { return Types::extended ? newState : ((int) newState - (int) stateArrayTable) / (int) nClasses; }
 
@@ -1297,7 +1314,12 @@
 	  ) &&
 
           /* 3. */
-          !c->table->is_actionable (machine.get_entry (state, CLASS_END_OF_TEXT))
+	  (
+	    state < 64 ?
+	      (ac->start_end_safe_to_break & (1 << state))
+	    :
+	      !c->table->is_actionable (machine.get_entry (state, CLASS_END_OF_TEXT))
+	  )
       );
 
       if (!is_safe_to_break && buffer->backtrack_len () && buffer->idx < buffer->len)
diff --git a/src/hb-aat-layout-morx-table.hh b/src/hb-aat-layout-morx-table.hh
index 89ec080..c47f86f 100644
--- a/src/hb-aat-layout-morx-table.hh
+++ b/src/hb-aat-layout-morx-table.hh
@@ -927,18 +927,21 @@
     friend struct hb_aat_layout_lookup_accelerator_t;
 
     public:
+    uint64_t start_end_safe_to_break;
     hb_bit_set_t glyph_set;
     mutable hb_aat_class_cache_t class_cache;
 
     template <typename T>
     auto init_ (const T &obj_, unsigned num_glyphs, hb_priority<1>) HB_AUTO_RETURN
-    (
+    ((
+      start_end_safe_to_break = obj_.machine.collect_start_end_safe_to_break (obj_),
       obj_.machine.collect_initial_glyphs (glyph_set, num_glyphs, obj_)
-    )
+    ))
 
     template <typename T>
     void init_ (const T &obj_, unsigned num_glyphs, hb_priority<0>)
     {
+      start_end_safe_to_break = 0;
       obj_.collect_initial_glyphs (glyph_set, num_glyphs);
     }
 
@@ -1178,6 +1181,7 @@
       c->subtable_flags = subtable_flags;
       c->first_set = accel ? &accel->subtables[i].glyph_set : &Null(hb_bit_set_t);
       c->machine_class_cache = accel ? &accel->subtables[i].class_cache : nullptr;
+      c->start_end_safe_to_break = accel ? accel->subtables[i].start_end_safe_to_break : 0;
 
       if (!c->buffer_intersects_machine ())
       {