From 9275bd03ea427eb607dde6a8e65f78a350b88323 Mon Sep 17 00:00:00 2001 From: Rod Sheeter Date: Fri, 9 Feb 2018 17:33:34 -0800 Subject: [PATCH] First pass at building a cmap --- src/hb-ot-cmap-table.hh | 103 ++++++++++++++++++++++++++++++++++++---- src/hb-subset.cc | 37 ++++++++------- 2 files changed, 115 insertions(+), 25 deletions(-) diff --git a/src/hb-ot-cmap-table.hh b/src/hb-ot-cmap-table.hh index bb3eba47..daee6ca5 100644 --- a/src/hb-ot-cmap-table.hh +++ b/src/hb-ot-cmap-table.hh @@ -254,6 +254,8 @@ struct CmapSubtableFormat10 : CmapSubtableTrimmed {}; template struct CmapSubtableLongSegmented { + friend struct cmap; + inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const { int i = groups.bsearch (codepoint); @@ -269,6 +271,20 @@ struct CmapSubtableLongSegmented return_trace (c->check_struct (this) && groups.sanitize (c)); } + inline bool serialize(hb_serialize_context_t *context, + unsigned int group_count, + Supplier &group_supplier) + { + TRACE_SERIALIZE (this); + if (unlikely(!context->extend_min (*this))) return_trace (false); + if (unlikely(!groups.serialize(context, group_count))) return_trace (false); + for (unsigned int i = 0; i < group_count; i++) { + const CmapSubtableLongGroup &group = group_supplier[i]; + memcpy(&groups[i], &group, sizeof(group)); + } + return true; + } + protected: HBUINT16 format; /* Subtable format; set to 12. */ HBUINT16 reservedZ; /* Reserved; set to 0. */ @@ -505,15 +521,15 @@ struct cmap encodingRecord.sanitize (c, this)); } - inline bool subset (hb_subset_plan_t *plan, hb_face_t *source, hb_face_t *dest) const + inline void populate_groups(hb_auto_array_t &codepoints, + hb_auto_array_t *groups) const { - hb_auto_array_t groups; CmapSubtableLongGroup *group = nullptr; - for (unsigned int i = 0; i < plan->codepoints.len; i++) { - hb_codepoint_t cp = plan->codepoints[i]; + for (unsigned int i = 0; i < codepoints.len; i++) { + hb_codepoint_t cp = codepoints[i]; if (!group) { - group = groups.push(); + group = groups->push(); group->startCharCode.set(cp); group->endCharCode.set(cp); group->glyphID.set(i); // index in codepoints is new gid @@ -527,13 +543,84 @@ struct cmap } 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, first gid %d", i, (uint32_t) group.startCharCode, (uint32_t) group.endCharCode, (uint32_t) group.glyphID); + 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)); + } + } + + hb_bool_t _subset (hb_auto_array_t &groups, + size_t dest_sz, + void *dest) const + { + hb_serialize_context_t context(dest, dest_sz); + + OT::cmap *cmap = context.start_serialize (); + if (unlikely(!context.extend_min(*cmap))) + { + return false; + } + + cmap->version.set(0); + + if (unlikely(!cmap->encodingRecord.serialize(&context, /* numTables */ 1))) + { + return false; } + + EncodingRecord &rec = cmap->encodingRecord[0]; + rec.platformID.set (3); // Windows + rec.encodingID.set (1); // Unicode BMP + + CmapSubtable &subtable = rec.subtable.serialize(&context, &rec.subtable); + subtable.u.format.set(12); + + CmapSubtableFormat12 &format12 = subtable.u.format12; + format12.format.set(12); + format12.reservedZ.set(0); + + OT::Supplier group_supplier (&groups[0], groups.len, sizeof (CmapSubtableLongGroup)); + if (unlikely(!format12.serialize(&context, groups.len, group_supplier))) + { + return false; + } + + context.end_serialize (); return true; } + hb_blob_t * subset (hb_subset_plan_t *plan, hb_face_t *source) const + { + hb_auto_array_t groups; + + populate_groups(plan->codepoints, &groups); + + // 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 + void *dest = calloc(dest_sz, 1); + if (unlikely(!dest)) { + DEBUG_MSG(SUBSET, nullptr, "Unable to alloc %ld for cmap subset output", dest_sz); + return nullptr; + } + + if (unlikely(!_subset(groups, dest_sz, dest))) + { + free(dest); + return nullptr; + } + + // all done, write the blob into dest + return hb_blob_create((const char *)dest, + dest_sz, + HB_MEMORY_MODE_READONLY, + /* userdata */ nullptr, + free); + } + struct accelerator_t { inline void init (hb_face_t *face) diff --git a/src/hb-subset.cc b/src/hb-subset.cc index 98565c30..8e1f8198 100644 --- a/src/hb-subset.cc +++ b/src/hb-subset.cc @@ -108,19 +108,19 @@ hb_subset_input_destroy(hb_subset_input_t *subset_input) } template -hb_bool_t -subset (hb_subset_plan_t *plan, hb_face_t *source, hb_face_t *dest) +hb_blob_t * +_subset (hb_subset_plan_t *plan, hb_face_t *source) { OT::Sanitizer sanitizer; - hb_blob_t *table_blob = sanitizer.sanitize (source->reference_table (TableType::tableTag)); - if (unlikely(!table_blob)) { + hb_blob_t *source_blob = sanitizer.sanitize (source->reference_table (TableType::tableTag)); + if (unlikely(!source_blob)) { DEBUG_MSG(SUBSET, nullptr, "Failed to reference table for tag %d", TableType::tableTag); - return false; + return nullptr; } - const TableType *table = OT::Sanitizer::lock_instance (table_blob); - hb_bool_t result = table->subset(plan, source, dest); + const TableType *table = OT::Sanitizer::lock_instance (source_blob); + hb_blob_t *result = table->subset(plan, source); - hb_blob_destroy (table_blob); + hb_blob_destroy (source_blob); hb_tag_t tag = TableType::tableTag; DEBUG_MSG(SUBSET, nullptr, "Subset %c%c%c%c %s", HB_UNTAG(tag), result ? "success" : "FAILED!"); @@ -242,7 +242,6 @@ hb_subset_face_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob) return false; hb_subset_face_data_t *data = (hb_subset_face_data_t *) face->user_data; - hb_subset_face_data_t::table_entry_t *entry = data->tables.push (); if (unlikely (!entry)) return false; @@ -306,10 +305,12 @@ bool _subset_table (hb_subset_plan_t *plan, hb_face_t *source, hb_tag_t tag, - hb_blob_t *table_blob, + hb_blob_t *source_blob, hb_face_t *dest) { // TODO (grieger): Handle updating the head table (loca format + num glyphs) + DEBUG_MSG(SUBSET, nullptr, "begin subset %c%c%c%c", HB_UNTAG(tag)); + hb_blob_t *dest_blob; switch (tag) { case HB_OT_TAG_glyf: return _subset_glyf (plan, source, dest); @@ -320,14 +321,16 @@ _subset_table (hb_subset_plan_t *plan, // SKIP loca, it's handle by glyf return true; case HB_OT_TAG_cmap: - // TODO(rsheeter): remove hb_subset_face_add_table - // once cmap subsetting works. - hb_subset_face_add_table (dest, tag, table_blob); - return subset (plan, source, dest); + dest_blob = _subset (plan, source); + break; default: - // Default action, copy table as is. - return hb_subset_face_add_table (dest, tag, table_blob); - } + dest_blob = source_blob; + break; + } + DEBUG_MSG(SUBSET, nullptr, "subset %c%c%c%c %s", HB_UNTAG(tag), dest_blob ? "ok" : "FAILED"); + if (unlikely(!dest_blob)) return false; + if (unlikely(!hb_subset_face_add_table (dest, tag, dest_blob))) return false; + return true; } /** -- GitLab