Add retain_gids option to subset input. Update glyf and loca handling to respect...
authorGarret Rieger <grieger@google.com>
Fri, 18 Jan 2019 02:55:56 +0000 (18:55 -0800)
committerGarret Rieger <grieger@google.com>
Tue, 29 Jan 2019 21:19:21 +0000 (13:19 -0800)
src/hb-subset-glyf.cc
src/hb-subset-input.cc
src/hb-subset-input.hh
src/hb-subset-plan.cc
src/hb-subset.h

index cca364d..e922285 100644 (file)
@@ -32,6 +32,7 @@
 static bool
 _calculate_glyf_and_loca_prime_size (const OT::glyf::accelerator_t &glyf,
                                     hb_vector_t<hb_codepoint_t> &glyph_ids,
+                                    const hb_map_t *glyph_map,
                                     hb_bool_t drop_hints,
                                     bool *use_short_loca /* OUT */,
                                     unsigned int *glyf_size /* OUT */,
@@ -39,9 +40,12 @@ _calculate_glyf_and_loca_prime_size (const OT::glyf::accelerator_t &glyf,
                                     hb_vector_t<unsigned int> *instruction_ranges /* OUT */)
 {
   unsigned int total = 0;
+  hb_codepoint_t max_new_gid = 0;
   for (unsigned int i = 0; i < glyph_ids.length; i++)
   {
     hb_codepoint_t next_glyph = glyph_ids[i];
+    hb_codepoint_t next_glyph_new_gid = glyph_map->get (next_glyph);
+    max_new_gid = MAX (max_new_gid, next_glyph_new_gid);
     if (!instruction_ranges->resize (instruction_ranges->length + 2))
     {
       DEBUG_MSG(SUBSET, nullptr, "Failed to resize instruction_ranges.");
@@ -79,7 +83,7 @@ _calculate_glyf_and_loca_prime_size (const OT::glyf::accelerator_t &glyf,
 
   *glyf_size = total;
   *use_short_loca = (total <= 131070);
-  *loca_size = (glyph_ids.length + 1)
+  *loca_size = (max_new_gid + 2)
       * (*use_short_loca ? sizeof (OT::HBUINT16) : sizeof (OT::HBUINT32));
 
   DEBUG_MSG(SUBSET, nullptr, "preparing to subset glyf: final size %d, loca size %d, using %s loca",
@@ -117,9 +121,9 @@ _write_loca_entry (unsigned int  id,
 }
 
 static void
-_update_components (hb_subset_plan_t * plan,
-                   char glyph_start,
-                   unsigned int length)
+_update_components (const hb_subset_plan_t *plan,
+                   char                   *glyph_start,
+                   unsigned int            length)
 {
   OT::glyf::CompositeGlyphHeader::Iterator iterator;
   if (OT::glyf::CompositeGlyphHeader::get_iterator (glyph_start,
@@ -153,22 +157,37 @@ static bool _remove_composite_instruction_flag (char *glyf_prime, unsigned int l
 }
 
 static bool
-_write_glyf_and_loca_prime (hb_subset_plan_t              *plan,
+_write_glyf_and_loca_prime (const hb_subset_plan_t        *plan,
                            const OT::glyf::accelerator_t &glyf,
                            const char                    *glyf_data,
                            bool                           use_short_loca,
-                           hb_vector_t<unsigned int> &instruction_ranges,
+                           hb_vector_t<unsigned int>     &instruction_ranges,
                            unsigned int                   glyf_prime_size,
                            char                          *glyf_prime_data /* OUT */,
                            unsigned int                   loca_prime_size,
                            char                          *loca_prime_data /* OUT */)
 {
-  hb_vector_t<hb_codepoint_t> &glyph_ids = plan->glyphs;
+  const hb_vector_t<hb_codepoint_t> &glyph_ids = plan->glyphs;
+  const hb_map_t *glyph_map = plan->glyph_map;
   char *glyf_prime_data_next = glyf_prime_data;
 
   bool success = true;
+  hb_codepoint_t gid = 0;
   for (unsigned int i = 0; i < glyph_ids.length; i++)
   {
+    while (gid < glyph_map->get (glyph_ids[i]))
+    {
+      // If we are retaining existing gids then there will potentially be gaps
+      // in the loca table between glyphs. Fill in this gap with glyphs that have
+      // no outlines.
+      success = success && _write_loca_entry (gid,
+                                             glyf_prime_data_next - glyf_prime_data,
+                                             use_short_loca,
+                                             loca_prime_data,
+                                             loca_prime_size);
+      gid++;
+    }
+
     unsigned int start_offset, end_offset;
     if (unlikely (!(glyf.get_offsets (glyph_ids[i], &start_offset, &end_offset) &&
                    glyf.remove_padding (start_offset, &end_offset))))
@@ -204,7 +223,7 @@ _write_glyf_and_loca_prime (hb_subset_plan_t              *plan,
        memset (glyf_prime_data_next + instruction_start - start_offset - 2, 0, 2);
     }
 
-    success = success && _write_loca_entry (i,
+    success = success && _write_loca_entry (gid,
                                            glyf_prime_data_next - glyf_prime_data,
                                            use_short_loca,
                                            loca_prime_data,
@@ -213,9 +232,10 @@ _write_glyf_and_loca_prime (hb_subset_plan_t              *plan,
 
     // TODO: don't align to two bytes if using long loca.
     glyf_prime_data_next += length + (length % 2); // Align to 2 bytes for short loca.
+    gid++;
   }
 
-  success = success && _write_loca_entry (glyph_ids.length,
+  success = success && _write_loca_entry (gid,
                                          glyf_prime_data_next - glyf_prime_data,
                                          use_short_loca,
                                          loca_prime_data,
@@ -241,6 +261,7 @@ _hb_subset_glyf_and_loca (const OT::glyf::accelerator_t  &glyf,
 
   if (unlikely (!_calculate_glyf_and_loca_prime_size (glyf,
                                                      glyphs_to_retain,
+                                                     plan->glyph_map,
                                                      plan->drop_hints,
                                                      use_short_loca,
                                                      &glyf_prime_size,
index f718a56..693c9c2 100644 (file)
@@ -44,7 +44,10 @@ hb_subset_input_create_or_fail ()
 
   input->unicodes = hb_set_create ();
   input->glyphs = hb_set_create ();
+  input->drop_hints = false;
   input->drop_layout = true;
+  input->desubroutinize = false;
+  input->retain_gids = false;
 
   return input;
 }
@@ -144,3 +147,27 @@ hb_subset_input_get_desubroutinize (hb_subset_input_t *subset_input)
 {
   return subset_input->desubroutinize;
 }
+
+/**
+ * hb_subset_input_set_retain_gids:
+ * @subset_input: a subset_input.
+ * @retain_gids: If true the subsetter will not renumber glyph ids.
+ * Since: REPLACEME
+ **/
+HB_EXTERN void
+hb_subset_input_set_retain_gids (hb_subset_input_t *subset_input,
+                                hb_bool_t retain_gids)
+{
+  subset_input->retain_gids = retain_gids;
+}
+
+/**
+ * hb_subset_input_get_retain_gids:
+ * Returns: value of retain_gids.
+ * Since: REPLACEME
+ **/
+HB_EXTERN hb_bool_t
+hb_subset_input_get_retain_gids (hb_subset_input_t *subset_input)
+{
+  return subset_input->retain_gids;
+}
index 8dad94f..04d6e12 100644 (file)
@@ -44,6 +44,7 @@ struct hb_subset_input_t
   bool drop_hints : 1;
   bool drop_layout : 1;
   bool desubroutinize : 1;
+  bool retain_gids : 1;
   /* TODO
    *
    * features
index cff3426..7060dc9 100644 (file)
@@ -156,11 +156,15 @@ _populate_gids_to_retain (hb_face_t *face,
 }
 
 static void
-_create_old_gid_to_new_gid_map (const hb_vector_t<hb_codepoint_t> &glyphs,
-                               hb_map_t *glyph_map)
+_create_old_gid_to_new_gid_map (bool retain_gids,
+                               const hb_vector_t<hb_codepoint_t> &glyphs,
+                                hb_map_t *glyph_map)
 {
   for (unsigned int i = 0; i < glyphs.length; i++) {
-    glyph_map->set (glyphs[i], i);
+    if (!retain_gids)
+      glyph_map->set (glyphs[i], i);
+    else
+      glyph_map->set (glyphs[i], glyphs[i]);
   }
 }
 
@@ -195,7 +199,9 @@ hb_subset_plan_create (hb_face_t           *face,
                                             plan->unicodes,
                                             plan->codepoint_to_glyph,
                                             &plan->glyphs);
-  _create_old_gid_to_new_gid_map (plan->glyphs,
+
+  _create_old_gid_to_new_gid_map (input->retain_gids,
+                                 plan->glyphs,
                                  plan->glyph_map);
 
   return plan;
index f582e46..657709e 100644 (file)
@@ -72,6 +72,12 @@ hb_subset_input_set_desubroutinize (hb_subset_input_t *subset_input,
 HB_EXTERN hb_bool_t
 hb_subset_input_get_desubroutinize (hb_subset_input_t *subset_input);
 
+HB_EXTERN void
+hb_subset_input_set_retain_gids (hb_subset_input_t *subset_input,
+                                hb_bool_t retain_gids);
+HB_EXTERN hb_bool_t
+hb_subset_input_get_retain_gids (hb_subset_input_t *subset_input);
+
 /* hb_subset () */
 HB_EXTERN hb_face_t *
 hb_subset (hb_face_t *source, hb_subset_input_t *input);