From 37572882e7a685d804384eaf11f0f3e53af38341 Mon Sep 17 00:00:00 2001 From: Qunxin Liu Date: Tue, 25 Jun 2019 13:17:30 -0700 Subject: [PATCH] [subset] cmap table to use _subset2 and new iterator frameworks --- src/hb-ot-cmap-table.hh | 670 +++++++++++------------ src/hb-subset.cc | 2 +- test/api/fonts/Roboto-Regular.D7,D8,D9,DA,DE.ttf | Bin 2816 -> 2532 bytes test/api/fonts/Roboto-Regular.abc.ttf | Bin 2460 -> 2168 bytes test/api/fonts/Roboto-Regular.ac.ttf | Bin 2268 -> 1988 bytes 5 files changed, 320 insertions(+), 352 deletions(-) diff --git a/src/hb-ot-cmap-table.hh b/src/hb-ot-cmap-table.hh index d79b549..746e87f 100644 --- a/src/hb-ot-cmap-table.hh +++ b/src/hb-ot-cmap-table.hh @@ -74,153 +74,201 @@ struct CmapSubtableFormat0 struct CmapSubtableFormat4 { - struct segment_plan - { - HBUINT16 start_code; - HBUINT16 end_code; - bool use_delta; - }; - bool serialize (hb_serialize_context_t *c, - const hb_subset_plan_t *plan, - const hb_sorted_vector_t &segments) + template + HBUINT16* serialize_endcode_array (hb_serialize_context_t *c, + Iterator it) { - TRACE_SERIALIZE (this); - - if (unlikely (!c->extend_min (*this))) return_trace (false); - - this->format = 4; - this->length = get_sub_table_size (segments); - - this->segCountX2 = segments.length * 2; - this->entrySelector = hb_max (1u, hb_bit_storage (segments.length)) - 1; - this->searchRange = 2 * (1u << this->entrySelector); - this->rangeShift = segments.length * 2 > this->searchRange - ? 2 * segments.length - this->searchRange - : 0; - - HBUINT16 *end_count = c->allocate_size (HBUINT16::static_size * segments.length); - c->allocate_size (HBUINT16::static_size); // 2 bytes of padding. - HBUINT16 *start_count = c->allocate_size (HBUINT16::static_size * segments.length); - HBINT16 *id_delta = c->allocate_size (HBUINT16::static_size * segments.length); - HBUINT16 *id_range_offset = c->allocate_size (HBUINT16::static_size * segments.length); - - if (id_range_offset == nullptr) - return_trace (false); + HBUINT16 *endCode = c->start_embed (); + hb_codepoint_t prev_endcp = 0xFFFF; + + + it + | hb_apply ([&] (const hb_item_type _) + { + if (prev_endcp != 0xFFFF && prev_endcp + 1u != _.first) + { + HBUINT16 end_code; + end_code = prev_endcp; + c->copy (end_code); + } + prev_endcp = _.first; + }) + ; - for (unsigned int i = 0; i < segments.length; i++) { - end_count[i] = segments[i].end_code; - start_count[i] = segments[i].start_code; - if (segments[i].use_delta) + // last endCode + HBUINT16 endcode; + endcode = prev_endcp; + if (unlikely (!c->copy (endcode))) return nullptr; + // There must be a final entry with end_code == 0xFFFF. + if (prev_endcp != 0xFFFF) { - hb_codepoint_t cp = segments[i].start_code; - hb_codepoint_t start_gid = 0; - if (unlikely (!plan->new_gid_for_codepoint (cp, &start_gid) && cp != 0xFFFF)) - return_trace (false); - id_delta[i] = start_gid - segments[i].start_code; - } else { - id_delta[i] = 0; - unsigned int num_codepoints = segments[i].end_code - segments[i].start_code + 1; - HBUINT16 *glyph_id_array = c->allocate_size (HBUINT16::static_size * num_codepoints); - if (glyph_id_array == nullptr) - return_trace (false); - // From the cmap spec: - // - // id_range_offset[i]/2 - // + (cp - segments[i].start_code) - // + (id_range_offset + i) - // = - // glyph_id_array + (cp - segments[i].start_code) - // - // So, solve for id_range_offset[i]: - // - // id_range_offset[i] - // = - // 2 * (glyph_id_array - id_range_offset - i) - id_range_offset[i] = 2 * (glyph_id_array - id_range_offset - i); - for (unsigned int j = 0; j < num_codepoints; j++) - { - hb_codepoint_t cp = segments[i].start_code + j; - hb_codepoint_t new_gid = 0; - if (unlikely (!plan->new_gid_for_codepoint (cp, &new_gid))) - return_trace (false); - glyph_id_array[j] = new_gid; - } + HBUINT16 finalcode; + finalcode = 0xFFFF; + if (unlikely (!c->copy (finalcode))) return nullptr; } } - return_trace (true); + return endCode; } - static size_t get_sub_table_size (const hb_sorted_vector_t &segments) + template + HBUINT16* serialize_startcode_array (hb_serialize_context_t *c, + Iterator it) { - size_t segment_size = 0; - for (unsigned int i = 0; i < segments.length; i++) + HBUINT16 *startCode = c->start_embed (); + hb_codepoint_t prev_cp = 0xFFFF; + + + it + | hb_apply ([&] (const hb_item_type _) + { + if (prev_cp == 0xFFFF || prev_cp + 1u != _.first) + { + HBUINT16 start_code; + start_code = _.first; + c->copy (start_code); + } + + prev_cp = _.first; + }) + ; + + // There must be a final entry with end_code == 0xFFFF. + if (it.len () == 0 || prev_cp != 0xFFFF) { - // Parallel array entries - segment_size += - 2 // end count - + 2 // start count - + 2 // delta - + 2; // range offset - - if (!segments[i].use_delta) - // Add bytes for the glyph index array entries for this segment. - segment_size += (segments[i].end_code - segments[i].start_code + 1) * 2; + HBUINT16 finalcode; + finalcode = 0xFFFF; + if (unlikely (!c->copy (finalcode))) return nullptr; } - return min_size - + 2 // Padding - + segment_size; + return startCode; } - static bool create_sub_table_plan (const hb_subset_plan_t *plan, - hb_sorted_vector_t *segments) + template + HBINT16* serialize_idDelta_array (hb_serialize_context_t *c, + Iterator it, + HBUINT16 *endCode, + HBUINT16 *startCode, + unsigned segcount) { - segment_plan *segment = nullptr; - hb_codepoint_t last_gid = 0; + unsigned i = 0; + hb_codepoint_t last_gid = 0, start_gid = 0, last_cp = 0xFFFF; + bool use_delta = true; + + HBINT16 *idDelta = c->start_embed (); + if ((char *)idDelta - (char *)startCode != (int) segcount * (int) HBINT16::static_size) + return nullptr; - hb_codepoint_t cp = HB_SET_VALUE_INVALID; - while (plan->unicodes->next (&cp)) { - hb_codepoint_t new_gid = 0; - if (unlikely (!plan->new_gid_for_codepoint (cp, &new_gid))) - { - DEBUG_MSG(SUBSET, nullptr, "Unable to find new gid for %04x", cp); - return false; - } + + it + | hb_apply ([&] (const hb_item_type _) + { + if (_.first == startCode[i]) + { + use_delta = true; + start_gid = _.second; + } + else if (_.second != last_gid + 1) use_delta = false; + + if (_.first == endCode[i]) + { + HBINT16 delta; + if (use_delta) delta = (int)start_gid - (int)startCode[i]; + else delta = 0; + c->copy (delta); + + i++; + } + + last_gid = _.second; + last_cp = _.first; + }) + ; - /* Stop adding to cmap if we are now outside of unicode BMP. */ - if (cp > 0xFFFF) break; + if (it.len () == 0 || last_cp != 0xFFFF) + { + HBINT16 delta; + delta = 1; + if (unlikely (!c->copy (delta))) return nullptr; + } - if (!segment || - cp != segment->end_code + 1u) - { - segment = segments->push (); - segment->start_code = cp; - segment->end_code = cp; - segment->use_delta = true; - } else { - segment->end_code = cp; - if (last_gid + 1u != new_gid) - // gid's are not consecutive in this segment so delta - // cannot be used. - segment->use_delta = false; - } + return idDelta; + } - last_gid = new_gid; - } + template + HBUINT16* serialize_rangeoffset_glyid (hb_serialize_context_t *c, + Iterator it, + HBUINT16 *endCode, + HBUINT16 *startCode, + HBINT16 *idDelta, + unsigned segcount) + { + HBUINT16 *idRangeOffset = c->allocate_size (HBUINT16::static_size * segcount); + if (unlikely (!c->check_success (idRangeOffset))) return nullptr; + if (unlikely ((char *)idRangeOffset - (char *)idDelta != (int) segcount * (int) HBINT16::static_size)) return nullptr; + + + hb_range (segcount) + | hb_filter ([&] (const unsigned _) { return idDelta[_] == 0; }) + | hb_apply ([&] (const unsigned i) + { + idRangeOffset[i] = 2 * (c->start_embed () - idRangeOffset - i); + + + it + | hb_filter ([&] (const hb_item_type _) { return _.first >= startCode[i] && _.first <= endCode[i]; }) + | hb_apply ([&] (const hb_item_type _) + { + HBUINT16 glyID; + glyID = _.second; + c->copy (glyID); + }) + ; + + + }) + ; - // There must be a final entry with end_code == 0xFFFF. Check if we need to add one. - if (segment == nullptr || segment->end_code != 0xFFFF) - { - segment = segments->push (); - segment->start_code = 0xFFFF; - segment->end_code = 0xFFFF; - segment->use_delta = true; - } + return idRangeOffset; + } - return true; + template + void serialize (hb_serialize_context_t *c, + Iterator it) + { + unsigned table_initpos = c->length (); + if (unlikely (!c->extend_min (*this))) return; + this->format = 4; + + //serialize endCode[] + HBUINT16 *endCode = serialize_endcode_array (c, it); + if (unlikely (!endCode)) return; + + unsigned segcount = (c->length () - min_size) / HBUINT16::static_size; + + // 2 bytes of padding. + if (unlikely (!c->allocate_size (HBUINT16::static_size))) return; // 2 bytes of padding. + + // serialize startCode[] + HBUINT16 *startCode = serialize_startcode_array (c, it); + if (unlikely (!startCode)) return; + + //serialize idDelta[] + HBINT16 *idDelta = serialize_idDelta_array (c, it, endCode, startCode, segcount); + if (unlikely (!idDelta)) return; + + HBUINT16 *idRangeOffset = serialize_rangeoffset_glyid (c, it, endCode, startCode, idDelta, segcount); + if (unlikely (!c->check_success (idRangeOffset))) return; + + if (unlikely (!c->check_assign(this->length, c->length () - table_initpos))) return; + this->segCountX2 = segcount * 2; + this->entrySelector = hb_max (1u, hb_bit_storage (segcount)) - 1; + this->searchRange = 2 * (1u << this->entrySelector); + this->rangeShift = segcount * 2 > this->searchRange + ? 2 * segcount - this->searchRange + : 0; } struct accelerator_t @@ -489,15 +537,6 @@ struct CmapSubtableLongSegmented return_trace (c->check_struct (this) && groups.sanitize (c)); } - bool serialize (hb_serialize_context_t *c, - const hb_sorted_vector_t &group_data) - { - TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (*this))) return_trace (false); - if (unlikely (!groups.serialize (c, group_data.as_array ()))) return_trace (false); - return_trace (true); - } - protected: HBUINT16 format; /* Subtable format; set to 12. */ HBUINT16 reserved; /* Reserved; set to 0. */ @@ -517,17 +556,56 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented group.glyphID + (u - group.startCharCode) : 0; } - bool serialize (hb_serialize_context_t *c, - const hb_sorted_vector_t &groups_data) + template + void serialize (hb_serialize_context_t *c, + Iterator it) { - TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (*this))) return_trace (false); + if (it.len () == 0) return; + unsigned table_initpos = c->length (); + if (unlikely (!c->extend_min (*this))) return; + + hb_codepoint_t startCharCode = 0xFFFF, endCharCode = 0xFFFF; + hb_codepoint_t glyphID = 0; + + + it + | hb_apply ([&] (const hb_item_type _) + { + if (startCharCode == 0xFFFF) + { + startCharCode = _.first; + endCharCode = _.first; + glyphID = _.second; + } + else if (!_is_gid_consecutive (endCharCode, startCharCode, glyphID, _.first, _.second)) + { + CmapSubtableLongGroup grouprecord; + grouprecord.startCharCode = startCharCode; + grouprecord.endCharCode = endCharCode; + grouprecord.glyphID = glyphID; + c->copy (grouprecord); + + startCharCode = _.first; + endCharCode = _.first; + glyphID = _.second; + } + else + { + endCharCode = _.first; + } + }) + ; + + CmapSubtableLongGroup record; + record.startCharCode = startCharCode; + record.endCharCode = endCharCode; + record.glyphID = glyphID; + c->copy (record); this->format = 12; this->reserved = 0; - this->length = get_sub_table_size (groups_data); - - return_trace (CmapSubtableLongSegmented::serialize (c, groups_data)); + this->length = c->length () - table_initpos; + this->groups.len = (this->length - min_size)/CmapSubtableLongGroup::static_size; } static size_t get_sub_table_size (const hb_sorted_vector_t &groups_data) @@ -535,46 +613,15 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented return 16 + 12 * groups_data.length; } - static bool create_sub_table_plan (const hb_subset_plan_t *plan, - hb_sorted_vector_t *groups_out) - { - CmapSubtableLongGroup *group = nullptr; - - hb_codepoint_t cp = HB_SET_VALUE_INVALID; - while (plan->unicodes->next (&cp)) { - hb_codepoint_t new_gid = 0; - if (unlikely (!plan->new_gid_for_codepoint (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_out->push (); - group->startCharCode = cp; - group->endCharCode = cp; - group->glyphID = new_gid; - } - else group->endCharCode = cp; - } - - DEBUG_MSG(SUBSET, nullptr, "cmap"); - for (unsigned int i = 0; i < groups_out->length; i++) { - CmapSubtableLongGroup& group = (*groups_out)[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 bool _is_gid_consecutive (CmapSubtableLongGroup *group, + static bool _is_gid_consecutive (hb_codepoint_t endCharCode, + hb_codepoint_t startCharCode, + hb_codepoint_t glyphID, hb_codepoint_t cp, hb_codepoint_t new_gid) { - return (cp - 1 == group->endCharCode) && - new_gid == group->glyphID + (cp - group->startCharCode); + return (cp - 1 == endCharCode) && + new_gid == glyphID + (cp - startCharCode); } }; @@ -756,12 +803,10 @@ struct CmapSubtable hb_codepoint_t *glyph) const { switch (u.format) { -#ifndef HB_NO_CMAP_LEGACY_SUBTABLES case 0: return u.format0 .get_glyph (codepoint, glyph); + case 4: return u.format4 .get_glyph (codepoint, glyph); case 6: return u.format6 .get_glyph (codepoint, glyph); case 10: return u.format10.get_glyph (codepoint, glyph); -#endif - case 4: return u.format4 .get_glyph (codepoint, glyph); case 12: return u.format12.get_glyph (codepoint, glyph); case 13: return u.format13.get_glyph (codepoint, glyph); case 14: @@ -771,12 +816,10 @@ struct CmapSubtable void collect_unicodes (hb_set_t *out) const { switch (u.format) { -#ifndef HB_NO_CMAP_LEGACY_SUBTABLES case 0: u.format0 .collect_unicodes (out); return; + case 4: u.format4 .collect_unicodes (out); return; case 6: u.format6 .collect_unicodes (out); return; case 10: u.format10.collect_unicodes (out); return; -#endif - case 4: u.format4 .collect_unicodes (out); return; case 12: u.format12.collect_unicodes (out); return; case 13: u.format13.collect_unicodes (out); return; case 14: @@ -784,17 +827,28 @@ struct CmapSubtable } } + template + void serialize (hb_serialize_context_t *c, + Iterator it, + unsigned format) + { + switch (format) { + case 4: u.format4.serialize (c, it); return; + case 12: u.format12.serialize (c, it); return; + default: return; + } + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return_trace (false); switch (u.format) { -#ifndef HB_NO_CMAP_LEGACY_SUBTABLES case 0: return_trace (u.format0 .sanitize (c)); + case 4: return_trace (u.format4 .sanitize (c)); case 6: return_trace (u.format6 .sanitize (c)); case 10: return_trace (u.format10.sanitize (c)); -#endif - case 4: return_trace (u.format4 .sanitize (c)); case 12: return_trace (u.format12.sanitize (c)); case 13: return_trace (u.format13.sanitize (c)); case 14: return_trace (u.format14.sanitize (c)); @@ -805,12 +859,10 @@ struct CmapSubtable public: union { HBUINT16 format; /* Format identifier */ -#ifndef HB_NO_CMAP_LEGACY_SUBTABLES CmapSubtableFormat0 format0; + CmapSubtableFormat4 format4; CmapSubtableFormat6 format6; CmapSubtableFormat10 format10; -#endif - CmapSubtableFormat4 format4; CmapSubtableFormat12 format12; CmapSubtableFormat13 format13; CmapSubtableFormat14 format14; @@ -839,6 +891,32 @@ struct EncodingRecord subtable.sanitize (c, base)); } + template + EncodingRecord* copy (hb_serialize_context_t *c, + Iterator it, + unsigned format, + void *base, + /* INOUT */ unsigned *objidx) const + { + TRACE_SERIALIZE (this); + auto *out = c->embed (this); + if (unlikely (!out)) return_trace (nullptr); + out->subtable = 0; + + if (*objidx == 0) + { + CmapSubtable *cmapsubtable = c->push (); + unsigned origin_length = c->length (); + cmapsubtable->serialize (c, it, format); + if (c->length () - origin_length > 0) *objidx = c->pop_pack (); + else c->pop_discard (); + } + + c->add_link (out->subtable, *objidx, base); + return_trace (out); + } + HBUINT16 platformID; /* Platform ID. */ HBUINT16 encodingID; /* Platform-specific encoding ID. */ LOffsetTo @@ -851,182 +929,62 @@ struct cmap { static constexpr hb_tag_t tableTag = HB_OT_TAG_cmap; - struct subset_plan + template + 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) { - size_t final_size () const - { - return 4 // header - + 8 * num_enc_records - + CmapSubtableFormat4::get_sub_table_size (this->format4_segments) - + CmapSubtableFormat12::get_sub_table_size (this->format12_groups); - } + if (unlikely (!c->extend_min ((*this)))) return; + this->version = 0; - unsigned int num_enc_records; - bool has_unicode_bmp; - bool has_unicode_ucs4; - bool has_ms_bmp; - bool has_ms_ucs4; - hb_sorted_vector_t format4_segments; - hb_sorted_vector_t format12_groups; - }; + 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; - bool _create_plan (const hb_subset_plan_t *plan, - subset_plan *cmap_plan) const - { - cmap_plan->has_unicode_bmp = find_subtable (0, 3); - cmap_plan->has_unicode_ucs4 = find_subtable (0, 4); - cmap_plan->has_ms_bmp = find_subtable (3, 1); - cmap_plan->has_ms_ucs4 = find_subtable (3, 10); - cmap_plan->num_enc_records = cmap_plan->has_unicode_bmp + cmap_plan->has_unicode_ucs4 + cmap_plan->has_ms_bmp + cmap_plan->has_ms_ucs4; + 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); - if (unlikely (!CmapSubtableFormat4::create_sub_table_plan (plan, &cmap_plan->format4_segments))) - return false; - - if (!find_subtable (12)) return true; - return CmapSubtableFormat12::create_sub_table_plan (plan, &cmap_plan->format12_groups); } - bool _subset (const hb_subset_plan_t *plan, - const subset_plan &cmap_subset_plan, - size_t dest_sz, - void *dest) const + bool subset (hb_subset_context_t *c) const { - hb_serialize_context_t c (dest, dest_sz); - - cmap *table = c.start_serialize (); - if (unlikely (!c.extend_min (*table))) - { - return false; - } - - table->version = 0; - - if (unlikely (!table->encodingRecord.serialize (&c, cmap_subset_plan.num_enc_records))) return false; - - // TODO(grieger): Convert the below to a for loop - int enc_index = 0; - int unicode_bmp_index = 0; - int unicode_ucs4_index = 0; - int ms_bmp_index = 0; - int ms_ucs4_index = 0; - - // Format 4, Plat 0 Encoding Record - if (cmap_subset_plan.has_unicode_bmp) - { - unicode_bmp_index = enc_index; - EncodingRecord &format4_plat0_rec = table->encodingRecord[enc_index++]; - format4_plat0_rec.platformID = 0; // Unicode - format4_plat0_rec.encodingID = 3; - } - - // Format 12, Plat 0 Encoding Record - if (cmap_subset_plan.has_unicode_ucs4) - { - unicode_ucs4_index = enc_index; - EncodingRecord &format12_rec = table->encodingRecord[enc_index++]; - format12_rec.platformID = 0; // Unicode - format12_rec.encodingID = 4; // Unicode UCS-4 - } - - // Format 4, Plat 3 Encoding Record - if (cmap_subset_plan.has_ms_bmp) - { - ms_bmp_index = enc_index; - EncodingRecord &format4_plat3_rec = table->encodingRecord[enc_index++]; - format4_plat3_rec.platformID = 3; // Windows - format4_plat3_rec.encodingID = 1; // Unicode BMP - } + TRACE_SUBSET (this); - // Format 12, Plat 3 Encoding Record - if (cmap_subset_plan.has_ms_ucs4) - { - ms_ucs4_index = enc_index; - EncodingRecord &format12_rec = table->encodingRecord[enc_index++]; - format12_rec.platformID = 3; // Windows - format12_rec.encodingID = 10; // Unicode UCS-4 - } + cmap *cmap_prime = c->serializer->start_embed (); + if (unlikely (!c->serializer->check_success (cmap_prime))) return_trace (false); - // Write out format 4 sub table - { - if (unlikely (!cmap_subset_plan.has_unicode_bmp && !cmap_subset_plan.has_ms_bmp)) return false; - EncodingRecord &format4_rec = cmap_subset_plan.has_unicode_bmp? - table->encodingRecord[unicode_bmp_index]: - table->encodingRecord[ms_bmp_index]; - CmapSubtable &subtable = format4_rec.subtable.serialize (&c, table); - if (cmap_subset_plan.has_unicode_bmp && cmap_subset_plan.has_ms_bmp) - table->encodingRecord[ms_bmp_index].subtable = (unsigned int) format4_rec.subtable; - subtable.u.format = 4; - - CmapSubtableFormat4 &format4 = subtable.u.format4; - if (unlikely (!format4.serialize (&c, plan, cmap_subset_plan.format4_segments))) - return 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); - // Write out format 12 sub table. - if (cmap_subset_plan.format12_groups) - { - if (unlikely (!cmap_subset_plan.has_unicode_ucs4 && !cmap_subset_plan.has_ms_ucs4)) return false; - EncodingRecord &format12_rec = cmap_subset_plan.has_unicode_ucs4? - table->encodingRecord[unicode_ucs4_index]: - table->encodingRecord[ms_ucs4_index]; - - CmapSubtable &subtable = format12_rec.subtable.serialize (&c, table); - if (cmap_subset_plan.has_unicode_ucs4 && cmap_subset_plan.has_ms_ucs4) - table->encodingRecord[ms_ucs4_index].subtable = (unsigned int) format12_rec.subtable; - subtable.u.format = 12; - - CmapSubtableFormat12 &format12 = subtable.u.format12; - if (unlikely (!format12.serialize (&c, cmap_subset_plan.format12_groups))) - return false; - } - else - { - // FIXME: Merge this with above or, remove and tweak #final_size - // and rebase all the tests expectations - HBUINT32 empty; - empty = 0; - for (unsigned int i = 0; i < 4; ++i) c.copy (empty); - } - - c.end_serialize (); + if (unlikely (!unicode_bmp && !ms_bmp)) return_trace (false); + if (unlikely (has_format12 && (!unicode_ucs4 && !ms_ucs4))) return_trace (false); - return true; - } - bool subset (hb_subset_plan_t *plan) const - { - subset_plan cmap_subset_plan; - - 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 - 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 (plan, cmap_subset_plan, dest_sz, dest))) - { - DEBUG_MSG(SUBSET, nullptr, "Failed to perform subsetting of cmap."); - free (dest); - return false; - } + auto it = + + hb_iter (c->plan->unicodes) + | hb_map ([&] (hb_codepoint_t _) + { + hb_codepoint_t new_gid = HB_MAP_VALUE_INVALID; + c->plan->new_gid_for_codepoint (_, &new_gid); + return hb_pair_t (_, new_gid); + }) + | hb_filter ([&] (const hb_pair_t _) + { + return (_.second != HB_MAP_VALUE_INVALID); + }) + ; - // all done, write the blob into dest - hb_blob_t *cmap_prime = hb_blob_create ((const char *) dest, - dest_sz, - HB_MEMORY_MODE_READONLY, - dest, - free); - bool result = plan->add_table (HB_OT_TAG_cmap, cmap_prime); - hb_blob_destroy (cmap_prime); - return result; + cmap_prime->serialize (c->serializer, it, unicode_bmp, unicode_ucs4, ms_bmp, ms_ucs4); + return_trace (true); } const CmapSubtable *find_best_subtable (bool *symbol = nullptr) const @@ -1220,6 +1178,16 @@ struct cmap return &(this+result.subtable); } + const EncodingRecord *find_encodingrec (unsigned int platform_id, + unsigned int encoding_id) const + { + EncodingRecord key; + key.platformID = platform_id; + key.encodingID = encoding_id; + + return encodingRecord.as_array ().bsearch (key); + } + bool find_subtable (unsigned format) const { auto it = diff --git a/src/hb-subset.cc b/src/hb-subset.cc index b117870..6235a5b 100644 --- a/src/hb-subset.cc +++ b/src/hb-subset.cc @@ -187,7 +187,7 @@ _subset_table (hb_subset_plan_t *plan, DEBUG_MSG(SUBSET, nullptr, "skip loca handled by glyf"); return true; case HB_OT_TAG_cmap: - result = _subset (plan); + result = _subset2 (plan); break; case HB_OT_TAG_OS2: result = _subset2 (plan); diff --git a/test/api/fonts/Roboto-Regular.D7,D8,D9,DA,DE.ttf b/test/api/fonts/Roboto-Regular.D7,D8,D9,DA,DE.ttf index 3a71f53f2d0e2e246d409bbcb94255ff53918ada..7860f2f1bdb2610c03f8bc25eace0b5d81c2fdb3 100644 GIT binary patch delta 417 zcmXYtJxD@P6vzMXOMNC;D4`(r`WS))D@tkz8d?IONXG)7Ur)l97k!mAq_s8QhL)Bf z5LyDaupx*b5Q3(Lpe3lmp*9J@&VzP+}_CIDfRxR&0tw5huDg7}R%kzEHPhXGIiv;;3DG<$?pvi!4X?x#dDE(l{zzBE_CjNY zVp^B#a*2j@>;a};VdA2s0xpeM+tJOec-9vnUM5~(#j@2iks+?wJ}YI}W$yQh_?#AA zg~U^e9+b$lW1UX>JM8SH9O9Z|j(;mNd`pct5{{) delta 719 zcmYk4KWGzC9LK-+H z9OVXGTm&It2Qh*m9h^kLNpvgdAn4*C4vGfi_np=Hj`!~O`Tc(H`@XrCkK^kTYmfl! z&=?o-5ZNdQSdqI@up?ghL_*0((MOwuE|8?nbv3hBstTxz3%i^2_;P4B&XWujBUwJBj4!o5fk%HXT=-YsF6R52FJCW`}Lo%0AmkL zog3uU8;U<|r2SvYl=|e(yH$Tu&HBU8L4P}xx;?BO7N0X3)>U0mG+onmB9xt(WF+e1 z9pSs^Z%Rk~o^)(5D{o1IyGBv+x25ttOEM0KW;M(W(O|oXWsH%Q(7`26k8=qY8n}WM zOt^m6NQn!T`Ay}~2(cg@<90EUB#qZB97w?3c!V?^H)yKM&aOo5E5+CHc)gV?mc(2*RlC8RsjR z8oXw!;ya%(VEqqrGW6S8EXo9Zd!gL6AJ)YC2O07&^0IF2M&l4wAeOSe-l^%+`u}Tk zkr!TpG*6ZPNYb;h%-Md2%}M60xlvj3S;bshIDw*e^P-1uLu^Pq@l;UBHZF!IM2yRSBVbhn||phB=n`=K@dc*($+?6w>!= e!47Qt(B6BM9HFJ)DlYQLR?5}5DJwhf&_(*$t1yMk|7;65hbN7 z7hNdRWpyEf1(&Ial0V>1bmhjCi!KxeH$?*Ryh*8a(L3CE_uS9(?#ym%bF2#i;22*T z61nWvIh;oV2yM|jmAk%>4}^dAi9Zo<!Wai^G9gl}cPg2Q?=Kik z0kT*tTkWW>sR65u$7-fg9^C!>5b$jiXKHllAN;R~2gJ#m<+Nk2cu)L8<=2}fL%haU zVs#5GNYO1M@6bF^V#e1q4Db+EJ%h0lO^9969omL(3YRg3{6CHBWqtAZ#L3ABTvqWFi4P7W3X!8(X^F!nD>eZ=>|fmbnJs5yU8C!q?Ri|5J|oi=j+?R&6K-eZeP+PKTcsjG&ufk4W~VjatZWi}Cun za;?w}KwjN~qfQ~~H$`$zU^uu_jj&ip>^~RGfOQm5!U1fUsF2Fo P;q*}Un<1nAt*t7504rGq delta 729 zcmZ8fO=}ZT6g}@{CQU*}Kg1#-NT>t0wrZ)RbRk6~HVTDG6QPKUj>#m!&Ll%R)ufw3 z1##g*8J8ABT?j5*WT8lxF6u^#Ykz@#B2q*46Oj)-drK;+e(5#i^jSl>#Em#49Dw z_VGyW5$_VarTam4{B7Sh`&}k3R{W~>;9%t)hfM=wr)sZl`iS8K6MiruS#{f$>vIDU z1}7*lYGtpLG7UB0BjW=#$1We<`?dkdU&J#tIuf7E*Nn3vteO|JlEdOW@u=$OHcB=& z@Rj+hf6TL6zPuEP6Dxw*x_!ZO5_n3-tlwA*x*p2JI>B!`{;SHLFM!E`;zq|Z zwnZqSBZJU=)$-(-p(_ucr^18CL^AROW#cwHV-k15J=1!2SQ=9~vAAiNCJi3GPD_Sb z#nhePoeN)zv9K-9b~18DbXw5`5$=lOEJG5fRk9IhK~k41TOviYga+jFcoWi8&a#`Gq3VrFPRry4rMBk#_B% zjx>K49(L9Ft4_1dDZNU;nCd6!S(g~mspl}w7pSNIe|jW(M3nw(^=?IEinYgySel5X LiCF)L9P4`o4xM@y -- 2.7.4