[subset] GPOS4 MarkBase subsetting support
This commit is contained in:
parent
4dc3db7344
commit
82afc75835
@ -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 <typename Type2>
|
||||
int cmp (Type2 a) const
|
||||
{
|
||||
|
@ -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 <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 @@ struct AnchorMatrix
|
||||
}
|
||||
|
||||
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 @@ 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<Anchor>
|
||||
@ -542,6 +582,20 @@ struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage orde
|
||||
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 @@ 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<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
|
||||
|
@ -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 \
|
||||
|
@ -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 \
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
test/subset/data/fonts/gpos4_multiple_anchors_1.otf
Normal file
BIN
test/subset/data/fonts/gpos4_multiple_anchors_1.otf
Normal file
Binary file not shown.
18
test/subset/data/tests/layout.gpos4.tests
Normal file
18
test/subset/data/tests/layout.gpos4.tests
Normal file
@ -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
|
||||
*
|
Loading…
Reference in New Issue
Block a user