Merge branch 'master' into bitops
diff --git a/TODO b/TODO
index 4f37f60..53ffbe9 100644
--- a/TODO
+++ b/TODO
@@ -1,24 +1,14 @@
 General fixes:
 =============
 
-- AAT 'morx' implementation.
-
-- Return "safe-to-break" bit from shaping.
-
 - Implement 'rand' feature.
 
-- mask propagation? (when ligation, "or" the masks).
-
 
 API issues:
 ===========
 
 - API to accept a list of languages?
 
-- Add init_func to font_funcs.  Adjust ft.
-
-- 'const' for getter APIs? (use mutable internally)
-
 - Remove hb_ot_shape_glyphs_closure()?
 
 
@@ -39,7 +29,7 @@
 
 - Add query / enumeration API for aalt-like features?
 
-- SFNT api? get_num_faces? get_table_tags? (there's something in stash)
+- SFNT api? get_num_faces?
 
 - Add segmentation API
 
@@ -50,20 +40,3 @@
 ===============================
 
 - Add --width, --height, --auto-size, --ink-box, --align, etc?
-
-
-Tests to write:
-==============
-
-- ot-layout enumeration API (needs font)
-
-- Finish test-shape.c, grep for TODO
-
-- Finish test-unicode.c, grep for TODO
-
-- GObject, FreeType, etc
-
-- hb_cache_t and relatives
-
-- hb_feature_to/from_string
-- hb_buffer_[sg]et_contents
diff --git a/src/hb-buffer-private.hh b/src/hb-buffer-private.hh
index a72376d..af4767f 100644
--- a/src/hb-buffer-private.hh
+++ b/src/hb-buffer-private.hh
@@ -344,8 +344,7 @@
   inline void
   unsafe_to_break_all (void)
   {
-    for (unsigned int i = 0; i < len; i++)
-      info[i].mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
+    unsafe_to_break_impl (0, len);
   }
   inline void
   safe_to_break_all (void)
diff --git a/src/hb-coretext.cc b/src/hb-coretext.cc
index 752dea8..aba7cf4 100644
--- a/src/hb-coretext.cc
+++ b/src/hb-coretext.cc
@@ -1244,8 +1244,6 @@
 	pos->x_offset = info->var1.i32;
 	pos->y_offset = info->var2.i32;
 
-	info->mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
-
 	info++, pos++;
       }
     else
@@ -1255,8 +1253,6 @@
 	pos->x_offset = info->var1.i32;
 	pos->y_offset = info->var2.i32;
 
-	info->mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
-
 	info++, pos++;
       }
 
diff --git a/src/hb-directwrite.cc b/src/hb-directwrite.cc
index 5429255..69a8aa2 100644
--- a/src/hb-directwrite.cc
+++ b/src/hb-directwrite.cc
@@ -878,8 +878,6 @@
     pos->x_offset =
       x_mult * (isRightToLeft ? -info->var1.i32 : info->var1.i32);
     pos->y_offset = y_mult * info->var2.i32;
-
-    info->mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
   }
 
   if (isRightToLeft)
diff --git a/src/hb-graphite2.cc b/src/hb-graphite2.cc
index 3b55b47..46fe139 100644
--- a/src/hb-graphite2.cc
+++ b/src/hb-graphite2.cc
@@ -360,7 +360,6 @@
       hb_glyph_info_t *info = &buffer->info[clusters[i].base_glyph + j];
       info->codepoint = gids[clusters[i].base_glyph + j];
       info->cluster = clusters[i].cluster;
-      info->mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
       info->var1.i32 = clusters[i].advance;     // all glyphs in the cluster get the same advance
     }
   }
diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh
index e6b07a8..a73fd4a 100644
--- a/src/hb-ot-glyf-table.hh
+++ b/src/hb-ot-glyf-table.hh
@@ -81,9 +81,9 @@
   struct GlyphHeader
   {
     HBINT16		numberOfContours;	/* If the number of contours is
-					   * greater than or equal to zero,
-					   * this is a simple glyph; if negative,
-					   * this is a composite glyph. */
+                                                 * greater than or equal to zero,
+                                                 * this is a simple glyph; if negative,
+                                                 * this is a composite glyph. */
     FWORD		xMin;			/* Minimum x for coordinate data. */
     FWORD		yMin;			/* Minimum y for coordinate data. */
     FWORD		xMax;			/* Maximum x for coordinate data. */
@@ -92,6 +92,102 @@
     DEFINE_SIZE_STATIC (10);
   };
 
+  struct CompositeGlyphHeader
+  {
+    static const uint16_t ARG_1_AND_2_ARE_WORDS =      0x0001;
+    static const uint16_t ARGS_ARE_XY_VALUES =         0x0002;
+    static const uint16_t ROUND_XY_TO_GRID =           0x0004;
+    static const uint16_t WE_HAVE_A_SCALE =            0x0008;
+    static const uint16_t MORE_COMPONENTS =            0x0020;
+    static const uint16_t WE_HAVE_AN_X_AND_Y_SCALE =   0x0040;
+    static const uint16_t WE_HAVE_A_TWO_BY_TWO =       0x0080;
+    static const uint16_t WE_HAVE_INSTRUCTIONS =       0x0100;
+    static const uint16_t USE_MY_METRICS =             0x0200;
+    static const uint16_t OVERLAP_COMPOUND =           0x0400;
+    static const uint16_t SCALED_COMPONENT_OFFSET =    0x0800;
+    static const uint16_t UNSCALED_COMPONENT_OFFSET =  0x1000;
+
+    HBUINT16 flags;
+    HBUINT16 glyphIndex;
+
+    inline unsigned int get_size (void) const
+    {
+      unsigned int size = min_size;
+      if (flags & ARG_1_AND_2_ARE_WORDS) {
+        // arg1 and 2 are int16
+        size += 4;
+      } else {
+        // arg1 and 2 are int8
+        size += 2;
+      }
+      if (flags & WE_HAVE_A_SCALE) {
+        // One x 16 bit (scale)
+        size += 2;
+      } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) {
+        // Two x 16 bit (xscale, yscale)
+        size += 4;
+      } else if (flags & WE_HAVE_A_TWO_BY_TWO) {
+        // Four x 16 bit (xscale, scale01, scale10, yscale)
+        size += 8;
+      }
+      return size;
+    }
+
+    struct Iterator
+    {
+      const char *glyph_start;
+      const char *glyph_end;
+      const CompositeGlyphHeader *current;
+
+      inline bool move_to_next ()
+      {
+	if (current->flags & CompositeGlyphHeader::MORE_COMPONENTS)
+	{
+	  const CompositeGlyphHeader *possible =
+	    &StructAfter<CompositeGlyphHeader, CompositeGlyphHeader> (*current);
+	  if (!in_range (possible))
+	    return false;
+	  current = possible;
+	  return true;
+	}
+	return false;
+      }
+
+      inline bool in_range (const CompositeGlyphHeader *composite) const
+      {
+	return (const char *) composite >= glyph_start
+	  && ((const char *) composite + CompositeGlyphHeader::min_size) <= glyph_end
+	  && ((const char *) composite + composite->get_size()) <= glyph_end;
+      }
+    };
+
+    static inline bool get_iterator (const char * glyph_data,
+				     unsigned int length,
+				     CompositeGlyphHeader::Iterator *iterator /* OUT */)
+    {
+      if (length < GlyphHeader::static_size)
+	return false; /* Empty glyph; zero extents. */
+
+      const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyph_data, 0);
+      if (glyph_header.numberOfContours < 0)
+      {
+        const CompositeGlyphHeader *possible =
+	  &StructAfter<CompositeGlyphHeader, GlyphHeader> (glyph_header);
+
+	iterator->glyph_start = glyph_data;
+	iterator->glyph_end = (const char *) glyph_data + length;
+	if (!iterator->in_range (possible))
+          return false;
+        iterator->current = possible;
+        return true;
+      }
+
+      return false;
+    }
+
+    DEFINE_SIZE_MIN (4);
+  };
+
   struct accelerator_t
   {
     inline void init (hb_face_t *face)
@@ -122,6 +218,23 @@
       hb_blob_destroy (glyf_blob);
     }
 
+    /*
+     * Returns true if the referenced glyph is a valid glyph and a composite glyph.
+     * If true is returned a pointer to the composite glyph will be written into
+     * composite.
+     */
+    inline bool get_composite (hb_codepoint_t glyph,
+			       CompositeGlyphHeader::Iterator *composite /* OUT */) const
+    {
+      unsigned int start_offset, end_offset;
+      if (!get_offsets (glyph, &start_offset, &end_offset))
+        return false; /* glyph not found */
+
+      return CompositeGlyphHeader::get_iterator ((const char*) this->glyf_table + start_offset,
+						 end_offset - start_offset,
+						 composite);
+    }
+
     inline bool get_offsets (hb_codepoint_t  glyph,
                              unsigned int   *start_offset /* OUT */,
                              unsigned int   *end_offset   /* OUT */) const
diff --git a/src/hb-ot-os2-table.hh b/src/hb-ot-os2-table.hh
index 5f4e2db..2d9d214 100644
--- a/src/hb-ot-os2-table.hh
+++ b/src/hb-ot-os2-table.hh
@@ -100,47 +100,47 @@
   HBUINT16	version;
 
   /* Version 0 */
-  HBINT16		xAvgCharWidth;
+  HBINT16	xAvgCharWidth;
   HBUINT16	usWeightClass;
   HBUINT16	usWidthClass;
   HBUINT16	fsType;
-  HBINT16		ySubscriptXSize;
-  HBINT16		ySubscriptYSize;
-  HBINT16		ySubscriptXOffset;
-  HBINT16		ySubscriptYOffset;
-  HBINT16		ySuperscriptXSize;
-  HBINT16		ySuperscriptYSize;
-  HBINT16		ySuperscriptXOffset;
-  HBINT16		ySuperscriptYOffset;
-  HBINT16		yStrikeoutSize;
-  HBINT16		yStrikeoutPosition;
-  HBINT16		sFamilyClass;
-  HBUINT8		panose[10];
-  HBUINT32		ulUnicodeRange[4];
+  HBINT16	ySubscriptXSize;
+  HBINT16	ySubscriptYSize;
+  HBINT16	ySubscriptXOffset;
+  HBINT16	ySubscriptYOffset;
+  HBINT16	ySuperscriptXSize;
+  HBINT16	ySuperscriptYSize;
+  HBINT16	ySuperscriptXOffset;
+  HBINT16	ySuperscriptYOffset;
+  HBINT16	yStrikeoutSize;
+  HBINT16	yStrikeoutPosition;
+  HBINT16	sFamilyClass;
+  HBUINT8	panose[10];
+  HBUINT32	ulUnicodeRange[4];
   Tag		achVendID;
   HBUINT16	fsSelection;
   HBUINT16	usFirstCharIndex;
   HBUINT16	usLastCharIndex;
-  HBINT16		sTypoAscender;
-  HBINT16		sTypoDescender;
-  HBINT16		sTypoLineGap;
+  HBINT16	sTypoAscender;
+  HBINT16	sTypoDescender;
+  HBINT16	sTypoLineGap;
   HBUINT16	usWinAscent;
   HBUINT16	usWinDescent;
 
   /* Version 1 */
-  //HBUINT32 ulCodePageRange1;
-  //HBUINT32 ulCodePageRange2;
+  //HBUINT32	ulCodePageRange1;
+  //HBUINT32	ulCodePageRange2;
 
   /* Version 2 */
-  //HBINT16 sxHeight;
-  //HBINT16 sCapHeight;
-  //HBUINT16  usDefaultChar;
-  //HBUINT16  usBreakChar;
-  //HBUINT16  usMaxContext;
+  //HBINT16	sxHeight;
+  //HBINT16	sCapHeight;
+  //HBUINT16	usDefaultChar;
+  //HBUINT16	usBreakChar;
+  //HBUINT16	usMaxContext;
 
   /* Version 5 */
-  //HBUINT16  usLowerOpticalPointSize;
-  //HBUINT16  usUpperOpticalPointSize;
+  //HBUINT16	usLowerOpticalPointSize;
+  //HBUINT16	usUpperOpticalPointSize;
 
   public:
   DEFINE_SIZE_STATIC (78);
diff --git a/src/hb-subset-glyf.cc b/src/hb-subset-glyf.cc
index f1bca10..7dfe0ba 100644
--- a/src/hb-subset-glyf.cc
+++ b/src/hb-subset-glyf.cc
@@ -28,6 +28,7 @@
 #include "hb-ot-glyf-table.hh"
 #include "hb-set.h"
 #include "hb-subset-glyf.hh"
+#include "hb-subset-plan.hh"
 
 static bool
 _calculate_glyf_and_loca_prime_size (const OT::glyf::accelerator_t &glyf,
@@ -70,16 +71,41 @@
   }
 }
 
+static void
+_update_components (hb_subset_plan_t * plan,
+		    char * glyph_start,
+		    unsigned int length)
+
+{
+  OT::glyf::CompositeGlyphHeader::Iterator iterator;
+  if (OT::glyf::CompositeGlyphHeader::get_iterator (glyph_start,
+						    length,
+						    &iterator))
+  {
+    do
+    {
+      hb_codepoint_t new_gid;
+      if (!hb_subset_plan_new_gid_for_old_id (plan,
+					      iterator.current->glyphIndex,
+					      &new_gid))
+	continue;
+
+      ((OT::glyf::CompositeGlyphHeader *) iterator.current)->glyphIndex.set (new_gid);
+    } while (iterator.move_to_next());
+  }
+}
+
 static bool
-_write_glyf_and_loca_prime (const OT::glyf::accelerator_t &glyf,
+_write_glyf_and_loca_prime (hb_subset_plan_t              *plan,
+			    const OT::glyf::accelerator_t &glyf,
                             const char                    *glyf_data,
-                            hb_prealloced_array_t<hb_codepoint_t> &glyph_ids,
                             bool                           use_short_loca,
                             int                            glyf_prime_size,
                             char                          *glyf_prime_data /* OUT */,
                             int                            loca_prime_size,
                             char                          *loca_prime_data /* OUT */)
 {
+  hb_prealloced_array_t<hb_codepoint_t> &glyph_ids = plan->gids_to_retain_sorted;
   char *glyf_prime_data_next = glyf_prime_data;
 
   for (unsigned int i = 0; i < glyph_ids.len; i++)
@@ -92,6 +118,7 @@
     memcpy (glyf_prime_data_next, glyf_data + start_offset, length);
 
     _write_loca_entry (i, glyf_prime_data_next - glyf_prime_data, use_short_loca, loca_prime_data);
+    _update_components (plan, glyf_prime_data_next, end_offset - start_offset);
 
     glyf_prime_data_next += length;
   }
@@ -104,7 +131,7 @@
 static bool
 _hb_subset_glyf_and_loca (const OT::glyf::accelerator_t  &glyf,
                           const char                     *glyf_data,
-                          hb_prealloced_array_t<hb_codepoint_t>&glyphs_to_retain,
+			  hb_subset_plan_t               *plan,
                           bool                           *use_short_loca,
                           hb_blob_t                     **glyf_prime /* OUT */,
                           hb_blob_t                     **loca_prime /* OUT */)
@@ -112,6 +139,7 @@
   // TODO(grieger): Sanity check writes to make sure they are in-bounds.
   // TODO(grieger): Sanity check allocation size for the new table.
   // TODO(grieger): Don't fail on bad offsets, just dump them.
+  hb_prealloced_array_t<hb_codepoint_t> &glyphs_to_retain = plan->gids_to_retain_sorted;
 
   unsigned int glyf_prime_size;
   unsigned int loca_prime_size;
@@ -126,7 +154,7 @@
 
   char *glyf_prime_data = (char *) malloc (glyf_prime_size);
   char *loca_prime_data = (char *) malloc (loca_prime_size);
-  if (unlikely (!_write_glyf_and_loca_prime (glyf, glyf_data, glyphs_to_retain,
+  if (unlikely (!_write_glyf_and_loca_prime (plan, glyf, glyf_data,
                                              *use_short_loca,
                                              glyf_prime_size, glyf_prime_data,
                                              loca_prime_size, loca_prime_data))) {
@@ -168,7 +196,7 @@
   glyf.init(plan->source);
   bool result = _hb_subset_glyf_and_loca (glyf,
                                           glyf_data,
-                                          plan->gids_to_retain_sorted,
+                                          plan,
                                           use_short_loca,
                                           glyf_prime,
                                           loca_prime);
diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc
index 034180a..b9e299a 100644
--- a/src/hb-subset-plan.cc
+++ b/src/hb-subset-plan.cc
@@ -28,6 +28,7 @@
 
 #include "hb-subset-plan.hh"
 #include "hb-ot-cmap-table.hh"
+#include "hb-ot-glyf-table.hh"
 
 static int
 _hb_codepoint_t_cmp (const void *pa, const void *pb)
@@ -62,10 +63,11 @@
                                    hb_codepoint_t *new_gid)
 {
   // the index in old_gids is the new gid; only up to codepoints.len are valid
-  for (unsigned int i = 0; i < plan->gids_to_retain.len; i++) {
-    if (plan->gids_to_retain[i] == old_gid) {
-      // +1: assign new gids from 1..N; 0 is special
-      *new_gid = i + 1;
+  for (unsigned int i = 0; i < plan->gids_to_retain_sorted.len; i++)
+  {
+    if (plan->gids_to_retain_sorted[i] == old_gid)
+    {
+      *new_gid = i;
       return true;
     }
   }
@@ -94,32 +96,54 @@
 }
 
 static void
+_add_gid_and_children (const OT::glyf::accelerator_t &glyf,
+		       hb_codepoint_t gid,
+		       hb_set_t *gids_to_retain)
+{
+  if (hb_set_has (gids_to_retain, gid))
+    // Already visited this gid, ignore.
+    return;
+
+  hb_set_add (gids_to_retain, gid);
+
+  OT::glyf::CompositeGlyphHeader::Iterator composite;
+  if (glyf.get_composite (gid, &composite))
+  {
+    do
+    {
+      _add_gid_and_children (glyf, (hb_codepoint_t) composite.current->glyphIndex, gids_to_retain);
+    } while (composite.move_to_next());
+  }
+}
+
+static void
 _populate_gids_to_retain (hb_face_t *face,
                           hb_prealloced_array_t<hb_codepoint_t>& codepoints,
                           hb_prealloced_array_t<hb_codepoint_t>& old_gids,
                           hb_prealloced_array_t<hb_codepoint_t>& old_gids_sorted)
 {
   OT::cmap::accelerator_t cmap;
+  OT::glyf::accelerator_t glyf;
   cmap.init (face);
+  glyf.init (face);
 
   hb_auto_array_t<unsigned int> bad_indices;
 
   old_gids.alloc (codepoints.len);
-  bool has_zero = false;
-  for (unsigned int i = 0; i < codepoints.len; i++) {
+  for (unsigned int i = 0; i < codepoints.len; i++)
+  {
     hb_codepoint_t gid;
-    if (!cmap.get_nominal_glyph (codepoints[i], &gid)) {
+    if (!cmap.get_nominal_glyph (codepoints[i], &gid))
+    {
       gid = -1;
       *(bad_indices.push ()) = i;
     }
-    if (gid == 0) {
-      has_zero = true;
-    }
     *(old_gids.push ()) = gid;
   }
 
   /* Generally there shouldn't be any */
-  while (bad_indices.len > 0) {
+  while (bad_indices.len > 0)
+  {
     unsigned int i = bad_indices[bad_indices.len - 1];
     bad_indices.pop ();
     DEBUG_MSG(SUBSET, nullptr, "Drop U+%04X; no gid", codepoints[i]);
@@ -127,19 +151,21 @@
     old_gids.remove (i);
   }
 
-  // Populate a second glyph id array that is sorted by glyph id
-  // and is gauranteed to contain 0.
-  old_gids_sorted.alloc (old_gids.len + (has_zero ? 0 : 1));
-  for (unsigned int i = 0; i < old_gids.len; i++) {
-    *(old_gids_sorted.push ()) = old_gids[i];
-  }
-  if (!has_zero)
-    *(old_gids_sorted.push ()) = 0;
-  old_gids_sorted.qsort (_hb_codepoint_t_cmp);
-
-  // TODO(Q1) expand with glyphs that make up complex glyphs
+  // Populate a full set of glyphs to retain by adding all referenced
+  // composite glyphs.
   // TODO expand with glyphs reached by G*
-  //
+  hb_set_t * all_gids_to_retain = hb_set_create ();
+  _add_gid_and_children (glyf, 0, all_gids_to_retain);
+  for (unsigned int i = 0; i < old_gids.len; i++)
+    _add_gid_and_children (glyf, old_gids[i], all_gids_to_retain);
+
+  // Transfer to a sorted list.
+  old_gids_sorted.alloc (hb_set_get_population (all_gids_to_retain));
+  hb_codepoint_t gid = HB_SET_VALUE_INVALID;
+  while (hb_set_next (all_gids_to_retain, &gid))
+    *(old_gids_sorted.push ()) = gid;
+
+  glyf.fini ();
   cmap.fini ();
 }
 
diff --git a/src/hb-subset-plan.hh b/src/hb-subset-plan.hh
index 9a4308f..b656faa 100644
--- a/src/hb-subset-plan.hh
+++ b/src/hb-subset-plan.hh
@@ -38,8 +38,14 @@
   // TODO(Q1) actual map, drop this crap
   // Look at me ma, I'm a poor mans map codepoint : new gid
   // codepoints is sorted and aligned with gids_to_retain.
+
+  // These first two lists provide a mapping from cp -> gid
+  // As a result it does not list the full set of glyphs to retain.
   hb_prealloced_array_t<hb_codepoint_t> codepoints;
   hb_prealloced_array_t<hb_codepoint_t> gids_to_retain;
+
+  // This list contains the complete set of glyphs to retain and may contain
+  // more glyphs then the lists above.
   hb_prealloced_array_t<hb_codepoint_t> gids_to_retain_sorted;
 
   // Plan is only good for a specific source/dest so keep them with it
diff --git a/src/hb-uniscribe.cc b/src/hb-uniscribe.cc
index 5e05baa..cd25769 100644
--- a/src/hb-uniscribe.cc
+++ b/src/hb-uniscribe.cc
@@ -1025,8 +1025,6 @@
     pos->x_advance = x_mult * (int32_t) info->mask;
     pos->x_offset = x_mult * (backward ? -info->var1.i32 : info->var1.i32);
     pos->y_offset = y_mult * info->var2.i32;
-
-    info->mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
   }
 
   if (backward)
diff --git a/test/api/Makefile.am b/test/api/Makefile.am
index 358cd57..ecf4475 100644
--- a/test/api/Makefile.am
+++ b/test/api/Makefile.am
@@ -12,6 +12,8 @@
 
 EXTRA_DIST += CMakeLists.txt
 
+EXTRA_DIST += fonts
+
 if HAVE_GLIB
 AM_CPPFLAGS = -DSRCDIR="\"$(srcdir)\"" -I$(top_srcdir)/src/ -I$(top_builddir)/src/ $(GLIB_CFLAGS)
 LDADD = $(top_builddir)/src/libharfbuzz.la $(GLIB_LIBS)
@@ -66,25 +68,6 @@
 	$(NULL)
 test_ot_math_LDADD = $(LDADD) $(FREETYPE_LIBS)
 test_ot_math_CPPFLAGS = $(AM_CPPFLAGS) $(FREETYPE_CFLAGS)
-EXTRA_DIST += \
-	fonts/Inconsolata-Regular.ab.ttf \
-	fonts/Inconsolata-Regular.abc.ttf \
-	fonts/Inconsolata-Regular.abc.widerc.ttf \
-	fonts/Inconsolata-Regular.ac.ttf \
-	fonts/Inconsolata-Regular.ac.widerc.ttf \
-	fonts/Roboto-Regular.abc.cmap-format12-only.ttf \
-	fonts/Roboto-Regular.ac.cmap-format12-only.ttf \
-	fonts/Roboto-Regular.b.ttf \
-	fonts/Roboto-Regular.abc.ttf \
-	fonts/Roboto-Regular.ac.ttf \
-	fonts/MathTestFontEmpty.otf \
-	fonts/MathTestFontFull.otf \
-	fonts/MathTestFontNone.otf \
-	fonts/MathTestFontPartial1.otf \
-	fonts/MathTestFontPartial2.otf \
-	fonts/MathTestFontPartial3.otf \
-	fonts/MathTestFontPartial4.otf \
-	$(NULL)
 endif # HAVE_FREETYPE
 
 endif # HAVE_OT
diff --git a/test/api/fonts/Roboto-Regular.components.subset.ttf b/test/api/fonts/Roboto-Regular.components.subset.ttf
new file mode 100644
index 0000000..e759d77
--- /dev/null
+++ b/test/api/fonts/Roboto-Regular.components.subset.ttf
Binary files differ
diff --git a/test/api/fonts/Roboto-Regular.components.ttf b/test/api/fonts/Roboto-Regular.components.ttf
new file mode 100644
index 0000000..816e3a2
--- /dev/null
+++ b/test/api/fonts/Roboto-Regular.components.ttf
Binary files differ
diff --git a/test/api/test-subset-glyf.c b/test/api/test-subset-glyf.c
index 3c9d8fe..96e37bb 100644
--- a/test/api/test-subset-glyf.c
+++ b/test/api/test-subset-glyf.c
@@ -53,6 +53,26 @@
 }
 
 static void
+test_subset_glyf_with_components (void)
+{
+  hb_face_t *face_components = hb_subset_test_open_font ("fonts/Roboto-Regular.components.ttf");
+  hb_face_t *face_subset = hb_subset_test_open_font ("fonts/Roboto-Regular.components.subset.ttf");
+
+  hb_set_t *codepoints = hb_set_create();
+  hb_set_add (codepoints, 0x1fc);
+  hb_face_t *face_generated_subset = hb_subset_test_create_subset (face_components, codepoints);
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_subset, face_generated_subset, HB_TAG ('g','l','y','f'));
+  hb_subset_test_check (face_subset, face_generated_subset, HB_TAG ('l','o','c', 'a'));
+  hb_subset_test_check (face_subset, face_generated_subset, HB_TAG ('m','a','x', 'p'));
+
+  hb_face_destroy (face_generated_subset);
+  hb_face_destroy (face_subset);
+  hb_face_destroy (face_components);
+}
+
+static void
 test_subset_glyf_noop (void)
 {
   hb_face_t *face_abc = hb_subset_test_open_font("fonts/Roboto-Regular.abc.ttf");
@@ -79,6 +99,7 @@
   hb_test_init (&argc, &argv);
 
   hb_test_add (test_subset_glyf);
+  hb_test_add (test_subset_glyf_with_components);
   hb_test_add (test_subset_glyf_noop);
 
   return hb_test_run();
diff --git a/test/api/test-subset-hmtx.c b/test/api/test-subset-hmtx.c
index 099b57d..36d7d9e 100644
--- a/test/api/test-subset-hmtx.c
+++ b/test/api/test-subset-hmtx.c
@@ -37,7 +37,6 @@
   hb_blob_t *hmtx_blob = hb_face_reference_table (face, HB_TAG ('h','m','t','x'));
 
   // TODO I sure wish I could just use the hmtx table struct!
-  unsigned int hmtx_len = hb_blob_get_length(hmtx_blob);
   unsigned int hhea_len;
   uint8_t *raw_hhea = (uint8_t *) hb_blob_get_data(hhea_blob, &hhea_len);
   uint16_t num_hmetrics = (raw_hhea[hhea_len - 2] << 8) + raw_hhea[hhea_len - 1];