templatized CFF2 accelerator for lean Private dict interpretting for subset

also fixed local subrs serialization
diff --git a/src/hb-ot-cff2-table.hh b/src/hb-ot-cff2-table.hh
index 9447a9d..2212579 100644
--- a/src/hb-ot-cff2-table.hh
+++ b/src/hb-ot-cff2-table.hh
@@ -212,41 +212,17 @@
   }
 };
 
-struct CFF2PrivateDictValues : DictValues
+struct CFF2PrivateDictValues_Base : DictValues
 {
   inline void init (void)
   {
     DictValues::init ();
-
-    languageGroup = 0;
-    expansionFactor = 0.06f;
-    vsIndex = 0;
     subrsOffset.set (0);
-    blueScale = 0.039625f;
-    blueShift = 7.0f;
-    blueFuzz = 1.0f;
-    stdHW = UNSET_REAL_VALUE;
-    stdVW = UNSET_REAL_VALUE;
-    subrsOffset.set (0);
-    blueValues.init ();
-    otherBlues.init ();
-    familyBlues.init ();
-    familyOtherBlues.init ();
-    stemSnapH.init ();
-    stemSnapV.init ();
-
     localSubrs = &Null(Subrs);
   }
 
   inline void fini (void)
   {
-    blueValues.fini ();
-    otherBlues.fini ();
-    familyBlues.fini ();
-    familyOtherBlues.fini ();
-    stemSnapH.fini ();
-    stemSnapV.fini ();
-
     DictValues::fini ();
   }
 
@@ -261,10 +237,48 @@
     return size;
   }
 
+  LOffsetTo<Subrs>  subrsOffset;
+  const Subrs       *localSubrs;
+};
+
+struct CFF2PrivateDictValues : CFF2PrivateDictValues_Base
+{
+  inline void init (void)
+  {
+    CFF2PrivateDictValues_Base::init ();
+
+    languageGroup = 0;
+    expansionFactor = 0.06f;
+    vsIndex = 0;
+    blueScale = 0.039625f;
+    blueShift = 7.0f;
+    blueFuzz = 1.0f;
+    stdHW = UNSET_REAL_VALUE;
+    stdVW = UNSET_REAL_VALUE;
+    subrsOffset.set (0);
+    blueValues.init ();
+    otherBlues.init ();
+    familyBlues.init ();
+    familyOtherBlues.init ();
+    stemSnapH.init ();
+    stemSnapV.init ();
+  }
+
+  inline void fini (void)
+  {
+    blueValues.fini ();
+    otherBlues.fini ();
+    familyBlues.fini ();
+    familyOtherBlues.fini ();
+    stemSnapH.fini ();
+    stemSnapV.fini ();
+
+    CFF2PrivateDictValues_Base::fini ();
+  }
+
   int       languageGroup;
   float     expansionFactor;
   int       vsIndex;
-  OffsetTo<Subrs>  subrsOffset;
   float     blueScale;
   float     blueShift;
   float     blueFuzz;
@@ -276,8 +290,6 @@
   hb_vector_t <float> familyOtherBlues;
   hb_vector_t <float> stemSnapH;
   hb_vector_t <float> stemSnapV;
-
-  const Subrs *localSubrs;
 };
 
 struct CFF2PrivateDictOpSet
@@ -368,6 +380,56 @@
   }
 };
 
+struct CFF2PrivateDictOpSet_Subset
+{
+  static inline bool process_op (const ByteStr& str, unsigned int& offset, OpCode op, Stack& stack, CFF2PrivateDictValues_Base& val)
+  {
+    switch (op) {
+      case OpCode_BlueValues:
+      case OpCode_OtherBlues:
+      case OpCode_FamilyBlues:
+      case OpCode_FamilyOtherBlues:
+      case OpCode_StdHW:
+      case OpCode_StdVW:
+      case OpCode_BlueScale:
+      case OpCode_BlueShift:
+      case OpCode_BlueFuzz:
+      case OpCode_StemSnapH:
+      case OpCode_StemSnapV:
+      case OpCode_LanguageGroup:
+      case OpCode_ExpansionFactor:
+      case OpCode_blend:
+        stack.clear ();
+        break;
+
+      case OpCode_BCD:
+        {
+          float v;
+          return parse_bcd (str, offset, v);
+        }
+
+      case OpCode_Subrs:
+        if (unlikely (!check_pop_offset (stack, val.subrsOffset)))
+          return false;
+        break;
+      case OpCode_longint:  /* 5-byte integer */
+        if (unlikely (!str.check_limit (offset, 5) || !stack.check_overflow (1)))
+          return false;
+        stack.push_int ((int32_t)((str[offset + 1] << 24) | (str[offset + 2] << 16) || (str[offset + 3] << 8) || str[offset + 4]));
+        offset += 4;
+        break;
+
+      default:
+        return false;
+    }
+
+    if (op != OpCode_blend)
+      val.pushOpStr (op, str, offset + 1);
+
+    return true;
+  }
+};
+
 typedef Interpreter<CFF2TopDictOpSet, CFF2TopDictValues> CFF2TopDict_Interpreter;
 typedef Interpreter<CFF2FontDictOpSet, CFF2FontDictValues> CFF2FontDict_Interpreter;
 typedef Interpreter<CFF2PrivateDictOpSet, CFF2PrivateDictValues> CFF2PrivateDict_Interpreter;
@@ -389,7 +451,8 @@
                   likely (version.major == 2));
   }
 
-  struct accelerator_t
+  template <typename PrivOpSet, typename PrivDictVal>
+  struct accelerator_templ_t
   {
     inline void init (hb_face_t *face)
     {
@@ -402,7 +465,7 @@
       sc.init (this->blob);
       sc.start_processing ();
       
-      const OT::cff2 *cff2 = this->blob->as<OT::cff2> ();
+      const OT::cff2 *cff2 = this->blob->template as<OT::cff2> ();
 
       if (cff2 == &Null(OT::cff2))
       {
@@ -460,7 +523,7 @@
         }
 
         const ByteStr privDictStr (font->privateDictOffset (cff2), font->privateDictSize);
-        CFF2PrivateDict_Interpreter priv_interp;
+        Interpreter<PrivOpSet, PrivDictVal> priv_interp;
         if (unlikely (!privDictStr.sanitize (&sc) ||
                       !priv_interp.interpret (privDictStr, privateDicts[i])))
         {
@@ -468,7 +531,12 @@
           return;
         }
 
-        privateDicts[i].localSubrs = &privateDicts[i].subrsOffset (cff2);
+        privateDicts[i].localSubrs = &privateDicts[i].subrsOffset (privDictStr.str);
+        if (unlikely (!privateDicts[i].localSubrs->sanitize (&sc)))
+        {
+          fini ();
+          return;
+        }
       }
     }
 
@@ -506,11 +574,14 @@
     const FDSelect            *fdSelect;
 
     hb_vector_t<CFF2FontDictValues>     fontDicts;
-    hb_vector_t<CFF2PrivateDictValues>  privateDicts;
+    hb_vector_t<PrivDictVal>  privateDicts;
 
     unsigned int            num_glyphs;
   };
 
+  typedef accelerator_templ_t<CFF2PrivateDictOpSet, CFF2PrivateDictValues> accelerator_t;
+  typedef accelerator_templ_t<CFF2PrivateDictOpSet_Subset, CFF2PrivateDictValues_Base> accelerator_subset_t;
+
   inline bool subset (hb_subset_plan_t *plan) const
   {
     hb_blob_t *cff2_prime = nullptr;