Add implementation of glyf subsetting.
authorGarret Rieger <grieger@google.com>
Wed, 7 Feb 2018 21:09:54 +0000 (13:09 -0800)
committerBehdad Esfahbod <behdad@behdad.org>
Wed, 7 Feb 2018 23:28:43 +0000 (17:28 -0600)
src/hb-subset-glyf.cc

index 5a3dff6d91feca7c310112025804c0d4a8f28e60..e0ae5d8081ed4119cfc6fd1fe1bc20d5b329cd14 100644 (file)
  * Google Author(s): Garret Rieger
  */
 
+#include "hb-open-type-private.hh"
 #include "hb-ot-glyf-table.hh"
+#include "hb-set.h"
 #include "hb-subset-glyf.hh"
 
+bool
+calculate_glyf_prime_size (const OT::glyf::accelerator_t &glyf,
+                           hb_set_t *glyph_ids,
+                           unsigned int *size /* OUT */)
+{
+  unsigned int total = 0;
+  hb_codepoint_t next_glyph = -1;
+  while (hb_set_next(glyph_ids, &next_glyph)) {
+    unsigned int start_offset, end_offset;
+    if (!glyf.get_offsets (next_glyph, &start_offset, &end_offset)) {
+      *size = 0;
+      return false;
+    }
+
+    total += end_offset - start_offset;
+  }
+
+  *size = total;
+  return true;
+}
+
+bool
+write_glyf_prime (const OT::glyf::accelerator_t &glyf,
+                  const char                    *glyf_data,
+                  hb_set_t                      *glyph_ids,
+                  int                            glyf_prime_size,
+                  char                          *glyf_prime_data /* OUT */)
+{
+  char *glyf_prime_data_next = glyf_prime_data;
+
+  hb_codepoint_t next_glyph = -1;
+  while (hb_set_next(glyph_ids, &next_glyph)) {
+    unsigned int start_offset, end_offset;
+    if (!glyf.get_offsets (next_glyph, &start_offset, &end_offset)) {
+      return false;
+    }
+
+    int length = end_offset - start_offset;
+    memcpy (glyf_prime_data_next, glyf_data + start_offset, length);
+    glyf_prime_data_next += length;
+  }
+
+  return true;
+}
+
 /**
  * hb_subset_glyf:
  * Subsets the glyph table according to a provided plan.
@@ -40,13 +87,37 @@ hb_subset_glyf (hb_subset_plan_t *plan,
                 hb_face_t        *face,
                 hb_blob_t       **glyf_prime /* OUT */)
 {
-  OT::glyf::accelerator_t glyf_accelerator;
-  glyf_accelerator.init(face);
+  // TODO(grieger): Sanity check writes to make sure they are in-bounds.
+  // TODO(grieger): Sanity check allocation size for the new table.
+  // TODO(grieger): Subset loca simultaneously.
+
+  hb_blob_t *glyf_blob = OT::Sanitizer<OT::glyf>().sanitize (face->reference_table (HB_OT_TAG_glyf));
+  const char *glyf_data = hb_blob_get_data(glyf_blob, nullptr);
+
+  OT::glyf::accelerator_t glyf;
+  glyf.init(face);
 
-  // TODO
+  unsigned int glyf_prime_size;
+  if (!calculate_glyf_prime_size (glyf,
+                                  plan->glyphs_to_retain,
+                                  &glyf_prime_size)) {
+    glyf.fini();
+    return false;
+  }
 
-  glyf_accelerator.fini();
+  char *glyf_prime_data = (char *) calloc (glyf_prime_size, 1);
+  if (!write_glyf_prime (glyf, glyf_data, plan->glyphs_to_retain, glyf_prime_size,
+                         glyf_prime_data)) {
+    glyf.fini();
+    free (glyf_prime_data);
+    return false;
+  }
 
-  *glyf_prime = hb_blob_get_empty ();
+  glyf.fini();
+  *glyf_prime = hb_blob_create (glyf_prime_data,
+                                glyf_prime_size,
+                                HB_MEMORY_MODE_READONLY,
+                                glyf_prime_data,
+                                free);
   return true;
 }