diff options
Diffstat (limited to 'thirdparty/harfbuzz/src/hb-ot-layout-common.hh')
-rw-r--r-- | thirdparty/harfbuzz/src/hb-ot-layout-common.hh | 641 |
1 files changed, 488 insertions, 153 deletions
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-common.hh b/thirdparty/harfbuzz/src/hb-ot-layout-common.hh index 0ba7e3c061..65f499a00d 100644 --- a/thirdparty/harfbuzz/src/hb-ot-layout-common.hh +++ b/thirdparty/harfbuzz/src/hb-ot-layout-common.hh @@ -88,12 +88,66 @@ static inline void ClassDef_serialize (hb_serialize_context_t *c, Iterator it); static void ClassDef_remap_and_serialize (hb_serialize_context_t *c, - const hb_set_t &glyphset, const hb_map_t &gid_klass_map, hb_sorted_vector_t<HBGlyphID> &glyphs, const hb_set_t &klasses, + bool use_class_zero, hb_map_t *klass_map /*INOUT*/); + +struct hb_prune_langsys_context_t +{ + hb_prune_langsys_context_t (const void *table_, + hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> *script_langsys_map_, + const hb_map_t *duplicate_feature_map_, + hb_set_t *new_collected_feature_indexes_) + :table (table_), + script_langsys_map (script_langsys_map_), + duplicate_feature_map (duplicate_feature_map_), + new_feature_indexes (new_collected_feature_indexes_), + script_count (0),langsys_count (0) {} + + bool visitedScript (const void *s) + { + if (script_count++ > HB_MAX_SCRIPTS) + return true; + + return visited (s, visited_script); + } + + bool visitedLangsys (const void *l) + { + if (langsys_count++ > HB_MAX_LANGSYS) + return true; + + return visited (l, visited_langsys); + } + + private: + template <typename T> + bool visited (const T *p, hb_set_t &visited_set) + { + hb_codepoint_t delta = (hb_codepoint_t) ((uintptr_t) p - (uintptr_t) table); + if (visited_set.has (delta)) + return true; + + visited_set.add (delta); + return false; + } + + public: + const void *table; + hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> *script_langsys_map; + const hb_map_t *duplicate_feature_map; + hb_set_t *new_feature_indexes; + + private: + hb_set_t visited_script; + hb_set_t visited_langsys; + unsigned script_count; + unsigned langsys_count; +}; + struct hb_subset_layout_context_t : hb_dispatch_context_t<hb_subset_layout_context_t, hb_empty_t, HB_DEBUG_SUBSET> { @@ -125,16 +179,21 @@ struct hb_subset_layout_context_t : hb_subset_context_t *subset_context; const hb_tag_t table_tag; const hb_map_t *lookup_index_map; + const hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> *script_langsys_map; const hb_map_t *feature_index_map; + unsigned cur_script_index; hb_subset_layout_context_t (hb_subset_context_t *c_, hb_tag_t tag_, hb_map_t *lookup_map_, - hb_map_t *feature_map_) : + hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> *script_langsys_map_, + hb_map_t *feature_index_map_) : subset_context (c_), table_tag (tag_), lookup_index_map (lookup_map_), - feature_index_map (feature_map_), + script_langsys_map (script_langsys_map_), + feature_index_map (feature_index_map_), + cur_script_index (0xFFFFu), script_count (0), langsys_count (0), feature_index_count (0), @@ -325,7 +384,7 @@ struct Record } Tag tag; /* 4-byte Tag identifier */ - OffsetTo<Type> + Offset16To<Type> offset; /* Offset from beginning of object holding * the Record */ public: @@ -333,11 +392,11 @@ struct Record }; template <typename Type> -struct RecordArrayOf : SortedArrayOf<Record<Type>> +struct RecordArrayOf : SortedArray16Of<Record<Type>> { - const OffsetTo<Type>& get_offset (unsigned int i) const + const Offset16To<Type>& get_offset (unsigned int i) const { return (*this)[i].offset; } - OffsetTo<Type>& get_offset (unsigned int i) + Offset16To<Type>& get_offset (unsigned int i) { return (*this)[i].offset; } const Tag& get_tag (unsigned int i) const { return (*this)[i].tag; } @@ -356,7 +415,7 @@ struct RecordArrayOf : SortedArrayOf<Record<Type>> } bool find_index (hb_tag_t tag, unsigned int *index) const { - return this->bfind (tag, index, HB_BFIND_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX); + return this->bfind (tag, index, HB_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX); } }; @@ -407,6 +466,30 @@ struct RecordListOfFeature : RecordListOf<Feature> } }; +struct Script; +struct RecordListOfScript : RecordListOf<Script> +{ + bool subset (hb_subset_context_t *c, + hb_subset_layout_context_t *l) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); + + unsigned count = this->len; + for (auto _ : + hb_zip (*this, hb_range (count))) + { + auto snap = c->serializer->snapshot (); + l->cur_script_index = _.second; + bool ret = _.first.subset (l, this); + if (!ret) c->serializer->revert (snap); + else out->len++; + } + + return_trace (true); + } +}; + struct RangeRecord { int cmp (hb_codepoint_t g) const @@ -434,7 +517,7 @@ struct RangeRecord DECLARE_NULL_NAMESPACE_BYTES (OT, RangeRecord); -struct IndexArray : ArrayOf<Index> +struct IndexArray : Array16Of<Index> { bool intersects (const hb_map_t *indexes) const { return hb_any (*this, indexes); } @@ -474,7 +557,7 @@ struct IndexArray : ArrayOf<Index> void add_indexes_to (hb_set_t* output /* OUT */) const { - output->add_array (arrayZ, len); + output->add_array (as_array ()); } }; @@ -506,18 +589,46 @@ struct LangSys return_trace (c->embed (*this)); } - bool operator == (const LangSys& o) const + bool compare (const LangSys& o, const hb_map_t *feature_index_map) const { - if (featureIndex.len != o.featureIndex.len || - reqFeatureIndex != o.reqFeatureIndex) + if (reqFeatureIndex != o.reqFeatureIndex) + return false; + + auto iter = + + hb_iter (featureIndex) + | hb_filter (feature_index_map) + | hb_map (feature_index_map) + ; + + auto o_iter = + + hb_iter (o.featureIndex) + | hb_filter (feature_index_map) + | hb_map (feature_index_map) + ; + + if (iter.len () != o_iter.len ()) return false; - for (const auto _ : + hb_zip (featureIndex, o.featureIndex)) + for (const auto _ : + hb_zip (iter, o_iter)) if (_.first != _.second) return false; return true; } + void collect_features (hb_prune_langsys_context_t *c) const + { + if (!has_required_feature () && !get_feature_count ()) return; + if (c->visitedLangsys (this)) return; + if (has_required_feature () && + c->duplicate_feature_map->has (reqFeatureIndex)) + c->new_feature_indexes->add (get_required_feature_index ()); + + + hb_iter (featureIndex) + | hb_filter (c->duplicate_feature_map) + | hb_sink (c->new_feature_indexes) + ; + } + bool subset (hb_subset_context_t *c, hb_subset_layout_context_t *l, const Tag *tag = nullptr) const @@ -581,6 +692,49 @@ struct Script bool has_default_lang_sys () const { return defaultLangSys != 0; } const LangSys& get_default_lang_sys () const { return this+defaultLangSys; } + void prune_langsys (hb_prune_langsys_context_t *c, + unsigned script_index) const + { + if (!has_default_lang_sys () && !get_lang_sys_count ()) return; + if (c->visitedScript (this)) return; + + if (!c->script_langsys_map->has (script_index)) + { + hb_set_t* empty_set = hb_set_create (); + if (unlikely (!c->script_langsys_map->set (script_index, empty_set))) + { + hb_set_destroy (empty_set); + return; + } + } + + unsigned langsys_count = get_lang_sys_count (); + if (has_default_lang_sys ()) + { + //only collect features from non-redundant langsys + const LangSys& d = get_default_lang_sys (); + d.collect_features (c); + + for (auto _ : + hb_zip (langSys, hb_range (langsys_count))) + { + const LangSys& l = this+_.first.offset; + if (l.compare (d, c->duplicate_feature_map)) continue; + + l.collect_features (c); + c->script_langsys_map->get (script_index)->add (_.second); + } + } + else + { + for (auto _ : + hb_zip (langSys, hb_range (langsys_count))) + { + const LangSys& l = this+_.first.offset; + l.collect_features (c); + c->script_langsys_map->get (script_index)->add (_.second); + } + } + } + bool subset (hb_subset_context_t *c, hb_subset_layout_context_t *l, const Tag *tag) const @@ -609,16 +763,17 @@ struct Script } } - + langSys.iter () - | hb_filter ([=] (const Record<LangSys>& record) {return l->visitLangSys (); }) - | hb_filter ([&] (const Record<LangSys>& record) - { - const LangSys& d = this+defaultLangSys; - const LangSys& l = this+record.offset; - return !(l == d); - }) - | hb_apply (subset_record_array (l, &(out->langSys), this)) - ; + const hb_set_t *active_langsys = l->script_langsys_map->get (l->cur_script_index); + if (active_langsys) + { + unsigned count = langSys.len; + + hb_zip (langSys, hb_range (count)) + | hb_filter (active_langsys, hb_second) + | hb_map (hb_first) + | hb_filter ([=] (const Record<LangSys>& record) {return l->visitLangSys (); }) + | hb_apply (subset_record_array (l, &(out->langSys), this)) + ; + } return_trace (bool (out->langSys.len) || defaultLang || l->table_tag == HB_OT_TAG_GSUB); } @@ -631,7 +786,7 @@ struct Script } protected: - OffsetTo<LangSys> + Offset16To<LangSys> defaultLangSys; /* Offset to DefaultLangSys table--from * beginning of Script table--may be Null */ RecordArrayOf<LangSys> @@ -641,7 +796,7 @@ struct Script DEFINE_SIZE_ARRAY_SIZED (4, langSys); }; -typedef RecordListOf<Script> ScriptList; +typedef RecordListOfScript ScriptList; /* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#size */ @@ -856,7 +1011,7 @@ struct FeatureParamsCharacterVariants * user-interface labels for the * feature parameters. (Must be zero * if numParameters is zero.) */ - ArrayOf<HBUINT24> + Array16Of<HBUINT24> characters; /* Array of the Unicode Scalar Value * of the characters for which this * feature provides glyph variants. @@ -953,7 +1108,7 @@ struct Feature auto *out = c->serializer->start_embed (*this); if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); - bool subset_featureParams = out->featureParams.serialize_subset (c, featureParams, this, tag); + out->featureParams.serialize_subset (c, featureParams, this, tag); auto it = + hb_iter (lookupIndex) @@ -962,8 +1117,9 @@ struct Feature ; out->lookupIndex.serialize (c->serializer, l, it); - return_trace (bool (it) || subset_featureParams - || (tag && *tag == HB_TAG ('p', 'r', 'e', 'f'))); + // The decision to keep or drop this feature is already made before we get here + // so always retain it. + return_trace (true); } bool sanitize (hb_sanitize_context_t *c, @@ -998,7 +1154,7 @@ struct Feature unsigned int new_offset_int = orig_offset - (((char *) this) - ((char *) closure->list_base)); - OffsetTo<FeatureParams> new_offset; + Offset16To<FeatureParams> new_offset; /* Check that it would not overflow. */ new_offset = new_offset_int; if (new_offset == new_offset_int && @@ -1010,7 +1166,7 @@ struct Feature return_trace (true); } - OffsetTo<FeatureParams> + Offset16To<FeatureParams> featureParams; /* Offset to Feature Parameters table (if one * has been defined for the feature), relative * to the beginning of the Feature Table; = Null @@ -1049,11 +1205,11 @@ struct Lookup unsigned int get_subtable_count () const { return subTable.len; } template <typename TSubTable> - const OffsetArrayOf<TSubTable>& get_subtables () const - { return reinterpret_cast<const OffsetArrayOf<TSubTable> &> (subTable); } + const Array16OfOffset16To<TSubTable>& get_subtables () const + { return reinterpret_cast<const Array16OfOffset16To<TSubTable> &> (subTable); } template <typename TSubTable> - OffsetArrayOf<TSubTable>& get_subtables () - { return reinterpret_cast<OffsetArrayOf<TSubTable> &> (subTable); } + Array16OfOffset16To<TSubTable>& get_subtables () + { return reinterpret_cast<Array16OfOffset16To<TSubTable> &> (subTable); } template <typename TSubTable> const TSubTable& get_subtable (unsigned int i) const @@ -1106,13 +1262,13 @@ struct Lookup unsigned int num_subtables) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (*this))) return_trace (false); + if (unlikely (!c->extend_min (this))) return_trace (false); lookupType = lookup_type; lookupFlag = lookup_props & 0xFFFFu; if (unlikely (!subTable.serialize (c, num_subtables))) return_trace (false); if (lookupFlag & LookupFlag::UseMarkFilteringSet) { - if (unlikely (!c->extend (*this))) return_trace (false); + if (unlikely (!c->extend (this))) return_trace (false); HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable); markFilteringSet = lookup_props >> 16; } @@ -1131,10 +1287,18 @@ struct Lookup const hb_set_t *glyphset = c->plan->glyphset_gsub (); unsigned int lookup_type = get_type (); + hb_iter (get_subtables <TSubTable> ()) - | hb_filter ([this, glyphset, lookup_type] (const OffsetTo<TSubTable> &_) { return (this+_).intersects (glyphset, lookup_type); }) + | hb_filter ([this, glyphset, lookup_type] (const Offset16To<TSubTable> &_) { return (this+_).intersects (glyphset, lookup_type); }) | hb_apply (subset_offset_array (c, out->get_subtables<TSubTable> (), this, lookup_type)) ; + if (lookupFlag & LookupFlag::UseMarkFilteringSet) + { + if (unlikely (!c->serializer->extend (out))) return_trace (false); + const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable); + HBUINT16 &outMarkFilteringSet = StructAfter<HBUINT16> (out->subTable); + outMarkFilteringSet = markFilteringSet; + } + return_trace (true); } @@ -1179,7 +1343,7 @@ struct Lookup private: HBUINT16 lookupType; /* Different enumerations for GSUB and GPOS */ HBUINT16 lookupFlag; /* Lookup qualifiers */ - ArrayOf<Offset16> + Array16Of<Offset16> subTable; /* Array of SubTables */ /*HBUINT16 markFilteringSetX[HB_VAR_ARRAY];*//* Index (base 0) into GDEF mark glyph sets * structure. This field is only present if bit @@ -1188,10 +1352,10 @@ struct Lookup DEFINE_SIZE_ARRAY (6, subTable); }; -typedef OffsetListOf<Lookup> LookupList; +typedef List16OfOffset16To<Lookup> LookupList; template <typename TLookup> -struct LookupOffsetList : OffsetListOf<TLookup> +struct LookupOffsetList : List16OfOffset16To<TLookup> { bool subset (hb_subset_context_t *c, hb_subset_layout_context_t *l) const @@ -1212,7 +1376,7 @@ struct LookupOffsetList : OffsetListOf<TLookup> bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (OffsetListOf<TLookup>::sanitize (c, this)); + return_trace (List16OfOffset16To<TLookup>::sanitize (c, this)); } }; @@ -1229,7 +1393,7 @@ struct CoverageFormat1 unsigned int get_coverage (hb_codepoint_t glyph_id) const { unsigned int i; - glyphArray.bfind (glyph_id, &i, HB_BFIND_NOT_FOUND_STORE, NOT_COVERED); + glyphArray.bfind (glyph_id, &i, HB_NOT_FOUND_STORE, NOT_COVERED); return i; } @@ -1250,19 +1414,25 @@ struct CoverageFormat1 bool intersects (const hb_set_t *glyphs) const { /* TODO Speed up, using hb_set_next() and bsearch()? */ - unsigned int count = glyphArray.len; - const HBGlyphID *arr = glyphArray.arrayZ; - for (unsigned int i = 0; i < count; i++) - if (glyphs->has (arr[i])) + for (const auto& g : glyphArray.as_array ()) + if (glyphs->has (g)) return true; return false; } bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { return glyphs->has (glyphArray[index]); } + void intersected_coverage_glyphs (const hb_set_t *glyphs, hb_set_t *intersect_glyphs) const + { + unsigned count = glyphArray.len; + for (unsigned i = 0; i < count; i++) + if (glyphs->has (glyphArray[i])) + intersect_glyphs->add (glyphArray[i]); + } + template <typename set_t> bool collect_coverage (set_t *glyphs) const - { return glyphs->add_sorted_array (glyphArray.arrayZ, glyphArray.len); } + { return glyphs->add_sorted_array (glyphArray.as_array ()); } public: /* Older compilers need this to be public. */ @@ -1284,7 +1454,7 @@ struct CoverageFormat1 protected: HBUINT16 coverageFormat; /* Format identifier--format = 1 */ - SortedArrayOf<HBGlyphID> + SortedArray16Of<HBGlyphID> glyphArray; /* Array of GlyphIDs--in numerical order */ public: DEFINE_SIZE_ARRAY (4, glyphArray); @@ -1308,7 +1478,7 @@ struct CoverageFormat2 bool serialize (hb_serialize_context_t *c, Iterator glyphs) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (*this))) return_trace (false); + if (unlikely (!c->extend_min (this))) return_trace (false); if (unlikely (!glyphs)) { @@ -1358,20 +1528,16 @@ struct CoverageFormat2 { /* TODO Speed up, using hb_set_next() and bsearch()? */ /* TODO(iter) Rewrite as dagger. */ - unsigned count = rangeRecord.len; - const RangeRecord *arr = rangeRecord.arrayZ; - for (unsigned i = 0; i < count; i++) - if (arr[i].intersects (glyphs)) + for (const auto& range : rangeRecord.as_array ()) + if (range.intersects (glyphs)) return true; return false; } bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { /* TODO(iter) Rewrite as dagger. */ - unsigned count = rangeRecord.len; - const RangeRecord *arr = rangeRecord.arrayZ; - for (unsigned i = 0; i < count; i++) { - const RangeRecord &range = arr[i]; + for (const auto& range : rangeRecord.as_array ()) + { if (range.value <= index && index < (unsigned int) range.value + (range.last - range.first) && range.intersects (glyphs)) @@ -1382,6 +1548,16 @@ struct CoverageFormat2 return false; } + void intersected_coverage_glyphs (const hb_set_t *glyphs, hb_set_t *intersect_glyphs) const + { + for (const auto& range : rangeRecord.as_array ()) + { + if (!range.intersects (glyphs)) continue; + for (hb_codepoint_t g = range.first; g <= range.last; g++) + if (glyphs->has (g)) intersect_glyphs->add (g); + } + } + template <typename set_t> bool collect_coverage (set_t *glyphs) const { @@ -1448,7 +1624,7 @@ struct CoverageFormat2 protected: HBUINT16 coverageFormat; /* Format identifier--format = 2 */ - SortedArrayOf<RangeRecord> + SortedArray16Of<RangeRecord> rangeRecord; /* Array of glyph ranges--ordered by * Start GlyphID. rangeCount entries * long */ @@ -1481,7 +1657,7 @@ struct Coverage bool serialize (hb_serialize_context_t *c, Iterator glyphs) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (*this))) return_trace (false); + if (unlikely (!c->extend_min (this))) return_trace (false); unsigned count = 0; unsigned num_ranges = 0; @@ -1564,6 +1740,16 @@ struct Coverage } } + void intersected_coverage_glyphs (const hb_set_t *glyphs, hb_set_t *intersect_glyphs) const + { + switch (u.format) + { + case 1: return u.format1.intersected_coverage_glyphs (glyphs, intersect_glyphs); + case 2: return u.format2.intersected_coverage_glyphs (glyphs, intersect_glyphs); + default:return ; + } + } + struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t> { static constexpr bool is_sorted_iterator = true; @@ -1645,10 +1831,10 @@ Coverage_serialize (hb_serialize_context_t *c, { c->start_embed<Coverage> ()->serialize (c, it); } static void ClassDef_remap_and_serialize (hb_serialize_context_t *c, - const hb_set_t &glyphset, const hb_map_t &gid_klass_map, hb_sorted_vector_t<HBGlyphID> &glyphs, const hb_set_t &klasses, + bool use_class_zero, hb_map_t *klass_map /*INOUT*/) { if (!klass_map) @@ -1660,7 +1846,7 @@ static void ClassDef_remap_and_serialize (hb_serialize_context_t *c, /* any glyph not assigned a class value falls into Class zero (0), * if any glyph assigned to class 0, remapping must start with 0->0*/ - if (glyphset.get_population () > gid_klass_map.get_population ()) + if (!use_class_zero) klass_map->set (0, 0); unsigned idx = klass_map->has (0) ? 1 : 0; @@ -1704,10 +1890,11 @@ struct ClassDefFormat1 Iterator it) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (*this))) return_trace (false); + if (unlikely (!c->extend_min (this))) return_trace (false); if (unlikely (!it)) { + classFormat = 1; startGlyph = 0; classValue.len = 0; return_trace (true); @@ -1730,7 +1917,10 @@ struct ClassDefFormat1 } bool subset (hb_subset_context_t *c, - hb_map_t *klass_map = nullptr /*OUT*/) const + hb_map_t *klass_map = nullptr /*OUT*/, + bool keep_empty_table = true, + bool use_class_zero = true, + const Coverage* glyph_filter = nullptr) const { TRACE_SUBSET (this); const hb_set_t &glyphset = *c->plan->glyphset_gsub (); @@ -1742,9 +1932,12 @@ struct ClassDefFormat1 hb_codepoint_t start = startGlyph; hb_codepoint_t end = start + classValue.len; + for (const hb_codepoint_t gid : + hb_range (start, end) - | hb_filter (glyphset)) + | hb_filter (glyphset)) { + if (glyph_filter && !glyph_filter->has(gid)) continue; + unsigned klass = classValue[gid - start]; if (!klass) continue; @@ -1753,9 +1946,13 @@ struct ClassDefFormat1 orig_klasses.add (klass); } - ClassDef_remap_and_serialize (c->serializer, glyphset, gid_org_klass_map, - glyphs, orig_klasses, klass_map); - return_trace ((bool) glyphs); + unsigned glyph_count = glyph_filter + ? hb_len (hb_iter (glyphset) | hb_filter (glyph_filter)) + : glyphset.get_population (); + use_class_zero = use_class_zero && glyph_count <= gid_org_klass_map.get_population (); + ClassDef_remap_and_serialize (c->serializer, gid_org_klass_map, + glyphs, orig_klasses, use_class_zero, klass_map); + return_trace (keep_empty_table || (bool) glyphs); } bool sanitize (hb_sanitize_context_t *c) const @@ -1829,10 +2026,28 @@ struct ClassDefFormat1 return false; } + void intersected_class_glyphs (const hb_set_t *glyphs, unsigned klass, hb_set_t *intersect_glyphs) const + { + unsigned count = classValue.len; + if (klass == 0) + { + hb_codepoint_t endGlyph = startGlyph + count -1; + for (hb_codepoint_t g : glyphs->iter ()) + if (g < startGlyph || g > endGlyph) + intersect_glyphs->add (g); + + return; + } + + for (unsigned i = 0; i < count; i++) + if (classValue[i] == klass && glyphs->has (startGlyph + i)) + intersect_glyphs->add (startGlyph + i); + } + protected: HBUINT16 classFormat; /* Format identifier--format = 1 */ HBGlyphID startGlyph; /* First GlyphID of the classValueArray */ - ArrayOf<HBUINT16> + Array16Of<HBUINT16> classValue; /* Array of Class Values--one per GlyphID */ public: DEFINE_SIZE_ARRAY (6, classValue); @@ -1854,10 +2069,11 @@ struct ClassDefFormat2 Iterator it) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (*this))) return_trace (false); + if (unlikely (!c->extend_min (this))) return_trace (false); if (unlikely (!it)) { + classFormat = 2; rangeRecord.len = 0; return_trace (true); } @@ -1903,7 +2119,10 @@ struct ClassDefFormat2 } bool subset (hb_subset_context_t *c, - hb_map_t *klass_map = nullptr /*OUT*/) const + hb_map_t *klass_map = nullptr /*OUT*/, + bool keep_empty_table = true, + bool use_class_zero = true, + const Coverage* glyph_filter = nullptr) const { TRACE_SUBSET (this); const hb_set_t &glyphset = *c->plan->glyphset_gsub (); @@ -1923,15 +2142,20 @@ struct ClassDefFormat2 for (hb_codepoint_t g = start; g < end; g++) { if (!glyphset.has (g)) continue; + if (glyph_filter && !glyph_filter->has (g)) continue; glyphs.push (glyph_map[g]); gid_org_klass_map.set (glyph_map[g], klass); orig_klasses.add (klass); } } - ClassDef_remap_and_serialize (c->serializer, glyphset, gid_org_klass_map, - glyphs, orig_klasses, klass_map); - return_trace ((bool) glyphs); + unsigned glyph_count = glyph_filter + ? hb_len (hb_iter (glyphset) | hb_filter (glyph_filter)) + : glyphset.get_population (); + use_class_zero = use_class_zero && glyph_count <= gid_org_klass_map.get_population (); + ClassDef_remap_and_serialize (c->serializer, gid_org_klass_map, + glyphs, orig_klasses, use_class_zero, klass_map); + return_trace (keep_empty_table || (bool) glyphs); } bool sanitize (hb_sanitize_context_t *c) const @@ -2005,9 +2229,57 @@ struct ClassDefFormat2 return false; } + void intersected_class_glyphs (const hb_set_t *glyphs, unsigned klass, hb_set_t *intersect_glyphs) const + { + unsigned count = rangeRecord.len; + if (klass == 0) + { + hb_codepoint_t g = HB_SET_VALUE_INVALID; + for (unsigned int i = 0; i < count; i++) + { + if (!hb_set_next (glyphs, &g)) + break; + while (g != HB_SET_VALUE_INVALID && g < rangeRecord[i].first) + { + intersect_glyphs->add (g); + hb_set_next (glyphs, &g); + } + g = rangeRecord[i].last; + } + while (g != HB_SET_VALUE_INVALID && hb_set_next (glyphs, &g)) + intersect_glyphs->add (g); + + return; + } + + hb_codepoint_t g = HB_SET_VALUE_INVALID; + for (unsigned int i = 0; i < count; i++) + { + if (rangeRecord[i].value != klass) continue; + + if (g != HB_SET_VALUE_INVALID) + { + if (g >= rangeRecord[i].first && + g <= rangeRecord[i].last) + intersect_glyphs->add (g); + if (g > rangeRecord[i].last) + continue; + } + + g = rangeRecord[i].first - 1; + while (hb_set_next (glyphs, &g)) + { + if (g >= rangeRecord[i].first && g <= rangeRecord[i].last) + intersect_glyphs->add (g); + else if (g > rangeRecord[i].last) + break; + } + } + } + protected: HBUINT16 classFormat; /* Format identifier--format = 2 */ - SortedArrayOf<RangeRecord> + SortedArray16Of<RangeRecord> rangeRecord; /* Array of glyph ranges--ordered by * Start GlyphID */ public: @@ -2036,19 +2308,20 @@ struct ClassDef template<typename Iterator, hb_requires (hb_is_iterator (Iterator))> - bool serialize (hb_serialize_context_t *c, Iterator it) + bool serialize (hb_serialize_context_t *c, Iterator it_with_class_zero) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (*this))) return_trace (false); + if (unlikely (!c->extend_min (this))) return_trace (false); + + auto it = + it_with_class_zero | hb_filter (hb_second); unsigned format = 2; if (likely (it)) { hb_codepoint_t glyph_min = (*it).first; - hb_codepoint_t glyph_max = + it - | hb_map (hb_first) - | hb_reduce (hb_max, 0u); + hb_codepoint_t glyph_max = glyph_min; + unsigned num_glyphs = 0; unsigned num_ranges = 1; hb_codepoint_t prev_gid = glyph_min; unsigned prev_klass = (*it).second; @@ -2057,7 +2330,9 @@ struct ClassDef { hb_codepoint_t cur_gid = gid_klass_pair.first; unsigned cur_klass = gid_klass_pair.second; - if (cur_gid == glyph_min || !cur_klass) continue; + num_glyphs++; + if (cur_gid == glyph_min) continue; + if (cur_gid > glyph_max) glyph_max = cur_gid; if (cur_gid != prev_gid + 1 || cur_klass != prev_klass) num_ranges++; @@ -2066,7 +2341,7 @@ struct ClassDef prev_klass = cur_klass; } - if (1 + (glyph_max - glyph_min + 1) <= num_ranges * 3) + if (num_glyphs && 1 + (glyph_max - glyph_min + 1) <= num_ranges * 3) format = 1; } u.format = format; @@ -2080,12 +2355,15 @@ struct ClassDef } bool subset (hb_subset_context_t *c, - hb_map_t *klass_map = nullptr /*OUT*/) const + hb_map_t *klass_map = nullptr /*OUT*/, + bool keep_empty_table = true, + bool use_class_zero = true, + const Coverage* glyph_filter = nullptr) const { TRACE_SUBSET (this); switch (u.format) { - case 1: return_trace (u.format1.subset (c, klass_map)); - case 2: return_trace (u.format2.subset (c, klass_map)); + case 1: return_trace (u.format1.subset (c, klass_map, keep_empty_table, use_class_zero, glyph_filter)); + case 2: return_trace (u.format2.subset (c, klass_map, keep_empty_table, use_class_zero, glyph_filter)); default:return_trace (false); } } @@ -2142,6 +2420,15 @@ struct ClassDef } } + void intersected_class_glyphs (const hb_set_t *glyphs, unsigned klass, hb_set_t *intersect_glyphs) const + { + switch (u.format) { + case 1: return u.format1.intersected_class_glyphs (glyphs, klass, intersect_glyphs); + case 2: return u.format2.intersected_class_glyphs (glyphs, klass, intersect_glyphs); + default:return; + } + } + protected: union { HBUINT16 format; /* Format identifier */ @@ -2229,19 +2516,19 @@ struct VarRegionList bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && - axesZ.sanitize (c, (unsigned int) axisCount * (unsigned int) regionCount)); + return_trace (c->check_struct (this) && axesZ.sanitize (c, axisCount * regionCount)); } bool serialize (hb_serialize_context_t *c, const VarRegionList *src, const hb_bimap_t ®ion_map) { TRACE_SERIALIZE (this); - VarRegionList *out = c->allocate_min<VarRegionList> (); - if (unlikely (!out)) return_trace (false); + if (unlikely (!c->extend_min (this))) return_trace (false); axisCount = src->axisCount; regionCount = region_map.get_population (); - if (unlikely (!c->allocate_size<VarRegionList> (get_size () - min_size))) return_trace (false); - unsigned int region_count = src->get_region_count (); + if (unlikely (hb_unsigned_mul_overflows (axisCount * regionCount, + VarRegionAxis::static_size))) return_trace (false); + if (unlikely (!c->extend (this))) return_trace (false); + unsigned int region_count = src->regionCount; for (unsigned int r = 0; r < regionCount; r++) { unsigned int backward = region_map.backward (r); @@ -2253,11 +2540,11 @@ struct VarRegionList } unsigned int get_size () const { return min_size + VarRegionAxis::static_size * axisCount * regionCount; } - unsigned int get_region_count () const { return regionCount; } - protected: + public: HBUINT16 axisCount; HBUINT16 regionCount; + protected: UnsizedArrayOf<VarRegionAxis> axesZ; public: @@ -2273,7 +2560,10 @@ struct VarData { return shortCount + regionIndices.len; } unsigned int get_size () const - { return itemCount * get_row_size (); } + { return min_size + - regionIndices.min_size + regionIndices.get_size () + + itemCount * get_row_size (); + } float get_delta (unsigned int inner, const int *coords, unsigned int coord_count, @@ -2307,10 +2597,10 @@ struct VarData return delta; } - void get_scalars (const int *coords, unsigned int coord_count, - const VarRegionList ®ions, - float *scalars /*OUT */, - unsigned int num_scalars) const + void get_region_scalars (const int *coords, unsigned int coord_count, + const VarRegionList ®ions, + float *scalars /*OUT */, + unsigned int num_scalars) const { unsigned count = hb_min (num_scalars, regionIndices.len); for (unsigned int i = 0; i < count; i++) @@ -2336,7 +2626,7 @@ struct VarData const hb_bimap_t ®ion_map) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (*this))) return_trace (false); + if (unlikely (!c->extend_min (this))) return_trace (false); itemCount = inner_map.get_next_value (); /* Optimize short count */ @@ -2378,9 +2668,7 @@ struct VarData shortCount = new_short_count; regionIndices.len = new_ri_count; - unsigned int size = regionIndices.get_size () - HBUINT16::static_size/*regionIndices.len*/ + (get_row_size () * itemCount); - if (unlikely (!c->allocate_size<HBUINT8> (size))) - return_trace (false); + if (unlikely (!c->extend (this))) return_trace (false); for (r = 0; r < ri_count; r++) if (delta_sz[r]) regionIndices[ri_map[r]] = region_map[src->regionIndices[r]]; @@ -2395,16 +2683,16 @@ struct VarData return_trace (true); } - void collect_region_refs (hb_inc_bimap_t ®ion_map, const hb_inc_bimap_t &inner_map) const + void collect_region_refs (hb_set_t ®ion_indices, const hb_inc_bimap_t &inner_map) const { for (unsigned int r = 0; r < regionIndices.len; r++) { unsigned int region = regionIndices[r]; - if (region_map.has (region)) continue; + if (region_indices.has (region)) continue; for (unsigned int i = 0; i < inner_map.get_next_value (); i++) if (get_item_delta (inner_map.backward (i), r) != 0) { - region_map.add (region); + region_indices.add (region); break; } } @@ -2439,7 +2727,7 @@ struct VarData protected: HBUINT16 itemCount; HBUINT16 shortCount; - ArrayOf<HBUINT16> regionIndices; + Array16Of<HBUINT16> regionIndices; /*UnsizedArrayOf<HBUINT8>bytesX;*/ public: DEFINE_SIZE_ARRAY (6, regionIndices); @@ -2447,6 +2735,7 @@ struct VarData struct VariationStore { + private: float get_delta (unsigned int outer, unsigned int inner, const int *coords, unsigned int coord_count) const { @@ -2462,6 +2751,7 @@ struct VariationStore this+regions); } + public: float get_delta (unsigned int index, const int *coords, unsigned int coord_count) const { @@ -2488,32 +2778,48 @@ struct VariationStore const hb_array_t <hb_inc_bimap_t> &inner_maps) { TRACE_SERIALIZE (this); + if (unlikely (!c->extend_min (this))) return_trace (false); + unsigned int set_count = 0; for (unsigned int i = 0; i < inner_maps.length; i++) - if (inner_maps[i].get_population () > 0) set_count++; + if (inner_maps[i].get_population ()) + set_count++; - unsigned int size = min_size + HBUINT32::static_size * set_count; - if (unlikely (!c->allocate_size<HBUINT32> (size))) return_trace (false); format = 1; - hb_inc_bimap_t region_map; + const auto &src_regions = src+src->regions; + + hb_set_t region_indices; for (unsigned int i = 0; i < inner_maps.length; i++) - (src+src->dataSets[i]).collect_region_refs (region_map, inner_maps[i]); - region_map.sort (); + (src+src->dataSets[i]).collect_region_refs (region_indices, inner_maps[i]); - if (unlikely (!regions.serialize (c, this) - .serialize (c, &(src+src->regions), region_map))) return_trace (false); + if (region_indices.in_error ()) + return_trace (false); + + region_indices.del_range ((src_regions).regionCount, hb_set_t::INVALID); + + /* TODO use constructor when our data-structures support that. */ + hb_inc_bimap_t region_map; + + hb_iter (region_indices) + | hb_apply ([®ion_map] (unsigned _) { region_map.add(_); }) + ; + if (region_map.in_error()) + return_trace (false); + + if (unlikely (!regions.serialize_serialize (c, &src_regions, region_map))) + return_trace (false); - /* TODO: The following code could be simplified when - * OffsetListOf::subset () can take a custom param to be passed to VarData::serialize () - */ dataSets.len = set_count; + if (unlikely (!c->extend (dataSets))) return_trace (false); + + /* TODO: The following code could be simplified when + * List16OfOffset16To::subset () can take a custom param to be passed to VarData::serialize () */ unsigned int set_index = 0; for (unsigned int i = 0; i < inner_maps.length; i++) { - if (inner_maps[i].get_population () == 0) continue; - if (unlikely (!dataSets[set_index++].serialize (c, this) - .serialize (c, &(src+src->dataSets[i]), inner_maps[i], region_map))) + if (!inner_maps[i].get_population ()) continue; + if (unlikely (!dataSets[set_index++] + .serialize_serialize (c, &(src+src->dataSets[i]), inner_maps[i], region_map))) return_trace (false); } @@ -2558,13 +2864,13 @@ struct VariationStore && varstore_prime->dataSets); } - unsigned int get_region_index_count (unsigned int ivs) const - { return (this+dataSets[ivs]).get_region_index_count (); } + unsigned int get_region_index_count (unsigned int major) const + { return (this+dataSets[major]).get_region_index_count (); } - void get_scalars (unsigned int ivs, - const int *coords, unsigned int coord_count, - float *scalars /*OUT*/, - unsigned int num_scalars) const + void get_region_scalars (unsigned int major, + const int *coords, unsigned int coord_count, + float *scalars /*OUT*/, + unsigned int num_scalars) const { #ifdef HB_NO_VAR for (unsigned i = 0; i < num_scalars; i++) @@ -2572,18 +2878,19 @@ struct VariationStore return; #endif - (this+dataSets[ivs]).get_scalars (coords, coord_count, this+regions, - &scalars[0], num_scalars); + (this+dataSets[major]).get_region_scalars (coords, coord_count, + this+regions, + &scalars[0], num_scalars); } unsigned int get_sub_table_count () const { return dataSets.len; } protected: HBUINT16 format; - LOffsetTo<VarRegionList> regions; - LOffsetArrayOf<VarData> dataSets; + Offset32To<VarRegionList> regions; + Array16OfOffset32To<VarData> dataSets; public: - DEFINE_SIZE_ARRAY (8, dataSets); + DEFINE_SIZE_ARRAY_SIZED (8, dataSets); }; /* @@ -2684,7 +2991,8 @@ struct ConditionSet + conditions.iter () | hb_apply (subset_offset_array (c, out->conditions, this)) ; - return_trace (true); + + return_trace (bool (out->conditions)); } bool sanitize (hb_sanitize_context_t *c) const @@ -2694,7 +3002,7 @@ struct ConditionSet } protected: - LOffsetArrayOf<Condition> conditions; + Array16OfOffset32To<Condition> conditions; public: DEFINE_SIZE_ARRAY (2, conditions); }; @@ -2719,6 +3027,12 @@ struct FeatureTableSubstitutionRecord bool subset (hb_subset_layout_context_t *c, const void *base) const { TRACE_SUBSET (this); + if (!c->feature_index_map->has (featureIndex)) { + // Feature that is being substituted is not being retained, so we don't + // need this. + return_trace (false); + } + auto *out = c->subset_context->serializer->embed (this); if (unlikely (!out)) return_trace (false); @@ -2735,7 +3049,7 @@ struct FeatureTableSubstitutionRecord protected: HBUINT16 featureIndex; - LOffsetTo<Feature> feature; + Offset32To<Feature> feature; public: DEFINE_SIZE_STATIC (6); }; @@ -2771,6 +3085,15 @@ struct FeatureTableSubstitution record.closure_features (this, lookup_indexes, feature_indexes); } + bool intersects_features (const hb_map_t *feature_index_map) const + { + for (const FeatureTableSubstitutionRecord& record : substitutions) + { + if (feature_index_map->has (record.featureIndex)) return true; + } + return false; + } + bool subset (hb_subset_context_t *c, hb_subset_layout_context_t *l) const { @@ -2784,7 +3107,8 @@ struct FeatureTableSubstitution + substitutions.iter () | hb_apply (subset_record_array (l, &(out->substitutions), this)) ; - return_trace (true); + + return_trace (bool (out->substitutions)); } bool sanitize (hb_sanitize_context_t *c) const @@ -2797,7 +3121,7 @@ struct FeatureTableSubstitution protected: FixedVersion<> version; /* Version--0x00010000u */ - ArrayOf<FeatureTableSubstitutionRecord> + Array16Of<FeatureTableSubstitutionRecord> substitutions; public: DEFINE_SIZE_ARRAY (6, substitutions); @@ -2821,6 +3145,11 @@ struct FeatureVariationRecord (base+substitutions).closure_features (lookup_indexes, feature_indexes); } + bool intersects_features (const void *base, const hb_map_t *feature_index_map) const + { + return (base+substitutions).intersects_features (feature_index_map); + } + bool subset (hb_subset_layout_context_t *c, const void *base) const { TRACE_SUBSET (this); @@ -2841,9 +3170,9 @@ struct FeatureVariationRecord } protected: - LOffsetTo<ConditionSet> + Offset32To<ConditionSet> conditions; - LOffsetTo<FeatureTableSubstitution> + Offset32To<FeatureTableSubstitution> substitutions; public: DEFINE_SIZE_STATIC (8); @@ -2907,9 +3236,18 @@ struct FeatureVariations out->version.major = version.major; out->version.minor = version.minor; - + varRecords.iter () - | hb_apply (subset_record_array (l, &(out->varRecords), this)) - ; + int keep_up_to = -1; + for (int i = varRecords.len - 1; i >= 0; i--) { + if (varRecords[i].intersects_features (this, l->feature_index_map)) { + keep_up_to = i; + break; + } + } + + unsigned count = (unsigned) (keep_up_to + 1); + for (unsigned i = 0; i < count; i++) { + subset_record_array (l, &(out->varRecords), this) (varRecords[i]); + } return_trace (bool (out->varRecords)); } @@ -2923,7 +3261,7 @@ struct FeatureVariations protected: FixedVersion<> version; /* Version--0x00010000u */ - LArrayOf<FeatureVariationRecord> + Array32Of<FeatureVariationRecord> varRecords; public: DEFINE_SIZE_ARRAY_SIZED (8, varRecords); @@ -3036,22 +3374,20 @@ struct VariationDevice if (unlikely (!out)) return_trace (nullptr); if (!layout_variation_idx_map || layout_variation_idx_map->is_empty ()) return_trace (out); - unsigned org_idx = (outerIndex << 16) + innerIndex; - if (!layout_variation_idx_map->has (org_idx)) + /* TODO Just get() and bail if NO_VARIATION. Needs to setup the map to return that. */ + if (!layout_variation_idx_map->has (varIdx)) { c->revert (snap); return_trace (nullptr); } - unsigned new_idx = layout_variation_idx_map->get (org_idx); - out->outerIndex = new_idx >> 16; - out->innerIndex = new_idx & 0xFFFF; + unsigned new_idx = layout_variation_idx_map->get (varIdx); + out->varIdx = new_idx; return_trace (out); } void record_variation_index (hb_set_t *layout_variation_indices) const { - unsigned var_idx = (outerIndex << 16) + innerIndex; - layout_variation_indices->add (var_idx); + layout_variation_indices->add (varIdx); } bool sanitize (hb_sanitize_context_t *c) const @@ -3064,12 +3400,11 @@ struct VariationDevice float get_delta (hb_font_t *font, const VariationStore &store) const { - return store.get_delta (outerIndex, innerIndex, font->coords, font->num_coords); + return store.get_delta (varIdx, font->coords, font->num_coords); } protected: - HBUINT16 outerIndex; - HBUINT16 innerIndex; + VarIdx varIdx; HBUINT16 deltaFormat; /* Format identifier for this table: 0x0x8000 */ public: DEFINE_SIZE_STATIC (6); |