[subset] Add subsetting for GPOS Lookup Type 1: Single Adjustment Positioning Subtable
authorQunxin Liu <qxliu@google.com>
Tue, 2 Jul 2019 23:30:57 +0000 (16:30 -0700)
committerGarret Rieger <grieger@google.com>
Tue, 6 Aug 2019 21:06:35 +0000 (14:06 -0700)
src/hb-ot-layout-gpos-table.hh
test/subset/data/Makefile.am
test/subset/data/Makefile.sources
test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.41,43.otf [new file with mode: 0644]
test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.41,46.otf [new file with mode: 0644]
test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.43,46.otf [new file with mode: 0644]
test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.retain-all-codepoint.otf [new file with mode: 0644]
test/subset/data/fonts/gpos1_2_font.otf [new file with mode: 0644]
test/subset/data/tests/layout.gpos.tests [new file with mode: 0644]

index 5c21980..7d57056 100644 (file)
@@ -236,6 +236,11 @@ struct ValueFormat : HBUINT16
   }
 };
 
+template<typename Iterator>
+static inline void SinglePos_serialize (hb_serialize_context_t *c,
+                                        Iterator it,
+                                        ValueFormat valFormat);
+
 
 struct AnchorFormat1
 {
@@ -496,11 +501,52 @@ struct SinglePosFormat1
     return_trace (true);
   }
 
+  template<typename Iterator,
+          hb_requires (hb_is_iterator (Iterator))>
+  void serialize (hb_serialize_context_t *c,
+                 Iterator it,
+                 ValueFormat valFormat)
+  {
+    if (unlikely (!c->extend_min (*this))) return;
+    if (unlikely (!c->check_assign (valueFormat, valFormat))) return;
+
+    auto vals = hb_second (*it);
+
+    + vals
+    | hb_apply ([=] (const Value& _)
+                {
+                  c->copy (_);
+                })
+    ;
+
+    auto glyphs =
+    + it
+    | hb_map_retains_sorting (hb_first)
+    ;
+
+    coverage.serialize (c, this).serialize (c, glyphs);
+  }
+
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    // TODO(subset)
-    return_trace (false);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    unsigned length = valueFormat.get_len ();
+
+    auto it =
+    + hb_iter (this+coverage)
+    | hb_filter (glyphset)
+    | hb_map_retains_sorting ([&] (hb_codepoint_t p)
+                              {
+                                return hb_pair (glyph_map[p], values.as_array (length));
+                              })
+    ;
+
+    bool ret = bool (it);
+    SinglePos_serialize (c->serializer, it, valueFormat);
+    return_trace (ret);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -552,11 +598,58 @@ struct SinglePosFormat2
     return_trace (true);
   }
 
+  template<typename Iterator,
+          hb_requires (hb_is_iterator (Iterator))>
+  void serialize (hb_serialize_context_t *c,
+                 Iterator it,
+                  ValueFormat valFormat)
+  {
+    if (unlikely (!c->extend_min (*this))) return;
+    if (unlikely (!c->check_assign (valueFormat, valFormat))) return;
+    if (unlikely (!c->check_assign (valueCount, it.len ()))) return;
+    
+    + it
+    | hb_map (hb_second)
+    | hb_apply ([=] (hb_array_t<const Value> val_iter)
+                {
+                  + val_iter
+                  | hb_apply ([=] (const Value& _)
+                              {
+                                c->copy (_);
+                              })
+                  ;
+                })
+    ;
+
+    auto glyphs =
+    + it
+    | hb_map_retains_sorting (hb_first)
+    ;
+    
+    coverage.serialize (c, this).serialize (c, glyphs);
+  }
+
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    // TODO(subset)
-    return_trace (false);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    unsigned sub_length = valueFormat.get_len ();
+    unsigned total_length = (unsigned)valueCount * sub_length;
+
+    auto it =
+    + hb_zip (this+coverage, hb_range ((unsigned) valueCount))
+    | hb_filter (glyphset, hb_first)
+    | hb_map_retains_sorting ([&] (const hb_pair_t<hb_codepoint_t, unsigned>& _)
+                              {
+                                return hb_pair (glyph_map[_.first], values.as_array (total_length).sub_array (_.second * sub_length, sub_length));
+                              })
+    ;
+
+    bool ret = bool (it);
+    SinglePos_serialize (c->serializer, it, valueFormat);
+    return_trace (ret);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -583,6 +676,55 @@ struct SinglePosFormat2
 
 struct SinglePos
 {
+  template<typename Iterator,
+          hb_requires (hb_is_iterator (Iterator))>
+  unsigned get_format (Iterator glyph_val_iter_pairs)
+  {
+    unsigned subset_format = 1;
+    hb_array_t<const Value> first_val_iter = hb_second (*glyph_val_iter_pairs);
+
+    + glyph_val_iter_pairs
+    | hb_map (hb_second)
+    | hb_apply ([&] (hb_array_t<const Value> val_iter)
+                {
+                  + hb_zip (val_iter, first_val_iter)
+                  | hb_apply ([&] (const hb_pair_t<Value, Value>& _)
+                              {
+                                if (_.first != _.second)
+                                {
+                                  subset_format = 2;
+                                  return;
+                                }
+                              })
+                  ;
+                })
+    ;
+
+    return subset_format;
+  }
+
+
+  template<typename Iterator,
+          hb_requires (hb_is_iterator (Iterator))>
+  void serialize (hb_serialize_context_t *c,
+                 Iterator glyph_val_iter_pairs,
+                  ValueFormat valFormat)
+  {
+    if (unlikely (!c->extend_min (u.format))) return;
+    unsigned format = 2;
+
+    if (glyph_val_iter_pairs) format = get_format (glyph_val_iter_pairs);
+
+    u.format = format;
+    switch (u.format) {
+    case 1: u.format1.serialize (c, glyph_val_iter_pairs, valFormat);
+            return;
+    case 2: u.format2.serialize (c, glyph_val_iter_pairs, valFormat);
+            return;
+    default:return;
+    }
+  }
+
   template <typename context_t, typename ...Ts>
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
@@ -603,6 +745,13 @@ struct SinglePos
   } u;
 };
 
+template<typename Iterator>
+static inline void
+SinglePos_serialize (hb_serialize_context_t *c,
+                     Iterator it,
+                     ValueFormat valFormat)
+{ c->start_embed<SinglePos> ()->serialize (c, it, valFormat); }
+
 
 struct PairValueRecord
 {
index 618e663..1e90367 100644 (file)
@@ -13,6 +13,7 @@ EXTRA_DIST += \
        expected/japanese \
        expected/cff-japanese \
        expected/layout \
+       expected/layout.gpos \
        fonts \
        profiles \
        $(NULL)
index f065e83..8bacc51 100644 (file)
@@ -5,6 +5,7 @@ TESTS = \
        tests/japanese.tests \
        tests/cff-japanese.tests \
        tests/layout.tests \
+       tests/layout.gpos.tests \
        $(NULL)
 
 XFAIL_TESTS = \
diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.41,43.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.41,43.otf
new file mode 100644 (file)
index 0000000..6b2879f
Binary files /dev/null and b/test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.41,43.otf differ
diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.41,46.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.41,46.otf
new file mode 100644 (file)
index 0000000..eebb3e1
Binary files /dev/null and b/test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.41,46.otf differ
diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.43,46.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.43,46.otf
new file mode 100644 (file)
index 0000000..c271bde
Binary files /dev/null and b/test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.43,46.otf differ
diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.retain-all-codepoint.otf
new file mode 100644 (file)
index 0000000..2d6962b
Binary files /dev/null and b/test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.retain-all-codepoint.otf differ
diff --git a/test/subset/data/fonts/gpos1_2_font.otf b/test/subset/data/fonts/gpos1_2_font.otf
new file mode 100644 (file)
index 0000000..28331f2
Binary files /dev/null and b/test/subset/data/fonts/gpos1_2_font.otf differ
diff --git a/test/subset/data/tests/layout.gpos.tests b/test/subset/data/tests/layout.gpos.tests
new file mode 100644 (file)
index 0000000..2d0f936
--- /dev/null
@@ -0,0 +1,11 @@
+FONTS:
+gpos1_2_font.otf
+
+PROFILES:
+keep-layout-retain-gids.txt
+
+SUBSETS:
+AC
+CF
+AF
+*