Cache various masks on the shape plan
diff --git a/src/hb-ot-shape-fallback.cc b/src/hb-ot-shape-fallback.cc
index 4d8fb54..5d526c3 100644
--- a/src/hb-ot-shape-fallback.cc
+++ b/src/hb-ot-shape-fallback.cc
@@ -430,14 +430,12 @@
 			    hb_font_t *font,
 			    hb_buffer_t  *buffer)
 {
-  hb_mask_t kern_mask = plan->map.get_mask (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction) ?
-					    HB_TAG ('k','e','r','n') : HB_TAG ('v','k','r','n'));
-  if (!kern_mask) return;
+  if (!plan->has_kern) return;
 
   unsigned int count = buffer->len;
 
   OT::hb_apply_context_t c (1, font, buffer);
-  c.set_lookup_mask (kern_mask);
+  c.set_lookup_mask (plan->kern_mask);
   c.set_lookup_props (OT::LookupFlag::IgnoreMarks);
 
   hb_glyph_info_t *info = buffer->info;
diff --git a/src/hb-ot-shape-private.hh b/src/hb-ot-shape-private.hh
index cbfab5b..df81fa2 100644
--- a/src/hb-ot-shape-private.hh
+++ b/src/hb-ot-shape-private.hh
@@ -40,6 +40,10 @@
   const struct hb_ot_complex_shaper_t *shaper;
   hb_ot_map_t map;
   const void *data;
+  hb_mask_t rtlm_mask, frac_mask, numr_mask, dnom_mask;
+  hb_mask_t kern_mask;
+  unsigned int has_frac : 1;
+  unsigned int has_kern : 1;
 
   inline void collect_lookups (hb_tag_t table_tag, hb_set_t *lookups) const
   {
@@ -77,6 +81,17 @@
     plan.props = props;
     plan.shaper = shaper;
     map.compile (plan.map);
+
+    plan.rtlm_mask = plan.map.get_1_mask (HB_TAG ('r','t','l','m'));
+    plan.frac_mask = plan.map.get_1_mask (HB_TAG ('f','r','a','c'));
+    plan.numr_mask = plan.map.get_1_mask (HB_TAG ('n','u','m','r'));
+    plan.dnom_mask = plan.map.get_1_mask (HB_TAG ('d','n','o','m'));
+
+    plan.kern_mask = plan.map.get_mask (HB_DIRECTION_IS_HORIZONTAL (plan.props.direction) ?
+					HB_TAG ('k','e','r','n') : HB_TAG ('v','k','r','n'));
+
+    plan.has_frac = plan.frac_mask || (plan.numr_mask && plan.dnom_mask);
+    plan.has_kern = !!plan.kern_mask;
   }
 
   private:
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 55ddbb5..fcc61ae 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -296,7 +296,7 @@
 
   hb_buffer_t *buffer = c->buffer;
   hb_unicode_funcs_t *unicode = buffer->unicode;
-  hb_mask_t rtlm_mask = c->plan->map.get_1_mask (HB_TAG ('r','t','l','m'));
+  hb_mask_t rtlm_mask = c->plan->rtlm_mask;
 
   unsigned int count = buffer->len;
   hb_glyph_info_t *info = buffer->info;
@@ -312,9 +312,10 @@
 static inline void
 hb_ot_shape_setup_masks_fraction (hb_ot_shape_context_t *c)
 {
+  if (!c->plan->has_frac)
+    return;
+
   hb_buffer_t *buffer = c->buffer;
-  bool initialized = false;
-  hb_mask_t frac_mask = 0, numr_mask = 0, dnom_mask = 0;
 
   /* TODO look in pre/post context text also. */
   unsigned int count = buffer->len;
@@ -323,19 +324,6 @@
   {
     if (info[i].codepoint == 0x2044) /* FRACTION SLASH */
     {
-      if (!initialized)
-      {
-	initialized = true;
-
-	frac_mask = c->plan->map.get_1_mask (HB_TAG ('f','r','a','c'));
-	numr_mask = c->plan->map.get_1_mask (HB_TAG ('n','u','m','r'));
-	dnom_mask = c->plan->map.get_1_mask (HB_TAG ('d','n','o','m'));
-
-	/* Only proceed if frac exists, or both numr and dnom exist. */
-	if (!frac_mask && (!numr_mask || !dnom_mask))
-	  return;
-      }
-
       unsigned int start = i, end = i + 1;
       while (start &&
 	     _hb_glyph_info_get_general_category (&info[start - 1]) ==
@@ -347,10 +335,10 @@
         end++;
 
       for (unsigned int j = start; j < i; j++)
-        info[j].mask |= numr_mask | frac_mask;
-      info[i].mask |= frac_mask;
+        info[j].mask |= c->plan->numr_mask | c->plan->frac_mask;
+      info[i].mask |= c->plan->frac_mask;
       for (unsigned int j = i + 1; j < end; j++)
-        info[j].mask |= frac_mask | dnom_mask;
+        info[j].mask |= c->plan->frac_mask | c->plan->dnom_mask;
 
       i = end - 1;
     }