[subset] GPOS4 MarkBase subsetting support
diff --git a/src/hb-open-type.hh b/src/hb-open-type.hh index 725f294..743a736 100644 --- a/src/hb-open-type.hh +++ b/src/hb-open-type.hh
@@ -73,6 +73,13 @@ HB_INTERNAL static int cmp (const IntType *a, const IntType *b) { return b->cmp (*a); } + HB_INTERNAL static int cmp (const void *a, const void *b) + { + IntType *pa = (IntType *) a; + IntType *pb = (IntType *) b; + + return pb->cmp (*pa); + } template <typename Type2> int cmp (Type2 a) const {
diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh index eb4b889..e0459c2 100644 --- a/src/hb-ot-layout-gpos-table.hh +++ b/src/hb-ot-layout-gpos-table.hh
@@ -34,6 +34,11 @@ namespace OT { +struct MarkArray; +static void Markclass_closure_and_remap_indexes (const Coverage &mark_coverage, + const MarkArray &mark_array, + const hb_set_t &glyphset, + hb_map_t* klass_mapping /* INOUT */); /* buffer **position** var allocations */ #define attach_chain() var.i16[0] /* glyph to which this attaches to, relative to current glyphs; negative for going back, positive for forward. */ @@ -465,6 +470,27 @@ return this+matrixZ[row * cols + col]; } + template <typename Iterator, + hb_requires (hb_is_iterator (Iterator))> + bool serialize (hb_serialize_context_t *c, + unsigned num_rows, + AnchorMatrix const *offset_matrix, + Iterator index_iter) + { + TRACE_SERIALIZE (this); + if (!index_iter.len ()) return_trace (false); + if (unlikely (!c->extend_min ((*this)))) return_trace (false); + + this->rows = num_rows; + for (const unsigned i : index_iter) + { + auto *offset = c->embed (offset_matrix->matrixZ[i]); + offset->serialize_copy (c, offset_matrix->matrixZ[i], offset_matrix, this); + } + + return_trace (true); + } + bool sanitize (hb_sanitize_context_t *c, unsigned int cols) const { TRACE_SANITIZE (this); @@ -478,7 +504,6 @@ } HBUINT16 rows; /* Number of rows */ - protected: UnsizedArrayOf<OffsetTo<Anchor>> matrixZ; /* Matrix of offsets to Anchor tables-- * from beginning of AnchorMatrix table */ @@ -491,12 +516,27 @@ { friend struct MarkArray; + unsigned get_class () const { return (unsigned) klass; } bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && markAnchor.sanitize (c, base)); } + MarkRecord *copy (hb_serialize_context_t *c, + const void *src_base, + const void *dst_base, + const hb_map_t *klass_mapping) const + { + TRACE_SERIALIZE (this); + auto *out = c->embed (this); + if (unlikely (!out)) return_trace (nullptr); + + out->klass = klass_mapping->get (klass); + out->markAnchor.serialize_copy (c, markAnchor, src_base, dst_base); + return_trace (out); + } + protected: HBUINT16 klass; /* Class defined for this mark */ OffsetTo<Anchor> @@ -542,6 +582,20 @@ return_trace (true); } + template<typename Iterator, + hb_requires (hb_is_source_of (Iterator, MarkRecord))> + bool serialize (hb_serialize_context_t *c, + const hb_map_t *klass_mapping, + const void *src_base, + Iterator it) + { + TRACE_SERIALIZE (this); + if (unlikely (!c->extend_min (*this))) return_trace (false); + if (unlikely (!c->check_assign (len, it.len ()))) return_trace (false); + c->copy_all (it, src_base, this, klass_mapping); + return_trace (true); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -1514,6 +1568,29 @@ * mark-minor-- * ordered by class--zero-based. */ +static void Markclass_closure_and_remap_indexes (const Coverage &mark_coverage, + const MarkArray &mark_array, + const hb_set_t &glyphset, + hb_map_t* klass_mapping /* INOUT */) +{ + hb_set_t orig_classes; + + + hb_zip (mark_coverage, mark_array) + | hb_filter (glyphset, hb_first) + | hb_map (hb_second) + | hb_map (&MarkRecord::get_class) + | hb_sink (orig_classes) + ; + + unsigned idx = 0; + for (auto klass : orig_classes.iter ()) + { + if (klass_mapping->has (klass)) continue; + klass_mapping->set (klass, idx); + idx++; + } +} + struct MarkBasePosFormat1 { bool intersects (const hb_set_t *glyphs) const @@ -1573,8 +1650,70 @@ bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - // TODO(subset) - return_trace (false); + const hb_set_t &glyphset = *c->plan->glyphset (); + 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) + ; + + hb_sorted_vector_t<hb_codepoint_t> new_coverage; + + mark_iter + | hb_map (hb_first) + | hb_map (glyph_map) + | hb_sink (new_coverage) + ; + + if (!out->markCoverage.serialize (c->serializer, out) + .serialize (c->serializer, new_coverage.iter ())) + return_trace (false); + + out->markArray.serialize (c->serializer, out) + .serialize (c->serializer, &klass_mapping, &(this+markArray), + mark_iter + | hb_map (hb_second)); + + unsigned basecount = (this+baseArray).rows; + auto base_iter = + + hb_zip (this+baseCoverage, hb_range (basecount)) + | hb_filter (glyphset, hb_first) + ; + + new_coverage.reset (); + + base_iter + | hb_map (hb_first) + | hb_map (glyph_map) + | hb_sink (new_coverage) + ; + + if (!out->baseCoverage.serialize (c->serializer, out) + .serialize (c->serializer, new_coverage.iter ())) + return_trace (false); + + hb_sorted_vector_t<unsigned> base_indexes; + for (const unsigned row : + base_iter + | hb_map (hb_second)) + { + + hb_range ((unsigned) classCount) + | hb_filter (klass_mapping) + | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; }) + | hb_sink (base_indexes) + ; + } + out->baseArray.serialize (c->serializer, out) + .serialize (c->serializer, base_iter.len (), &(this+baseArray), base_indexes.iter ()); + + return_trace (true); } bool sanitize (hb_sanitize_context_t *c) const
diff --git a/test/subset/data/Makefile.am b/test/subset/data/Makefile.am index 4a5bb30..81aee95 100644 --- a/test/subset/data/Makefile.am +++ b/test/subset/data/Makefile.am
@@ -16,6 +16,7 @@ expected/layout.gpos \ expected/layout.gpos2 \ expected/layout.gpos3 \ + expected/layout.gpos4 \ expected/layout.gsub6 \ expected/cmap \ expected/cmap14 \
diff --git a/test/subset/data/Makefile.sources b/test/subset/data/Makefile.sources index d642db8..b5b4a1f 100644 --- a/test/subset/data/Makefile.sources +++ b/test/subset/data/Makefile.sources
@@ -8,6 +8,7 @@ tests/layout.gpos.tests \ tests/layout.gpos2.tests \ tests/layout.gpos3.tests \ + tests/layout.gpos4.tests \ tests/layout.gsub6.tests \ tests/cmap.tests \ tests/cmap14.tests \
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout-retain-gids.41,42,43,44.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout-retain-gids.41,42,43,44.otf new file mode 100644 index 0000000..1c2e5a4 --- /dev/null +++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout-retain-gids.41,42,43,44.otf Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout-retain-gids.41,42,43,45.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout-retain-gids.41,42,43,45.otf new file mode 100644 index 0000000..2fed45d --- /dev/null +++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout-retain-gids.41,42,43,45.otf Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout-retain-gids.41,42,43.otf new file mode 100644 index 0000000..0007615 --- /dev/null +++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout-retain-gids.41,42,43.otf Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout-retain-gids.41,42.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout-retain-gids.41,42.otf new file mode 100644 index 0000000..8eb6ace --- /dev/null +++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout-retain-gids.41,42.otf Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout-retain-gids.41,43,44,45,46.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout-retain-gids.41,43,44,45,46.otf new file mode 100644 index 0000000..73315f3 --- /dev/null +++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout-retain-gids.41,43,44,45,46.otf Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout-retain-gids.41,43,44.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout-retain-gids.41,43,44.otf new file mode 100644 index 0000000..4005a0d --- /dev/null +++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout-retain-gids.41,43,44.otf Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout-retain-gids.41,43,45.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout-retain-gids.41,43,45.otf new file mode 100644 index 0000000..c9f261c --- /dev/null +++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout-retain-gids.41,43,45.otf Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout-retain-gids.41,43.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout-retain-gids.41,43.otf new file mode 100644 index 0000000..9ed6a9b --- /dev/null +++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout-retain-gids.41,43.otf Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout-retain-gids.41.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout-retain-gids.41.otf new file mode 100644 index 0000000..f50cc90 --- /dev/null +++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout-retain-gids.41.otf Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout-retain-gids.retain-all-codepoint.otf new file mode 100644 index 0000000..d4f9fc0 --- /dev/null +++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout-retain-gids.retain-all-codepoint.otf Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout.41,42,43,44.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout.41,42,43,44.otf new file mode 100644 index 0000000..5447973 --- /dev/null +++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout.41,42,43,44.otf Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout.41,42,43,45.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout.41,42,43,45.otf new file mode 100644 index 0000000..e6c891b --- /dev/null +++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout.41,42,43,45.otf Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout.41,42,43.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout.41,42,43.otf new file mode 100644 index 0000000..127f798 --- /dev/null +++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout.41,42,43.otf Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout.41,42.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout.41,42.otf new file mode 100644 index 0000000..6cafcb8 --- /dev/null +++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout.41,42.otf Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout.41,43,44,45,46.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout.41,43,44,45,46.otf new file mode 100644 index 0000000..5f47542 --- /dev/null +++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout.41,43,44,45,46.otf Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout.41,43,44.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout.41,43,44.otf new file mode 100644 index 0000000..8fe4d63 --- /dev/null +++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout.41,43,44.otf Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout.41,43,45.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout.41,43,45.otf new file mode 100644 index 0000000..147ed57 --- /dev/null +++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout.41,43,45.otf Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout.41,43.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout.41,43.otf new file mode 100644 index 0000000..1b0f243 --- /dev/null +++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout.41,43.otf Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout.41.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout.41.otf new file mode 100644 index 0000000..657b686 --- /dev/null +++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout.41.otf Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout.retain-all-codepoint.otf new file mode 100644 index 0000000..d4f9fc0 --- /dev/null +++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout.retain-all-codepoint.otf Binary files differ
diff --git a/test/subset/data/fonts/gpos4_multiple_anchors_1.otf b/test/subset/data/fonts/gpos4_multiple_anchors_1.otf new file mode 100644 index 0000000..e77cbb6 --- /dev/null +++ b/test/subset/data/fonts/gpos4_multiple_anchors_1.otf Binary files differ
diff --git a/test/subset/data/tests/layout.gpos4.tests b/test/subset/data/tests/layout.gpos4.tests new file mode 100644 index 0000000..fd2b688 --- /dev/null +++ b/test/subset/data/tests/layout.gpos4.tests
@@ -0,0 +1,18 @@ +FONTS: +gpos4_multiple_anchors_1.otf + +PROFILES: +keep-layout.txt +keep-layout-retain-gids.txt + +SUBSETS: +A +AB +AC +ABC +ACE +ABCE +ACD +ACDEF +ABCD +*