[subset] Refactor cmap subsetting to make it possible to add support for more sub tables.
This commit is contained in:
parent
03b2754812
commit
0053d13283
|
@ -294,7 +294,7 @@ struct CmapSubtableLongSegmented
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool serialize (hb_serialize_context_t *c,
|
inline bool serialize (hb_serialize_context_t *c,
|
||||||
hb_vector_t<CmapSubtableLongGroup> &group_data)
|
const hb_vector_t<CmapSubtableLongGroup> &group_data)
|
||||||
{
|
{
|
||||||
TRACE_SERIALIZE (this);
|
TRACE_SERIALIZE (this);
|
||||||
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
||||||
|
@ -319,6 +319,69 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
|
||||||
static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
|
static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
|
||||||
hb_codepoint_t u)
|
hb_codepoint_t u)
|
||||||
{ return group.glyphID + (u - group.startCharCode); }
|
{ return group.glyphID + (u - group.startCharCode); }
|
||||||
|
|
||||||
|
|
||||||
|
bool serialize (hb_serialize_context_t *c,
|
||||||
|
const hb_vector_t<CmapSubtableLongGroup> &groups)
|
||||||
|
{
|
||||||
|
if (unlikely (!c->extend_min (*this))) return false;
|
||||||
|
|
||||||
|
this->format.set (12);
|
||||||
|
this->reservedZ.set (0);
|
||||||
|
this->lengthZ.set (get_sub_table_size (groups));
|
||||||
|
|
||||||
|
return CmapSubtableLongSegmented::serialize (c, groups);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline size_t get_sub_table_size (const hb_vector_t<CmapSubtableLongGroup> &groups)
|
||||||
|
{
|
||||||
|
return 16 + 12 * groups.len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool create_sub_table_plan (const hb_subset_plan_t *plan,
|
||||||
|
hb_vector_t<CmapSubtableLongGroup> *groups)
|
||||||
|
{
|
||||||
|
CmapSubtableLongGroup *group = nullptr;
|
||||||
|
for (unsigned int i = 0; i < plan->codepoints.len; i++) {
|
||||||
|
|
||||||
|
hb_codepoint_t cp = plan->codepoints[i];
|
||||||
|
hb_codepoint_t new_gid;
|
||||||
|
if (unlikely (!hb_subset_plan_new_gid_for_codepoint (plan, cp, &new_gid)))
|
||||||
|
{
|
||||||
|
DEBUG_MSG(SUBSET, nullptr, "Unable to find new gid for %04x", cp);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!group || !_is_gid_consecutive (group, cp, new_gid))
|
||||||
|
{
|
||||||
|
group = groups->push ();
|
||||||
|
group->startCharCode.set (cp);
|
||||||
|
group->endCharCode.set (cp);
|
||||||
|
group->glyphID.set (new_gid);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
group->endCharCode.set (cp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_MSG(SUBSET, nullptr, "cmap");
|
||||||
|
for (unsigned int i = 0; i < groups->len; i++) {
|
||||||
|
CmapSubtableLongGroup& group = (*groups)[i];
|
||||||
|
DEBUG_MSG(SUBSET, nullptr, " %d: U+%04X-U+%04X, gid %d-%d", i, (uint32_t) group.startCharCode, (uint32_t) group.endCharCode, (uint32_t) group.glyphID, (uint32_t) group.glyphID + ((uint32_t) group.endCharCode - (uint32_t) group.startCharCode));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static inline bool _is_gid_consecutive (CmapSubtableLongGroup *group,
|
||||||
|
hb_codepoint_t cp,
|
||||||
|
hb_codepoint_t new_gid)
|
||||||
|
{
|
||||||
|
return (cp - 1 == group->endCharCode) &&
|
||||||
|
new_gid == group->glyphID + (cp - group->startCharCode);
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CmapSubtableFormat13 : CmapSubtableLongSegmented<CmapSubtableFormat13>
|
struct CmapSubtableFormat13 : CmapSubtableLongSegmented<CmapSubtableFormat13>
|
||||||
|
@ -531,6 +594,29 @@ struct cmap
|
||||||
{
|
{
|
||||||
static const hb_tag_t tableTag = HB_OT_TAG_cmap;
|
static const hb_tag_t tableTag = HB_OT_TAG_cmap;
|
||||||
|
|
||||||
|
struct subset_plan {
|
||||||
|
subset_plan(void)
|
||||||
|
{
|
||||||
|
groups.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
~subset_plan(void)
|
||||||
|
{
|
||||||
|
groups.fini();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline size_t final_size() const
|
||||||
|
{
|
||||||
|
return
|
||||||
|
4 // header
|
||||||
|
+ 8 // 1 EncodingRecord
|
||||||
|
+ CmapSubtableFormat12::get_sub_table_size (this->groups);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format 12
|
||||||
|
hb_vector_t<CmapSubtableLongGroup> groups;
|
||||||
|
};
|
||||||
|
|
||||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||||
{
|
{
|
||||||
TRACE_SANITIZE (this);
|
TRACE_SANITIZE (this);
|
||||||
|
@ -539,50 +625,13 @@ struct cmap
|
||||||
encodingRecord.sanitize (c, this));
|
encodingRecord.sanitize (c, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool _is_gid_consecutive (CmapSubtableLongGroup *group,
|
inline bool _create_plan (const hb_subset_plan_t *plan,
|
||||||
hb_codepoint_t cp,
|
subset_plan *cmap_plan) const
|
||||||
hb_codepoint_t new_gid)
|
|
||||||
{
|
{
|
||||||
return (cp - 1 == group->endCharCode) &&
|
return CmapSubtableFormat12::create_sub_table_plan (plan, &cmap_plan->groups);
|
||||||
new_gid == group->glyphID + (cp - group->startCharCode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool populate_groups (hb_subset_plan_t *plan,
|
inline bool _subset (const subset_plan &cmap_subset_plan,
|
||||||
hb_vector_t<CmapSubtableLongGroup> *groups) const
|
|
||||||
{
|
|
||||||
CmapSubtableLongGroup *group = nullptr;
|
|
||||||
for (unsigned int i = 0; i < plan->codepoints.len; i++) {
|
|
||||||
|
|
||||||
hb_codepoint_t cp = plan->codepoints[i];
|
|
||||||
hb_codepoint_t new_gid;
|
|
||||||
if (unlikely (!hb_subset_plan_new_gid_for_codepoint (plan, cp, &new_gid)))
|
|
||||||
{
|
|
||||||
DEBUG_MSG(SUBSET, nullptr, "Unable to find new gid for %04x", cp);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!group || !_is_gid_consecutive (group, cp, new_gid))
|
|
||||||
{
|
|
||||||
group = groups->push ();
|
|
||||||
group->startCharCode.set (cp);
|
|
||||||
group->endCharCode.set (cp);
|
|
||||||
group->glyphID.set (new_gid);
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
group->endCharCode.set (cp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG_MSG(SUBSET, nullptr, "cmap");
|
|
||||||
for (unsigned int i = 0; i < groups->len; i++) {
|
|
||||||
CmapSubtableLongGroup& group = (*groups)[i];
|
|
||||||
DEBUG_MSG(SUBSET, nullptr, " %d: U+%04X-U+%04X, gid %d-%d", i, (uint32_t) group.startCharCode, (uint32_t) group.endCharCode, (uint32_t) group.glyphID, (uint32_t) group.glyphID + ((uint32_t) group.endCharCode - (uint32_t) group.startCharCode));
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool _subset (hb_vector_t<CmapSubtableLongGroup> &groups,
|
|
||||||
size_t dest_sz,
|
size_t dest_sz,
|
||||||
void *dest) const
|
void *dest) const
|
||||||
{
|
{
|
||||||
|
@ -602,19 +651,12 @@ struct cmap
|
||||||
rec.platformID.set (3); // Windows
|
rec.platformID.set (3); // Windows
|
||||||
rec.encodingID.set (10); // Unicode UCS-4
|
rec.encodingID.set (10); // Unicode UCS-4
|
||||||
|
|
||||||
/* capture offset to subtable */
|
// Write out format 12 sub table.
|
||||||
CmapSubtable &subtable = rec.subtable.serialize (&c, cmap);
|
CmapSubtable &subtable = rec.subtable.serialize (&c, cmap);
|
||||||
|
|
||||||
subtable.u.format.set (12);
|
subtable.u.format.set (12);
|
||||||
|
|
||||||
CmapSubtableFormat12 &format12 = subtable.u.format12;
|
CmapSubtableFormat12 &format12 = subtable.u.format12;
|
||||||
if (unlikely (!c.extend_min (format12))) return false;
|
if (unlikely (!format12.serialize (&c, cmap_subset_plan.groups))) return false;
|
||||||
|
|
||||||
format12.format.set (12);
|
|
||||||
format12.reserved.set (0);
|
|
||||||
format12.length.set (16 + 12 * groups.len);
|
|
||||||
|
|
||||||
if (unlikely (!format12.serialize (&c, groups))) return false;
|
|
||||||
|
|
||||||
c.end_serialize ();
|
c.end_serialize ();
|
||||||
|
|
||||||
|
@ -623,24 +665,25 @@ struct cmap
|
||||||
|
|
||||||
inline bool subset (hb_subset_plan_t *plan) const
|
inline bool subset (hb_subset_plan_t *plan) const
|
||||||
{
|
{
|
||||||
hb_auto_t<hb_vector_t<CmapSubtableLongGroup> > groups;
|
subset_plan cmap_subset_plan;
|
||||||
|
|
||||||
if (unlikely (!populate_groups (plan, &groups))) return false;
|
if (unlikely (!_create_plan (plan, &cmap_subset_plan)))
|
||||||
|
{
|
||||||
|
DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cmap subsetting plan.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// We now know how big our blob needs to be
|
// We now know how big our blob needs to be
|
||||||
// TODO use APIs from the structs to get size?
|
size_t dest_sz = cmap_subset_plan.final_size();
|
||||||
size_t dest_sz = 4 // header
|
|
||||||
+ 8 // 1 EncodingRecord
|
|
||||||
+ 16 // Format 12 header
|
|
||||||
+ 12 * groups.len; // SequentialMapGroup records
|
|
||||||
void *dest = malloc (dest_sz);
|
void *dest = malloc (dest_sz);
|
||||||
if (unlikely (!dest)) {
|
if (unlikely (!dest)) {
|
||||||
DEBUG_MSG(SUBSET, nullptr, "Unable to alloc %lu for cmap subset output", (unsigned long) dest_sz);
|
DEBUG_MSG(SUBSET, nullptr, "Unable to alloc %lu for cmap subset output", (unsigned long) dest_sz);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely (!_subset (groups, dest_sz, dest)))
|
if (unlikely (!_subset (cmap_subset_plan, dest_sz, dest)))
|
||||||
{
|
{
|
||||||
|
DEBUG_MSG(SUBSET, nullptr, "Failed to perform subsetting of cmap.");
|
||||||
free (dest);
|
free (dest);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue