diff --git a/src/hb-open-type.hh b/src/hb-open-type.hh index 725f294b7..743a736d8 100644 --- a/src/hb-open-type.hh +++ b/src/hb-open-type.hh @@ -73,6 +73,13 @@ struct IntType 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 int cmp (Type2 a) const { diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh index eb4b8894b..e0459c263 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 @@ struct AnchorMatrix return this+matrixZ[row * cols + col]; } + template + 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 @@ struct AnchorMatrix } HBUINT16 rows; /* Number of rows */ - protected: UnsizedArrayOf> matrixZ; /* Matrix of offsets to Anchor tables-- * from beginning of AnchorMatrix table */ @@ -491,12 +516,27 @@ struct MarkRecord { 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 @@ -542,6 +582,20 @@ struct MarkArray : ArrayOf /* Array of MarkRecords--in Coverage orde return_trace (true); } + template + 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 @@ typedef AnchorMatrix BaseArray; /* base-major-- * 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 @@ struct MarkBasePosFormat1 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 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 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 4a5bb3064..81aee9579 100644 --- a/test/subset/data/Makefile.am +++ b/test/subset/data/Makefile.am @@ -16,6 +16,7 @@ EXTRA_DIST += \ 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 d642db89d..b5b4a1f37 100644 --- a/test/subset/data/Makefile.sources +++ b/test/subset/data/Makefile.sources @@ -8,6 +8,7 @@ TESTS = \ 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 000000000..1c2e5a462 Binary files /dev/null and b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout-retain-gids.41,42,43,44.otf 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 000000000..2fed45d31 Binary files /dev/null and b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout-retain-gids.41,42,43,45.otf 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 000000000..00076157a Binary files /dev/null and b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout-retain-gids.41,42,43.otf 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 000000000..8eb6ace19 Binary files /dev/null and b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout-retain-gids.41,42.otf 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 000000000..73315f3ed Binary files /dev/null and b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout-retain-gids.41,43,44,45,46.otf 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 000000000..4005a0d77 Binary files /dev/null and b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout-retain-gids.41,43,44.otf 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 000000000..c9f261ce9 Binary files /dev/null and b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout-retain-gids.41,43,45.otf 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 000000000..9ed6a9b77 Binary files /dev/null and b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout-retain-gids.41,43.otf 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 000000000..f50cc90bc Binary files /dev/null and b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout-retain-gids.41.otf 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 000000000..d4f9fc081 Binary files /dev/null and b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout-retain-gids.retain-all-codepoint.otf 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 000000000..5447973d5 Binary files /dev/null and b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout.41,42,43,44.otf 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 000000000..e6c891b2e Binary files /dev/null and b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout.41,42,43,45.otf 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 000000000..127f798f3 Binary files /dev/null and b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout.41,42,43.otf 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 000000000..6cafcb831 Binary files /dev/null and b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout.41,42.otf 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 000000000..5f4754268 Binary files /dev/null and b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout.41,43,44,45,46.otf 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 000000000..8fe4d63eb Binary files /dev/null and b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout.41,43,44.otf 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 000000000..147ed5782 Binary files /dev/null and b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout.41,43,45.otf 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 000000000..1b0f24362 Binary files /dev/null and b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout.41,43.otf 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 000000000..657b68674 Binary files /dev/null and b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout.41.otf 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 000000000..d4f9fc081 Binary files /dev/null and b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.keep-layout.retain-all-codepoint.otf 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 000000000..e77cbb654 Binary files /dev/null and b/test/subset/data/fonts/gpos4_multiple_anchors_1.otf differ diff --git a/test/subset/data/tests/layout.gpos4.tests b/test/subset/data/tests/layout.gpos4.tests new file mode 100644 index 000000000..fd2b68851 --- /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 +*