Merge pull request #2701 from googlefonts/Mark-To-Ligature_grieger

[subset] GPOS 5 MarkToLigature subsetting support
diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index 131ded2..b2b2f0e 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -566,6 +566,26 @@
     return_trace (true);
   }
 
+  bool subset (hb_subset_context_t *c,
+	       unsigned cols,
+	       const hb_map_t *klass_mapping) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->start_embed (*this);
+
+    auto indexes =
+    + hb_range (rows * cols)
+    | hb_filter ([=] (unsigned index) { return klass_mapping->has (index % cols); })
+    ;
+
+    out->serialize (c->serializer,
+                    (unsigned) rows,
+                    this,
+                    c->plan->layout_variation_idx_map,
+                    indexes);
+    return_trace (true);
+  }
+
   bool sanitize (hb_sanitize_context_t *c, unsigned int cols) const
   {
     TRACE_SANITIZE (this);
@@ -2025,10 +2045,40 @@
 					 * mark-minor--
 					 * ordered by class--zero-based. */
 
-typedef OffsetListOf<LigatureAttach> LigatureArray;
-					/* Array of LigatureAttach
-					 * tables ordered by
-					 * LigatureCoverage Index */
+/* Array of LigatureAttach tables ordered by LigatureCoverage Index */
+struct LigatureArray : OffsetListOf<LigatureAttach>
+{
+  template <typename Iterator,
+	    hb_requires (hb_is_iterator (Iterator))>
+  bool subset (hb_subset_context_t *c,
+	       Iterator		    coverage,
+	       unsigned		    class_count,
+	       const hb_map_t	   *klass_mapping) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+
+    auto *out = c->serializer->start_embed (this);
+    if (unlikely (!c->serializer->extend_min (out)))  return_trace (false);
+
+    unsigned ligature_count = 0;
+    for (hb_codepoint_t gid : coverage)
+    {
+      ligature_count++;
+      if (!glyphset.has (gid)) continue;
+
+      auto *matrix = out->serialize_append (c->serializer);
+      if (unlikely (!matrix)) return_trace (false);
+
+      matrix->serialize_subset (c,
+				this->arrayZ[ligature_count - 1],
+				this,
+				class_count,
+				klass_mapping);
+    }
+    return_trace (this->len);
+  }
+};
 
 struct MarkLigPosFormat1
 {
@@ -2130,8 +2180,56 @@
   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;
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->format = format;
+
+    hb_map_t klass_mapping;
+    Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, glyphset, &klass_mapping);
+
+    if (!klass_mapping.get_population ()) return_trace (false);
+    out->classCount = klass_mapping.get_population ();
+
+    auto mark_iter =
+    + hb_zip (this+markCoverage, this+markArray)
+    | hb_filter (glyphset, hb_first)
+    ;
+
+    auto new_mark_coverage =
+    + mark_iter
+    | hb_map_retains_sorting (hb_first)
+    | hb_map_retains_sorting (glyph_map)
+    ;
+
+    if (!out->markCoverage.serialize (c->serializer, out)
+			  .serialize (c->serializer, new_mark_coverage))
+      return_trace (false);
+
+    out->markArray.serialize (c->serializer, out)
+		  .serialize (c->serializer,
+                              &klass_mapping,
+                              c->plan->layout_variation_idx_map,
+                              &(this+markArray),
+                              + mark_iter
+                              | hb_map (hb_second));
+
+    auto new_ligature_coverage =
+    + hb_iter (this + ligatureCoverage)
+    | hb_filter (glyphset)
+    | hb_map_retains_sorting (glyph_map)
+    ;
+
+    if (!out->ligatureCoverage.serialize (c->serializer, out)
+			      .serialize (c->serializer, new_ligature_coverage))
+      return_trace (false);
+
+    out->ligatureArray.serialize_subset (c, ligatureArray, this,
+                                         hb_iter (this+ligatureCoverage), classCount, &klass_mapping);
+
+    return_trace (true);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -2164,6 +2262,7 @@
   DEFINE_SIZE_STATIC (12);
 };
 
+
 struct MarkLigPos
 {
   template <typename context_t, typename ...Ts>
diff --git a/test/subset/data/Makefile.am b/test/subset/data/Makefile.am
index d921f72..133971a 100644
--- a/test/subset/data/Makefile.am
+++ b/test/subset/data/Makefile.am
@@ -17,6 +17,7 @@
 	expected/layout.gpos2 \
 	expected/layout.gpos3 \
 	expected/layout.gpos4 \
+	expected/layout.gpos5 \
 	expected/layout.gpos6 \
 	expected/layout.gpos8 \
 	expected/layout.gpos8.amiri \
diff --git a/test/subset/data/Makefile.sources b/test/subset/data/Makefile.sources
index 58ba108..46680a5 100644
--- a/test/subset/data/Makefile.sources
+++ b/test/subset/data/Makefile.sources
@@ -16,6 +16,7 @@
 	tests/layout.gpos2.tests \
 	tests/layout.gpos3.tests \
 	tests/layout.gpos4.tests \
+	tests/layout.gpos5.tests \
 	tests/layout.gpos6.tests \
 	tests/layout.gpos8.tests \
 	tests/layout.gpos8.amiri.tests \
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41,42,43,44.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41,42,43,44.otf
new file mode 100644
index 0000000..13a1fb7
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41,42,43,44.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41,42,43,45.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41,42,43,45.otf
new file mode 100644
index 0000000..5153358
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41,42,43,45.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41,42,43.otf
new file mode 100644
index 0000000..b7a0bc6
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41,42,44.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41,42,44.otf
new file mode 100644
index 0000000..bb7d74b
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41,42,44.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41,42,45.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41,42,45.otf
new file mode 100644
index 0000000..0da7880
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41,42,45.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41,42.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41,42.otf
new file mode 100644
index 0000000..9b6e158
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41,43.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41,43.otf
new file mode 100644
index 0000000..c28bed1
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41.otf
new file mode 100644
index 0000000..7878d4b
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.42.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.42.otf
new file mode 100644
index 0000000..f5824e4
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.retain-all-codepoint.otf
new file mode 100644
index 0000000..b7c424e
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41,42,43,44.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41,42,43,44.otf
new file mode 100644
index 0000000..3749d35
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41,42,43,44.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41,42,43,45.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41,42,43,45.otf
new file mode 100644
index 0000000..5d4fcee
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41,42,43,45.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41,42,43.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41,42,43.otf
new file mode 100644
index 0000000..54fc068
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41,42,44.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41,42,44.otf
new file mode 100644
index 0000000..d4c95a6
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41,42,44.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41,42,45.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41,42,45.otf
new file mode 100644
index 0000000..656792d
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41,42,45.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41,42.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41,42.otf
new file mode 100644
index 0000000..cc2f5f7
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41,43.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41,43.otf
new file mode 100644
index 0000000..946c63c
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41.otf
new file mode 100644
index 0000000..093f4ee
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.42.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.42.otf
new file mode 100644
index 0000000..9e1aabf
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.retain-all-codepoint.otf
new file mode 100644
index 0000000..b7c424e
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/fonts/gpos5_font1.otf b/test/subset/data/fonts/gpos5_font1.otf
new file mode 100644
index 0000000..c7e2132
--- /dev/null
+++ b/test/subset/data/fonts/gpos5_font1.otf
Binary files differ
diff --git a/test/subset/data/tests/layout.gpos5.tests b/test/subset/data/tests/layout.gpos5.tests
new file mode 100644
index 0000000..3f5ef0c
--- /dev/null
+++ b/test/subset/data/tests/layout.gpos5.tests
@@ -0,0 +1,18 @@
+FONTS:
+gpos5_font1.otf
+
+PROFILES:
+keep-layout.txt
+keep-layout-retain-gids.txt
+
+SUBSETS:
+A
+B
+AB
+AC
+ABC
+ABE
+ABCE
+ABD
+ABCD
+*
diff --git a/test/subset/meson.build b/test/subset/meson.build
index 8d3d58b..de28fda 100644
--- a/test/subset/meson.build
+++ b/test/subset/meson.build
@@ -9,6 +9,7 @@
   'layout.gpos2',
   'layout.gpos3',
   'layout.gpos4',
+  'layout.gpos5',
   'layout.gpos6',
   'layout.gpos8',
   'layout.gpos8.amiri',