[subset] subsetting cmap14

This commit is contained in:
Qunxin Liu 2019-08-16 13:54:24 -07:00 committed by Garret Rieger
parent 078ddbd0f6
commit 2583afa0eb
1 changed files with 264 additions and 29 deletions

View File

@ -676,6 +676,70 @@ struct DefaultUVS : SortedArrayOf<UnicodeValueRange, HBUINT32>
}
}
DefaultUVS* copy (hb_serialize_context_t *c,
const hb_set_t *unicodes) const
{
DefaultUVS *out = c->start_embed<DefaultUVS> ();
if (unlikely (!out)) return nullptr;
auto snap = c->snapshot ();
HBUINT32 len;
len = 0;
if (unlikely (!c->copy<HBUINT32> (len))) return nullptr;
unsigned init_len = c->length ();
hb_codepoint_t lastCode = HB_MAP_VALUE_INVALID;
int count = -1;
+ as_array ()
| hb_apply ([&] (const UnicodeValueRange& _)
{
+ hb_range ((unsigned)_.additionalCount + 1)
| hb_apply ([&] (const unsigned addcnt)
{
unsigned curEntry = (unsigned)_.startUnicodeValue + addcnt;
if (hb_set_has (unicodes, curEntry))
{
count += 1;
if (lastCode == HB_MAP_VALUE_INVALID)
{
lastCode = curEntry;
} else if (lastCode + count != curEntry)
{
UnicodeValueRange rec;
rec.startUnicodeValue = lastCode;
rec.additionalCount = count - 1;
c->copy<UnicodeValueRange> (rec);
lastCode = curEntry;
count = 0;
}
}
})
;
})
;
if (lastCode != HB_MAP_VALUE_INVALID)
{
UnicodeValueRange rec;
rec.startUnicodeValue = lastCode;
rec.additionalCount = count;
c->copy<UnicodeValueRange> (rec);
}
if (c->length () - init_len == 0)
{
c->revert (snap);
return nullptr;
}
else
{
if (unlikely (!c->check_assign (out->len, (c->length () - init_len) / UnicodeValueRange::static_size))) return nullptr;
return out;
}
}
public:
DEFINE_SIZE_ARRAY (4, *this);
};
@ -718,6 +782,41 @@ struct NonDefaultUVS : SortedArrayOf<UVSMapping, HBUINT32>
;
}
NonDefaultUVS* copy (hb_serialize_context_t *c,
const hb_set_t *unicodes,
const hb_set_t *glyphs,
const hb_map_t *glyph_map) const
{
NonDefaultUVS *out = c->start_embed<NonDefaultUVS> ();
if (unlikely (!out)) return nullptr;
auto it =
+ as_array ()
| hb_filter ([&] (const UVSMapping& _)
{
return hb_set_has (unicodes, _.unicodeValue) || hb_set_has (glyphs, _.glyphID);
})
;
if (!it) return nullptr;
HBUINT32 len;
len = it.len ();
if (unlikely (!c->copy<HBUINT32> (len))) return nullptr;
+ it
| hb_apply ([&] (const UVSMapping& _)
{
UVSMapping mapping;
mapping.unicodeValue = _.unicodeValue;
mapping.glyphID = glyph_map->get (_.glyphID);
c->copy<UVSMapping> (mapping);
})
;
return out;
}
public:
DEFINE_SIZE_ARRAY (4, *this);
};
@ -758,6 +857,52 @@ struct VariationSelectorRecord
nonDefaultUVS.sanitize (c, base));
}
VariationSelectorRecord* copy (hb_serialize_context_t *c,
const hb_set_t *unicodes,
const hb_set_t *glyphs,
const hb_map_t *glyph_map,
const void *src_base,
const void *dst_base) const
{
auto snap = c->snapshot ();
auto *out = c->embed<VariationSelectorRecord> (*this);
if (unlikely (!out)) return nullptr;
out->defaultUVS = 0;
out->nonDefaultUVS = 0;
bool drop = true;
if (defaultUVS != 0)
{
c->push ();
if (c->copy (src_base+defaultUVS, unicodes))
{
c->add_link (out->defaultUVS, c->pop_pack (), dst_base);
drop = false;
}
else c->pop_discard ();
}
if (nonDefaultUVS != 0)
{
c->push ();
if (c->copy (src_base+nonDefaultUVS, unicodes, glyphs, glyph_map))
{
c->add_link (out->nonDefaultUVS, c->pop_pack (), dst_base);
drop = false;
}
else c->pop_discard ();
}
if (drop)
{
c->revert (snap);
return nullptr;
}
else return out;
}
HBUINT24 varSelector; /* Variation selector. */
LOffsetTo<DefaultUVS>
defaultUVS; /* Offset to Default UVS Table. May be 0. */
@ -788,11 +933,44 @@ struct CmapSubtableFormat14
record.bsearch (variation_selector).collect_unicodes (out, this);
}
void serialize (hb_serialize_context_t *c,
const hb_set_t *unicodes,
const hb_set_t *glyphs,
const hb_map_t *glyph_map,
const void *src_base)
{
auto snap = c->snapshot ();
unsigned table_initpos = c->length ();
const char* init_tail = c->tail;
if (unlikely (!c->extend_min (*this))) return;
this->format = 14;
const CmapSubtableFormat14 *src_tbl = reinterpret_cast<const CmapSubtableFormat14*> (src_base);
+ hb_iter (src_tbl->record)
| hb_apply ([&] (const VariationSelectorRecord& _)
{
c->copy (_, unicodes, glyphs, glyph_map, src_base, this);
})
;
if (c->length () - table_initpos == CmapSubtableFormat14::min_size)
{
c->revert (snap);
}
else
{
int tail_len = init_tail - c->tail;
c->check_assign (this->length, c->length () - table_initpos + tail_len);
c->check_assign (this->record.len, (c->length () - table_initpos - CmapSubtableFormat14::min_size) / VariationSelectorRecord::static_size);
}
}
void closure_glyphs (const hb_set_t *unicodes,
hb_set_t *glyphset) const
{
+ hb_iter (record)
| hb_filter ([&] (const VariationSelectorRecord& _) { return _.nonDefaultUVS != 0 && hb_set_has (unicodes, _.varSelector); })
| hb_filter ([&] (const VariationSelectorRecord& _) { return _.nonDefaultUVS != 0; })
| hb_map (&VariationSelectorRecord::nonDefaultUVS)
| hb_map (hb_add (this))
| hb_apply ([=] (const NonDefaultUVS& _) { _.closure_glyphs (unicodes, glyphset); })
@ -852,11 +1030,16 @@ struct CmapSubtable
hb_requires (hb_is_iterator (Iterator))>
void serialize (hb_serialize_context_t *c,
Iterator it,
unsigned format)
unsigned format,
const hb_set_t *unicodes,
const hb_set_t *glyphs,
const hb_map_t *glyph_map,
const void *src_base)
{
switch (format) {
case 4: u.format4.serialize (c, it); return;
case 12: u.format12.serialize (c, it); return;
case 14: u.format14.serialize (c, unicodes, glyphs, glyph_map, src_base); return;
default: return;
}
}
@ -915,12 +1098,17 @@ struct EncodingRecord
template<typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
EncodingRecord* copy (hb_serialize_context_t *c,
Iterator it,
unsigned format,
void *base,
/* INOUT */ unsigned *objidx) const
Iterator it,
unsigned format,
const void *src_base,
const void *dst_base,
/* INOUT */ unsigned *objidx,
const hb_set_t *unicodes,
const hb_set_t *glyphs,
const hb_map_t *glyph_map) const
{
TRACE_SERIALIZE (this);
auto snap = c->snapshot ();
auto *out = c->embed (this);
if (unlikely (!out)) return_trace (nullptr);
out->subtable = 0;
@ -929,13 +1117,21 @@ struct EncodingRecord
{
CmapSubtable *cmapsubtable = c->push<CmapSubtable> ();
unsigned origin_length = c->length ();
cmapsubtable->serialize (c, it, format);
cmapsubtable->serialize (c, it, format, unicodes, glyphs, glyph_map, &(src_base+subtable));
if (c->length () - origin_length > 0) *objidx = c->pop_pack ();
else c->pop_discard ();
}
c->add_link (out->subtable, *objidx, base);
return_trace (out);
if (*objidx == 0)
{
c->revert (snap);
return_trace (nullptr);
}
else
{
c->add_link (out->subtable, *objidx, dst_base);
return_trace (out);
}
}
HBUINT16 platformID; /* Platform ID. */
@ -950,27 +1146,33 @@ struct cmap
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_cmap;
template<typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
template<typename Iterator, typename EncodingRecIter,
hb_requires (hb_is_iterator (Iterator))>
void serialize (hb_serialize_context_t *c,
Iterator it,
const EncodingRecord *unicode_bmp,
const EncodingRecord *unicode_ucs4,
const EncodingRecord *ms_bmp,
const EncodingRecord *ms_ucs4)
Iterator it,
EncodingRecIter encodingrec_iter,
const void *src_base,
const hb_set_t *unicodes,
const hb_set_t *glyphs,
const hb_map_t *glyph_map)
{
if (unlikely (!c->extend_min ((*this)))) return;
this->version = 0;
unsigned numTables = (unicode_bmp ? 1 : 0) + (unicode_ucs4 ? 1 : 0) + (ms_bmp ? 1 : 0) + (ms_ucs4 ? 1 : 0);
if (unlikely (!c->check_assign(this->encodingRecord.len, numTables))) return;
unsigned format4objidx = 0, format12objidx = 0, format14objidx = 0;
unsigned format4objidx = 0, format12objidx = 0;
if (unicode_bmp) c->copy (unicode_bmp, it, 4u, this, &format4objidx);
if (unicode_ucs4) c->copy (unicode_ucs4, it, 12u, this, &format12objidx);
if (ms_bmp) c->copy (ms_bmp, it, 4u, this, &format4objidx);
if (ms_ucs4) c->copy (ms_ucs4, it, 12u, this, &format12objidx);
+ encodingrec_iter
| hb_apply ([&] (const EncodingRecord& _)
{
unsigned format = (src_base+_.subtable).u.format;
if (format == 4) c->copy (_, it, 4u, src_base, this, &format4objidx, unicodes, glyphs, glyph_map);
else if (format == 12) c->copy (_, it, 12u, src_base, this, &format12objidx, unicodes, glyphs, glyph_map);
else if (format == 14) c->copy (_, it, 14u, src_base, this, &format14objidx, unicodes, glyphs, glyph_map);
})
;
c->check_assign(this->encodingRecord.len, (c->length () - cmap::min_size)/EncodingRecord::static_size);
}
void closure_glyphs (const hb_set_t *unicodes,
@ -991,12 +1193,45 @@ struct cmap
cmap *cmap_prime = c->serializer->start_embed<cmap> ();
if (unlikely (!c->serializer->check_success (cmap_prime))) return_trace (false);
const EncodingRecord *unicode_bmp = find_encodingrec (0, 3);
const EncodingRecord *unicode_ucs4 = find_encodingrec (0, 4);
const EncodingRecord *ms_bmp = find_encodingrec (3, 1);
const EncodingRecord *ms_ucs4 = find_encodingrec (3, 10);
bool has_format12 = find_subtable (12);
const EncodingRecord *unicode_bmp= nullptr, *unicode_ucs4 = nullptr, *ms_bmp = nullptr, *ms_ucs4 = nullptr;
bool has_format12 = false, has_format14 = false;
auto encodingrec_iter =
+ hb_iter (encodingRecord)
| hb_filter ([&] (const EncodingRecord& _)
{
unsigned format = (this + _.subtable).u.format;
if (format == 12) has_format12 = true;
if (format == 14) has_format14 = true;
const EncodingRecord *table = hb_addressof (_);
if (_.platformID == 0 && _.encodingID == 3)
{
unicode_bmp = table;
return true;
}
else if (_.platformID == 0 && _.encodingID == 4)
{
unicode_ucs4 = table;
return true;
}
else if (_.platformID == 3 && _.encodingID == 1)
{
ms_bmp = table;
return true;
}
else if (_.platformID == 3 && _.encodingID == 10)
{
ms_ucs4 = table;
return true;
}
else if (format == 14) return true;
else return false;
})
;
if (unlikely (!encodingrec_iter.len ())) return_trace (false);
if (unlikely (!unicode_bmp && !ms_bmp)) return_trace (false);
if (unlikely (has_format12 && (!unicode_ucs4 && !ms_ucs4))) return_trace (false);
@ -1014,7 +1249,7 @@ struct cmap
})
;
cmap_prime->serialize (c->serializer, it, unicode_bmp, unicode_ucs4, ms_bmp, ms_ucs4);
cmap_prime->serialize (c->serializer, it, encodingrec_iter, this, c->plan->unicodes, c->plan->_glyphset, c->plan->glyph_map);
return_trace (true);
}