From 0053d13283458996372f04bd501001d450523605 Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Wed, 2 May 2018 15:42:43 -0700 Subject: [PATCH] [subset] Refactor cmap subsetting to make it possible to add support for more sub tables. --- src/hb-ot-cmap-table.hh | 161 +++++++++++++++++++++++++--------------- 1 file changed, 102 insertions(+), 59 deletions(-) diff --git a/src/hb-ot-cmap-table.hh b/src/hb-ot-cmap-table.hh index 83a0b519b..f0e70afee 100644 --- a/src/hb-ot-cmap-table.hh +++ b/src/hb-ot-cmap-table.hh @@ -294,7 +294,7 @@ struct CmapSubtableLongSegmented } inline bool serialize (hb_serialize_context_t *c, - hb_vector_t &group_data) + const hb_vector_t &group_data) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return_trace (false); @@ -319,6 +319,69 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group, hb_codepoint_t u) { return group.glyphID + (u - group.startCharCode); } + + + bool serialize (hb_serialize_context_t *c, + const hb_vector_t &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 &groups) + { + return 16 + 12 * groups.len; + } + + static inline bool create_sub_table_plan (const hb_subset_plan_t *plan, + hb_vector_t *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 @@ -531,6 +594,29 @@ struct 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 groups; + }; + inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -539,50 +625,13 @@ struct cmap encodingRecord.sanitize (c, this)); } - static inline bool _is_gid_consecutive (CmapSubtableLongGroup *group, - hb_codepoint_t cp, - hb_codepoint_t new_gid) + inline bool _create_plan (const hb_subset_plan_t *plan, + subset_plan *cmap_plan) const { - return (cp - 1 == group->endCharCode) && - new_gid == group->glyphID + (cp - group->startCharCode); + return CmapSubtableFormat12::create_sub_table_plan (plan, &cmap_plan->groups); } - inline bool populate_groups (hb_subset_plan_t *plan, - hb_vector_t *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 &groups, + inline bool _subset (const subset_plan &cmap_subset_plan, size_t dest_sz, void *dest) const { @@ -602,19 +651,12 @@ struct cmap rec.platformID.set (3); // Windows rec.encodingID.set (10); // Unicode UCS-4 - /* capture offset to subtable */ + // Write out format 12 sub table. CmapSubtable &subtable = rec.subtable.serialize (&c, cmap); - subtable.u.format.set (12); CmapSubtableFormat12 &format12 = subtable.u.format12; - if (unlikely (!c.extend_min (format12))) 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; + if (unlikely (!format12.serialize (&c, cmap_subset_plan.groups))) return false; c.end_serialize (); @@ -623,24 +665,25 @@ struct cmap inline bool subset (hb_subset_plan_t *plan) const { - hb_auto_t > 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 - // TODO use APIs from the structs to get size? - size_t dest_sz = 4 // header - + 8 // 1 EncodingRecord - + 16 // Format 12 header - + 12 * groups.len; // SequentialMapGroup records + size_t dest_sz = cmap_subset_plan.final_size(); void *dest = malloc (dest_sz); if (unlikely (!dest)) { DEBUG_MSG(SUBSET, nullptr, "Unable to alloc %lu for cmap subset output", (unsigned long) dest_sz); 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); return false; }