added CFF1 desubr api test cases & bug fixes
diff --git a/src/hb-cff1-interp-cs.hh b/src/hb-cff1-interp-cs.hh
index ec8a7fa..0d267ac 100644
--- a/src/hb-cff1-interp-cs.hh
+++ b/src/hb-cff1-interp-cs.hh
@@ -111,16 +111,9 @@
           break;
       }
       env.set_width (has_width);
-      if (has_width)
-      {
-        OPSET::process_width (env, param);
-      }
     }
   }
 
-  static inline void process_width (CFF1CSInterpEnv &env, PARAM& param)
-  {}
-
   static inline void flush_args (CFF1CSInterpEnv &env, PARAM& param)
   {
     SUPER::flush_args (env, param);
diff --git a/src/hb-ot-cff-common.hh b/src/hb-ot-cff-common.hh
index 40ae957..2f5e2f8 100644
--- a/src/hb-ot-cff-common.hh
+++ b/src/hb-ot-cff-common.hh
@@ -93,7 +93,12 @@
   { return calculate_offset_array_size (offSize, count); }
 
   inline static unsigned int calculate_serialized_size (unsigned int offSize, unsigned int count, unsigned int dataSize)
-  { return min_size + calculate_offset_array_size (offSize, count) + dataSize; }
+  {
+    if (count == 0)
+      return COUNT::static_size;
+    else
+      return min_size + calculate_offset_array_size (offSize, count) + dataSize;
+  }
 
   inline bool serialize (hb_serialize_context_t *c, const CFFIndex &src)
   {
@@ -110,30 +115,39 @@
                          const ByteStrArray &byteArray)
   {
     TRACE_SERIALIZE (this);
-    /* serialize CFFIndex header */
-    if (unlikely (!c->extend_min (*this))) return_trace (false);
-    this->count.set (byteArray.len);
-    this->offSize.set (offSize_);
-    if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (byteArray.len + 1))))
-      return_trace (false);
-  
-    /* serialize indices */
-    unsigned int  offset = 1;
-    unsigned int  i = 0;
-    for (; i < byteArray.len; i++)
+    if (byteArray.len == 0)
     {
-      set_offset_at (i, offset);
-      offset += byteArray[i].get_size ();
+      COUNT *dest = c->allocate_min<COUNT> ();
+      if (unlikely (dest == nullptr)) return_trace (false);
+      dest->set (0);
     }
-    set_offset_at (i, offset);
-
-    /* serialize data */
-    for (unsigned int i = 0; i < byteArray.len; i++)
+    else
     {
-      ByteStr  *dest = c->start_embed<ByteStr> ();
-      if (unlikely (dest == nullptr ||
-                    !dest->serialize (c, byteArray[i])))
+      /* serialize CFFIndex header */
+      if (unlikely (!c->extend_min (*this))) return_trace (false);
+      this->count.set (byteArray.len);
+      this->offSize.set (offSize_);
+      if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (byteArray.len + 1))))
         return_trace (false);
+    
+      /* serialize indices */
+      unsigned int  offset = 1;
+      unsigned int  i = 0;
+      for (; i < byteArray.len; i++)
+      {
+        set_offset_at (i, offset);
+        offset += byteArray[i].get_size ();
+      }
+      set_offset_at (i, offset);
+
+      /* serialize data */
+      for (unsigned int i = 0; i < byteArray.len; i++)
+      {
+        ByteStr  *dest = c->start_embed<ByteStr> ();
+        if (unlikely (dest == nullptr ||
+                      !dest->serialize (c, byteArray[i])))
+          return_trace (false);
+      }
     }
     return_trace (true);
   }
diff --git a/src/hb-subset-cff-common.hh b/src/hb-subset-cff-common.hh
index 944d5e9..edee147 100644
--- a/src/hb-subset-cff-common.hh
+++ b/src/hb-subset-cff-common.hh
@@ -378,8 +378,10 @@
   inline void init (unsigned int subr_num_ = 0)
   {
     OpStr::init ();
-    flags = kDropFlag_None;
     subr_num = subr_num_;
+    drop_flag = false;
+    keep_flag = false;
+    skip_flag = false;
   }
 
   inline void fini (void)
@@ -387,20 +389,19 @@
     OpStr::fini ();
   }
 
-  inline bool for_keep (void) const { return (flags & kDropFlag_Keep) != 0; }
-  inline bool for_drop (void) const { return (flags & kDropFlag_Drop) != 0; }
-  inline void set_drop (void) { if (!for_keep ()) flags |= kDropFlag_Drop; }
-  inline void set_keep (void) { flags |= kDropFlag_Keep; }
+  inline bool for_drop (void) const { return drop_flag; }
+  inline void set_drop (void) { if (!for_keep ()) drop_flag = true; }
+  inline bool for_keep (void) const { return keep_flag; }
+  inline void set_keep (void) { keep_flag = true; }
+  inline bool for_skip (void) const { return skip_flag; }
+  inline void set_skip (void) { skip_flag = true; }
 
-  enum DropFlag
-  {
-    kDropFlag_None  = 0,
-    kDropFlag_Drop  = 1,
-    kDropFlag_Keep  = 2
-  };
-
-  unsigned int  flags;
   unsigned int  subr_num;
+
+  protected:
+  bool          drop_flag : 1;
+  bool          keep_flag : 1;
+  bool          skip_flag : 1;
 };
 
 struct ParsedCStr : ParsedValues<ParsedCSOp>
@@ -425,7 +426,7 @@
     {
       unsigned int parsed_len = get_count ();
       if (likely (parsed_len > 0))
-        values[parsed_len-1].set_drop ();
+        values[parsed_len-1].set_skip ();
       
       ParsedCSOp val;
       val.init (subr_num);
@@ -629,8 +630,8 @@
    * 4. re-encode all charstrings and subroutines with new subroutine numbers
    *
    * Phases #1 and #2 are done at the same time in collect_subrs ().
-   * Phase #3 requires walking charstrings/subroutines forward then backward (hence parsing), because
-   * we can't tell if a number belongs to a hint op until we see the first moveto.
+   * Phase #3 walks charstrings/subroutines forward then backward (hence parsing required),
+   * because we can't tell if a number belongs to a hint op until we see the first moveto.
    *
    * Assumption: a callsubr/callgsubr operator must immediately follow a (biased) subroutine number
    * within the same charstring/subroutine, e.g., not split across a charstring and a subroutine.
@@ -686,7 +687,8 @@
                     drop_hints);
 
         bool seen_moveto = false;
-        if (drop_hints_in_str (parsed_charstrings[i], param, seen_moveto))
+        bool ends_in_hint = false;
+        if (drop_hints_in_str (parsed_charstrings[i], param, seen_moveto, ends_in_hint))
           parsed_charstrings[i].set_hint_removed ();
       }
 
@@ -755,39 +757,39 @@
                                  ParsedCStrs &subrs, unsigned int subr_num,
                                  const SubrSubsetParam &param, bool &seen_moveto)
   {
-    if (drop_hints_in_str (subrs[subr_num], param, seen_moveto))
-    {
-      /* if the first op in the subr is a hint op, then all args/ops (especially including other subr calls)
-       * preceding this subr no and call op are hints */
-      /* TODO CFF2 vsindex */
-      for (unsigned int i = 0; i + 1 < pos; i++)
-        str.values[i].set_drop ();
-      return true;
-    }
-    else
-      return false;
+    bool  ends_in_hint = false;
+    bool has_hint = drop_hints_in_str (subrs[subr_num], param, seen_moveto, ends_in_hint);
+
+    /* if this subr ends with a stem hint (i.e., not a number a potential argument for moveto),
+     * then this entire subroutine must be a hint. drop its call. */
+    if (ends_in_hint)
+      str.values[pos].set_drop ();
+    
+    return has_hint;
   }
 
-  /* returns true if it sees a hint op before moveto */
-  inline bool drop_hints_in_str (ParsedCStr &str, const SubrSubsetParam &param, bool &seen_moveto)
+  /* returns true if it sees a hint op before the first moveto */
+  inline bool drop_hints_in_str (ParsedCStr &str, const SubrSubsetParam &param,
+                                 bool &seen_moveto, bool &ends_in_hint)
   {
     bool  seen_hint = false;
-    unsigned int next_check_pos = 0;
 
     for (unsigned int pos = 0; pos < str.values.len; pos++)
     {
+      bool  has_hint = false;
       switch (str.values[pos].op)
       {
         case OpCode_callsubr:
-          seen_hint |= drop_hints_in_subr (str, pos,
-                                           *param.parsed_local_subrs, str.values[pos].subr_num,
-                                           param, seen_moveto);
+          has_hint = drop_hints_in_subr (str, pos,
+                                        *param.parsed_local_subrs, str.values[pos].subr_num,
+                                        param, seen_moveto);
+                                        
           break;
 
         case OpCode_callgsubr:
-          seen_hint |= drop_hints_in_subr (str, pos,
-                                           *param.parsed_global_subrs, str.values[pos].subr_num,
-                                           param, seen_moveto);
+          has_hint = drop_hints_in_subr (str, pos,
+                                        *param.parsed_global_subrs, str.values[pos].subr_num,
+                                        param, seen_moveto);
           break;
 
         case OpCode_rmoveto:
@@ -809,19 +811,27 @@
         case OpCode_vstemhm:
         case OpCode_hstem:
         case OpCode_vstem:
-          seen_hint = true;
-          for (unsigned int i = next_check_pos; i <= pos; i++)
-          {
-            /* TODO: CFF2 vsindex */
-            str.values[i].set_drop ();
-          }
-          next_check_pos = pos + 1;
+          has_hint = true;
+          str.values[pos].set_drop ();
+          if ((pos + 1 >= str.values.len) /* CFF2 */
+             || (str.values[pos + 1].op == OpCode_return))
+            ends_in_hint = true;
           break;
 
         default:
           /* NONE */
           break;
       }
+      if (has_hint)
+      {
+        for (int i = pos - 1; i >= 0; i--)
+        {
+          if (str.values[i].for_drop ())
+            break;
+          str.values[i].set_drop ();
+        }
+        seen_hint |= has_hint;
+      }
     }
 
     return seen_hint;
@@ -878,7 +888,7 @@
     for (unsigned int i = 0; i < str.get_count(); i++)
     {
       const ParsedCSOp  &opstr = str.values[i];
-      if (!opstr.for_drop ())
+      if (!opstr.for_drop () && !opstr.for_skip ())
       {
         switch (opstr.op)
         {
diff --git a/src/hb-subset-cff1.cc b/src/hb-subset-cff1.cc
index 414642f..216d095 100644
--- a/src/hb-subset-cff1.cc
+++ b/src/hb-subset-cff1.cc
@@ -380,11 +380,6 @@
     }
   }
 
-  static inline void process_width (CFF1CSInterpEnv &env, SubrSubsetParam& param)
-  {
-  
-  }
-
   protected:
   static inline void process_call_subr (OpCode op, CSType type,
                                         CFF1CSInterpEnv &env, SubrSubsetParam& param,
@@ -405,7 +400,7 @@
 {
   static inline void set_parsed_prefix (const CFF1CSInterpEnv &env, ParsedCStr &charstring)
   {
-    if (env.processed_width)
+    if (env.has_width)
       charstring.set_prefix (env.width);
   }
 };
@@ -676,7 +671,7 @@
         return false;
       
       /* no global/local subroutines */
-      offsets.globalSubrsInfo.size = HBUINT16::static_size; /* count 0 only */
+      offsets.globalSubrsInfo.size = CFF1Subrs::calculate_serialized_size (1, 0, 0);
     }
     else
     {
@@ -704,14 +699,19 @@
       for (unsigned int fd = 0; fd < orig_fdcount; fd++)
       {
         subset_localsubrs[fd].init ();
+        offsets.localSubrsInfos[fd].init ();
         if (fdmap.includes (fd))
         {
           if (!subr_subsetter.encode_localsubrs (fd, subset_localsubrs[fd]))
             return false;
 
           unsigned int dataSize = subset_localsubrs[fd].total_size ();
-          offsets.localSubrsInfos[fd].offSize = calcOffSize (dataSize);
-          offsets.localSubrsInfos[fd].size = CFF1Subrs::calculate_serialized_size (offsets.localSubrsInfos[fd].offSize, subset_localsubrs[fd].len, dataSize);
+          if (dataSize > 0)
+          {
+            offsets.localSubrsInfos[fd].offset = final_size;
+            offsets.localSubrsInfos[fd].offSize = calcOffSize (dataSize);
+            offsets.localSubrsInfos[fd].size = CFF1Subrs::calculate_serialized_size (offsets.localSubrsInfos[fd].offSize, subset_localsubrs[fd].len, dataSize);
+          }
         }
       }
     }
@@ -779,8 +779,11 @@
         fontdicts_mod.push (fontdict_mod);
         final_size += privInfo.size;
 
-        if (!plan->desubroutinize)
+        if (!plan->desubroutinize && (offsets.localSubrsInfos[i].size > 0))
+        {
+          offsets.localSubrsInfos[i].offset = final_size;
           final_size += offsets.localSubrsInfos[i].size;
+        }
       }
     }
 
@@ -900,21 +903,12 @@
     assert (plan.offsets.globalSubrsInfo.offset != 0);
     assert (plan.offsets.globalSubrsInfo.offset == c.head - c.start);
     
-    if (plan.desubroutinize)
+    CFF1Subrs *dest = c.start_embed <CFF1Subrs> ();
+    if (unlikely (dest == nullptr)) return false;
+    if (unlikely (!dest->serialize (&c, plan.offsets.globalSubrsInfo.offSize, plan.subset_globalsubrs)))
     {
-      CFF1Subrs *dest = c.allocate_size <CFF1Subrs> (HBUINT16::static_size);
-      if (unlikely (dest == nullptr)) return false;
-      dest->count.set (0);
-    }
-    else
-    {
-      CFF1Subrs *dest = c.start_embed <CFF1Subrs> ();
-      if (unlikely (dest == nullptr)) return false;
-      if (unlikely (!dest->serialize (&c, plan.offsets.globalSubrsInfo.offSize, plan.subset_globalsubrs)))
-      {
-        DEBUG_MSG (SUBSET, nullptr, "failed to serialize global subroutines");
-        return false;
-      }
+      DEBUG_MSG (SUBSET, nullptr, "failed to serialize global subroutines");
+      return false;
     }
   }
 
@@ -1010,7 +1004,7 @@
   assert (plan.offsets.privateDictInfo.offset == c.head - c.start);
   for (unsigned int i = 0; i < acc.privateDicts.len; i++)
   {
-    if (!plan.fdmap.excludes (i))
+    if (plan.fdmap.includes (i))
     {
       PrivateDict  *pd = c.start_embed<PrivateDict> ();
       if (unlikely (pd == nullptr)) return false;
@@ -1024,14 +1018,7 @@
         DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF Private Dict[%d]", i);
         return false;
       }
-    }
-  }
-
-  if (!plan.desubroutinize)
-  {
-    for (unsigned int i = 0; i < acc.privateDicts.len; i++)
-    {
-      if (!plan.fdmap.excludes (i))
+      if (plan.offsets.localSubrsInfos[i].size > 0)
       {
         CFF1Subrs *dest = c.start_embed <CFF1Subrs> ();
         if (unlikely (dest == nullptr)) return false;
diff --git a/test/api/fonts/SourceHanSans-Regular.41,3041,4C2E.otf b/test/api/fonts/SourceHanSans-Regular.41,3041,4C2E.otf
index 08bc0e0..b4d1165 100644
--- a/test/api/fonts/SourceHanSans-Regular.41,3041,4C2E.otf
+++ b/test/api/fonts/SourceHanSans-Regular.41,3041,4C2E.otf
Binary files differ
diff --git a/test/api/fonts/SourceHanSans-Regular.41,4C2E.nohints.otf b/test/api/fonts/SourceHanSans-Regular.41,4C2E.nohints.otf
new file mode 100644
index 0000000..e054826
--- /dev/null
+++ b/test/api/fonts/SourceHanSans-Regular.41,4C2E.nohints.otf
Binary files differ
diff --git a/test/api/fonts/SourceHanSans-Regular.41,4C2E.nosubrs.nohints.otf b/test/api/fonts/SourceHanSans-Regular.41,4C2E.nosubrs.nohints.otf
new file mode 100644
index 0000000..00a112f
--- /dev/null
+++ b/test/api/fonts/SourceHanSans-Regular.41,4C2E.nosubrs.nohints.otf
Binary files differ
diff --git a/test/api/fonts/SourceHanSans-Regular.41,4C2E.nosubrs.otf b/test/api/fonts/SourceHanSans-Regular.41,4C2E.nosubrs.otf
new file mode 100644
index 0000000..6fe9bf3
--- /dev/null
+++ b/test/api/fonts/SourceHanSans-Regular.41,4C2E.nosubrs.otf
Binary files differ
diff --git a/test/api/fonts/SourceHanSans-Regular.41,4C2E.otf b/test/api/fonts/SourceHanSans-Regular.41,4C2E.otf
index 113c1d7..7b88702 100644
--- a/test/api/fonts/SourceHanSans-Regular.41,4C2E.otf
+++ b/test/api/fonts/SourceHanSans-Regular.41,4C2E.otf
Binary files differ
diff --git a/test/api/fonts/SourceSansPro-Regular.abc.otf b/test/api/fonts/SourceSansPro-Regular.abc.otf
index 1f1af4a..4db5c79 100644
--- a/test/api/fonts/SourceSansPro-Regular.abc.otf
+++ b/test/api/fonts/SourceSansPro-Regular.abc.otf
Binary files differ
diff --git a/test/api/fonts/SourceSansPro-Regular.ac.nohints.otf b/test/api/fonts/SourceSansPro-Regular.ac.nohints.otf
index 30d9e34..3ad2bb4 100644
--- a/test/api/fonts/SourceSansPro-Regular.ac.nohints.otf
+++ b/test/api/fonts/SourceSansPro-Regular.ac.nohints.otf
Binary files differ
diff --git a/test/api/fonts/SourceSansPro-Regular.ac.nosubrs.nohints.otf b/test/api/fonts/SourceSansPro-Regular.ac.nosubrs.nohints.otf
new file mode 100644
index 0000000..69e244c
--- /dev/null
+++ b/test/api/fonts/SourceSansPro-Regular.ac.nosubrs.nohints.otf
Binary files differ
diff --git a/test/api/fonts/SourceSansPro-Regular.ac.nosubrs.otf b/test/api/fonts/SourceSansPro-Regular.ac.nosubrs.otf
new file mode 100644
index 0000000..28edf13
--- /dev/null
+++ b/test/api/fonts/SourceSansPro-Regular.ac.nosubrs.otf
Binary files differ
diff --git a/test/api/fonts/SourceSansPro-Regular.ac.otf b/test/api/fonts/SourceSansPro-Regular.ac.otf
index 40b938e..a22b157 100644
--- a/test/api/fonts/SourceSansPro-Regular.ac.otf
+++ b/test/api/fonts/SourceSansPro-Regular.ac.otf
Binary files differ
diff --git a/test/api/test-subset-cff1.c b/test/api/test-subset-cff1.c
index 8f0c1b6..4aafb80 100644
--- a/test/api/test-subset-cff1.c
+++ b/test/api/test-subset-cff1.c
@@ -92,6 +92,53 @@
 }
 
 static void
+test_subset_cff1_desubr (void)
+{
+  hb_face_t *face_abc = hb_test_open_font_file ("fonts/SourceSansPro-Regular.abc.otf");
+  hb_face_t *face_ac = hb_test_open_font_file ("fonts/SourceSansPro-Regular.ac.nosubrs.otf");
+
+  hb_set_t *codepoints = hb_set_create ();
+  hb_subset_input_t *input;
+  hb_face_t *face_abc_subset;
+  hb_set_add (codepoints, 'a');
+  hb_set_add (codepoints, 'c');
+  input = hb_subset_test_create_input (codepoints);
+  hb_subset_input_set_desubroutinize (input, true);
+  face_abc_subset = hb_subset_test_create_subset (face_abc, input);
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('C','F','F',' '));
+
+  hb_face_destroy (face_abc_subset);
+  hb_face_destroy (face_abc);
+  hb_face_destroy (face_ac);
+}
+
+static void
+test_subset_cff1_desubr_strip_hints (void)
+{
+  hb_face_t *face_abc = hb_test_open_font_file ("fonts/SourceSansPro-Regular.abc.otf");
+  hb_face_t *face_ac = hb_test_open_font_file ("fonts/SourceSansPro-Regular.ac.nosubrs.nohints.otf");
+
+  hb_set_t *codepoints = hb_set_create ();
+  hb_subset_input_t *input;
+  hb_face_t *face_abc_subset;
+  hb_set_add (codepoints, 'a');
+  hb_set_add (codepoints, 'c');
+  input = hb_subset_test_create_input (codepoints);
+  hb_subset_input_set_drop_hints (input, true);
+  hb_subset_input_set_desubroutinize (input, true);
+  face_abc_subset = hb_subset_test_create_subset (face_abc, input);
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('C', 'F', 'F', ' '));
+
+  hb_face_destroy (face_abc_subset);
+  hb_face_destroy (face_abc);
+  hb_face_destroy (face_ac);
+}
+
+static void
 test_subset_cff1_j (void)
 {
   hb_face_t *face_41_3041_4c2e = hb_test_open_font_file ("fonts/SourceHanSans-Regular.41,3041,4C2E.otf");
@@ -112,6 +159,76 @@
 }
 
 static void
+test_subset_cff1_j_strip_hints (void)
+{
+  hb_face_t *face_41_3041_4c2e = hb_test_open_font_file ("fonts/SourceHanSans-Regular.41,3041,4C2E.otf");
+  hb_face_t *face_41_4c2e = hb_test_open_font_file ("fonts/SourceHanSans-Regular.41,4C2E.nohints.otf");
+
+  hb_set_t *codepoints = hb_set_create ();
+  hb_face_t *face_41_3041_4c2e_subset;
+  hb_subset_input_t *input;
+  hb_set_add (codepoints, 0x41);
+  hb_set_add (codepoints, 0x4C2E);
+  input = hb_subset_test_create_input (codepoints);
+  hb_subset_input_set_drop_hints (input, true);
+  face_41_3041_4c2e_subset = hb_subset_test_create_subset (face_41_3041_4c2e, input);
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_41_4c2e, face_41_3041_4c2e_subset, HB_TAG ('C','F','F',' '));
+
+  hb_face_destroy (face_41_3041_4c2e_subset);
+  hb_face_destroy (face_41_3041_4c2e);
+  hb_face_destroy (face_41_4c2e);
+}
+
+static void
+test_subset_cff1_j_desubr (void)
+{
+  hb_face_t *face_41_3041_4c2e = hb_test_open_font_file ("fonts/SourceHanSans-Regular.41,3041,4C2E.otf");
+  hb_face_t *face_41_4c2e = hb_test_open_font_file ("fonts/SourceHanSans-Regular.41,4C2E.nosubrs.otf");
+
+  hb_set_t *codepoints = hb_set_create ();
+  hb_face_t *face_41_3041_4c2e_subset;
+  hb_subset_input_t *input;
+  hb_set_add (codepoints, 0x41);
+  hb_set_add (codepoints, 0x4C2E);
+  input = hb_subset_test_create_input (codepoints);
+  hb_subset_input_set_desubroutinize (input, true);
+  face_41_3041_4c2e_subset = hb_subset_test_create_subset (face_41_3041_4c2e, input);
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_41_4c2e, face_41_3041_4c2e_subset, HB_TAG ('C','F','F',' '));
+
+  hb_face_destroy (face_41_3041_4c2e_subset);
+  hb_face_destroy (face_41_3041_4c2e);
+  hb_face_destroy (face_41_4c2e);
+}
+
+static void
+test_subset_cff1_j_desubr_strip_hints (void)
+{
+  hb_face_t *face_41_3041_4c2e = hb_test_open_font_file ("fonts/SourceHanSans-Regular.41,3041,4C2E.otf");
+  hb_face_t *face_41_4c2e = hb_test_open_font_file ("fonts/SourceHanSans-Regular.41,4C2E.nosubrs.nohints.otf");
+
+  hb_set_t *codepoints = hb_set_create ();
+  hb_face_t *face_41_3041_4c2e_subset;
+  hb_subset_input_t *input;
+  hb_set_add (codepoints, 0x41);
+  hb_set_add (codepoints, 0x4C2E);
+  input = hb_subset_test_create_input (codepoints);
+  hb_subset_input_set_drop_hints (input, true);
+  hb_subset_input_set_desubroutinize (input, true);
+  face_41_3041_4c2e_subset = hb_subset_test_create_subset (face_41_3041_4c2e, input);
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_41_4c2e, face_41_3041_4c2e_subset, HB_TAG ('C','F','F',' '));
+
+  hb_face_destroy (face_41_3041_4c2e_subset);
+  hb_face_destroy (face_41_3041_4c2e);
+  hb_face_destroy (face_41_4c2e);
+}
+
+static void
 test_subset_cff1_expert (void)
 {
   hb_face_t *face = hb_test_open_font_file ("fonts/cff1_expert.otf");
@@ -139,7 +256,12 @@
   hb_test_add (test_subset_cff1_noop);
   hb_test_add (test_subset_cff1);
   hb_test_add (test_subset_cff1_strip_hints);
+  hb_test_add (test_subset_cff1_desubr);
+  hb_test_add (test_subset_cff1_desubr_strip_hints);
   hb_test_add (test_subset_cff1_j);
+  hb_test_add (test_subset_cff1_j_strip_hints);
+  hb_test_add (test_subset_cff1_j_desubr);
+  hb_test_add (test_subset_cff1_j_desubr_strip_hints);
   hb_test_add (test_subset_cff1_expert);
 
   return hb_test_run ();