1diff --git a/src/hb-buffer.h b/src/hb-buffer.h 2index 865ccb2..88f1f4c 100644 3--- a/src/hb-buffer.h 4+++ b/src/hb-buffer.h 5@@ -307,7 +307,8 @@ typedef enum { /*< flags >*/ 6 HB_BUFFER_FLAG_EOT = 0x00000002u, /* End-of-text */ 7 HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES = 0x00000004u, 8 HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES = 0x00000008u, 9- HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE = 0x00000010u 10+ HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE = 0x00000010u, 11+ HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT = 0x00000040u 12 } hb_buffer_flags_t; 13 14 HB_EXTERN void 15diff --git a/src/hb-open-type.hh b/src/hb-open-type.hh 16index 406771f..b8ac4c5 100644 17--- a/src/hb-open-type.hh 18+++ b/src/hb-open-type.hh 19@@ -575,8 +575,13 @@ struct SortedUnsizedArrayOf : UnsizedArrayOf<Type> 20 { return hb_sorted_array (this->arrayZ, len); } 21 hb_sorted_array_t<const Type> as_array (unsigned int len) const 22 { return hb_sorted_array (this->arrayZ, len); } 23+#ifdef ENABLE_ICCARM 24+ operator hb_sorted_array_t<Type> () { return as_array (0); } 25+ operator hb_sorted_array_t<const Type> () const { return as_array (0); } 26+#else 27 operator hb_sorted_array_t<Type> () { return as_array (); } 28 operator hb_sorted_array_t<const Type> () const { return as_array (); } 29+#endif 30 31 template <typename T> 32 Type &bsearch (unsigned int len, const T &x, Type ¬_found = Crap (Type)) 33diff --git a/src/hb-ot-layout-common.hh b/src/hb-ot-layout-common.hh 34index c78f820..c9d93a7 100644 35--- a/src/hb-ot-layout-common.hh 36+++ b/src/hb-ot-layout-common.hh 37@@ -445,6 +445,7 @@ struct RecordListOf : RecordArrayOf<Type> 38 } 39 }; 40 41+#ifndef ENABLE_ICCARM // Adaptive compilation, only changes the order of the code, does not affect the function 42 struct Feature; 43 44 struct RecordListOfFeature : RecordListOf<Feature> 45@@ -797,7 +798,7 @@ struct Script 46 }; 47 48 typedef RecordListOfScript ScriptList; 49- 50+#endif // ENABLE_ICCARM 51 52 /* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#size */ 53 struct FeatureParamsSize 54@@ -1081,6 +1082,52 @@ struct FeatureParams 55 DEFINE_SIZE_MIN (0); 56 }; 57 58+#ifdef ENABLE_ICCARM // Adaptive compilation, only changes the order of the code, does not affect the function 59+struct IndexArray : Array16Of<Index> 60+{ 61+ bool intersects (const hb_map_t *indexes) const 62+ { return hb_any (*this, indexes); } 63+ 64+ template <typename Iterator, 65+ hb_requires (hb_is_iterator (Iterator))> 66+ void serialize (hb_serialize_context_t *c, 67+ hb_subset_layout_context_t *l, 68+ Iterator it) 69+ { 70+ if (!it) return; 71+ if (unlikely (!c->extend_min ((*this)))) return; 72+ 73+ for (const auto _ : it) 74+ { 75+ if (!l->visitLookupIndex()) break; 76+ 77+ Index i; 78+ i = _; 79+ c->copy (i); 80+ this->len++; 81+ } 82+ } 83+ 84+ unsigned int get_indexes (unsigned int start_offset, 85+ unsigned int *_count /* IN/OUT */, 86+ unsigned int *_indexes /* OUT */) const 87+ { 88+ if (_count) 89+ { 90+ + this->sub_array (start_offset, _count) 91+ | hb_sink (hb_array (_indexes, *_count)) 92+ ; 93+ } 94+ return this->len; 95+ } 96+ 97+ void add_indexes_to (hb_set_t* output /* OUT */) const 98+ { 99+ output->add_array (as_array ()); 100+ } 101+}; 102+#endif // ENABLE_ICCARM 103+ 104 struct Feature 105 { 106 unsigned int get_lookup_count () const 107@@ -1176,6 +1223,311 @@ struct Feature 108 DEFINE_SIZE_ARRAY_SIZED (4, lookupIndex); 109 }; 110 111+#ifdef ENABLE_ICCARM // Adaptive compilation, only changes the order of the code, does not affect the function 112+struct RecordListOfFeature : RecordListOf<Feature> 113+{ 114+ bool subset (hb_subset_context_t *c, 115+ hb_subset_layout_context_t *l) const 116+ { 117+ TRACE_SUBSET (this); 118+ auto *out = c->serializer->start_embed (*this); 119+ if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); 120+ 121+ unsigned count = this->len; 122+ + hb_zip (*this, hb_range (count)) 123+ | hb_filter (l->feature_index_map, hb_second) 124+ | hb_map (hb_first) 125+ | hb_apply (subset_record_array (l, out, this)) 126+ ; 127+ return_trace (true); 128+ } 129+}; 130+ 131+struct LangSys 132+{ 133+ unsigned int get_feature_count () const 134+ { return featureIndex.len; } 135+ hb_tag_t get_feature_index (unsigned int i) const 136+ { return featureIndex[i]; } 137+ unsigned int get_feature_indexes (unsigned int start_offset, 138+ unsigned int *feature_count /* IN/OUT */, 139+ unsigned int *feature_indexes /* OUT */) const 140+ { return featureIndex.get_indexes (start_offset, feature_count, feature_indexes); } 141+ void add_feature_indexes_to (hb_set_t *feature_indexes) const 142+ { featureIndex.add_indexes_to (feature_indexes); } 143+ 144+ bool has_required_feature () const { return reqFeatureIndex != 0xFFFFu; } 145+ unsigned int get_required_feature_index () const 146+ { 147+ if (reqFeatureIndex == 0xFFFFu) 148+ return Index::NOT_FOUND_INDEX; 149+ return reqFeatureIndex; 150+ } 151+ 152+ LangSys* copy (hb_serialize_context_t *c) const 153+ { 154+ TRACE_SERIALIZE (this); 155+ return_trace (c->embed (*this)); 156+ } 157+ 158+ bool compare (const LangSys& o, const hb_map_t *feature_index_map) const 159+ { 160+ if (reqFeatureIndex != o.reqFeatureIndex) 161+ return false; 162+ 163+ auto iter = 164+ + hb_iter (featureIndex) 165+ | hb_filter (feature_index_map) 166+ | hb_map (feature_index_map) 167+ ; 168+ 169+ auto o_iter = 170+ + hb_iter (o.featureIndex) 171+ | hb_filter (feature_index_map) 172+ | hb_map (feature_index_map) 173+ ; 174+ 175+ if (iter.len () != o_iter.len ()) 176+ return false; 177+ 178+ for (const auto _ : + hb_zip (iter, o_iter)) 179+ if (_.first != _.second) return false; 180+ 181+ return true; 182+ } 183+ 184+ void collect_features (hb_prune_langsys_context_t *c) const 185+ { 186+ if (!has_required_feature () && !get_feature_count ()) return; 187+ if (c->visitedLangsys (this)) return; 188+ if (has_required_feature () && 189+ c->duplicate_feature_map->has (reqFeatureIndex)) 190+ c->new_feature_indexes->add (get_required_feature_index ()); 191+ 192+ + hb_iter (featureIndex) 193+ | hb_filter (c->duplicate_feature_map) 194+ | hb_sink (c->new_feature_indexes) 195+ ; 196+ } 197+ 198+ bool subset (hb_subset_context_t *c, 199+ hb_subset_layout_context_t *l, 200+ const Tag *tag = nullptr) const 201+ { 202+ TRACE_SUBSET (this); 203+ auto *out = c->serializer->start_embed (*this); 204+ if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); 205+ 206+ out->reqFeatureIndex = l->feature_index_map->has (reqFeatureIndex) ? l->feature_index_map->get (reqFeatureIndex) : 0xFFFFu; 207+ 208+ if (!l->visitFeatureIndex (featureIndex.len)) 209+ return_trace (false); 210+ 211+ auto it = 212+ + hb_iter (featureIndex) 213+ | hb_filter (l->feature_index_map) 214+ | hb_map (l->feature_index_map) 215+ ; 216+ 217+ bool ret = bool (it); 218+ out->featureIndex.serialize (c->serializer, l, it); 219+ return_trace (ret); 220+ } 221+ 222+ bool sanitize (hb_sanitize_context_t *c, 223+ const Record_sanitize_closure_t * = nullptr) const 224+ { 225+ TRACE_SANITIZE (this); 226+ return_trace (c->check_struct (this) && featureIndex.sanitize (c)); 227+ } 228+ 229+ Offset16 lookupOrderZ; /* = Null (reserved for an offset to a 230+ * reordering table) */ 231+ HBUINT16 reqFeatureIndex;/* Index of a feature required for this 232+ * language system--if no required features 233+ * = 0xFFFFu */ 234+ IndexArray featureIndex; /* Array of indices into the FeatureList */ 235+ public: 236+ DEFINE_SIZE_ARRAY_SIZED (6, featureIndex); 237+}; 238+DECLARE_NULL_NAMESPACE_BYTES (OT, LangSys); 239+ 240+struct Script 241+{ 242+ unsigned int get_lang_sys_count () const 243+ { return langSys.len; } 244+ const Tag& get_lang_sys_tag (unsigned int i) const 245+ { return langSys.get_tag (i); } 246+ unsigned int get_lang_sys_tags (unsigned int start_offset, 247+ unsigned int *lang_sys_count /* IN/OUT */, 248+ hb_tag_t *lang_sys_tags /* OUT */) const 249+ { return langSys.get_tags (start_offset, lang_sys_count, lang_sys_tags); } 250+ const LangSys& get_lang_sys (unsigned int i) const 251+ { 252+ if (i == Index::NOT_FOUND_INDEX) return get_default_lang_sys (); 253+ return this+langSys[i].offset; 254+ } 255+ bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const 256+ { return langSys.find_index (tag, index); } 257+ 258+ bool has_default_lang_sys () const { return defaultLangSys != 0; } 259+ const LangSys& get_default_lang_sys () const { return this+defaultLangSys; } 260+ 261+ void prune_langsys (hb_prune_langsys_context_t *c, 262+ unsigned script_index) const 263+ { 264+ if (!has_default_lang_sys () && !get_lang_sys_count ()) return; 265+ if (c->visitedScript (this)) return; 266+ 267+ if (!c->script_langsys_map->has (script_index)) 268+ { 269+ hb_set_t* empty_set = hb_set_create (); 270+ if (unlikely (!c->script_langsys_map->set (script_index, empty_set))) 271+ { 272+ hb_set_destroy (empty_set); 273+ return; 274+ } 275+ } 276+ 277+ unsigned langsys_count = get_lang_sys_count (); 278+ if (has_default_lang_sys ()) 279+ { 280+ //only collect features from non-redundant langsys 281+ const LangSys& d = get_default_lang_sys (); 282+ d.collect_features (c); 283+ 284+ for (auto _ : + hb_zip (langSys, hb_range (langsys_count))) 285+ { 286+ const LangSys& l = this+_.first.offset; 287+ if (l.compare (d, c->duplicate_feature_map)) continue; 288+ 289+ l.collect_features (c); 290+ c->script_langsys_map->get (script_index)->add (_.second); 291+ } 292+ } 293+ else 294+ { 295+ for (auto _ : + hb_zip (langSys, hb_range (langsys_count))) 296+ { 297+ const LangSys& l = this+_.first.offset; 298+ l.collect_features (c); 299+ c->script_langsys_map->get (script_index)->add (_.second); 300+ } 301+ } 302+ } 303+ 304+ bool subset (hb_subset_context_t *c, 305+ hb_subset_layout_context_t *l, 306+ const Tag *tag) const 307+ { 308+ TRACE_SUBSET (this); 309+ if (!l->visitScript ()) return_trace (false); 310+ 311+ auto *out = c->serializer->start_embed (*this); 312+ if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); 313+ 314+ bool defaultLang = false; 315+ if (has_default_lang_sys ()) 316+ { 317+ c->serializer->push (); 318+ const LangSys& ls = this+defaultLangSys; 319+ bool ret = ls.subset (c, l); 320+ if (!ret && tag && *tag != HB_TAG ('D', 'F', 'L', 'T')) 321+ { 322+ c->serializer->pop_discard (); 323+ out->defaultLangSys = 0; 324+ } 325+ else 326+ { 327+ c->serializer->add_link (out->defaultLangSys, c->serializer->pop_pack ()); 328+ defaultLang = true; 329+ } 330+ } 331+ 332+ const hb_set_t *active_langsys = l->script_langsys_map->get (l->cur_script_index); 333+ if (active_langsys) 334+ { 335+ unsigned count = langSys.len; 336+ + hb_zip (langSys, hb_range (count)) 337+ | hb_filter (active_langsys, hb_second) 338+ | hb_map (hb_first) 339+ | hb_filter ([=] (const Record<LangSys>& record) {return l->visitLangSys (); }) 340+ | hb_apply (subset_record_array (l, &(out->langSys), this)) 341+ ; 342+ } 343+ 344+ return_trace (bool (out->langSys.len) || defaultLang || l->table_tag == HB_OT_TAG_GSUB); 345+ } 346+ 347+ bool sanitize (hb_sanitize_context_t *c, 348+ const Record_sanitize_closure_t * = nullptr) const 349+ { 350+ TRACE_SANITIZE (this); 351+ return_trace (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this)); 352+ } 353+ 354+ protected: 355+ Offset16To<LangSys> 356+ defaultLangSys; /* Offset to DefaultLangSys table--from 357+ * beginning of Script table--may be Null */ 358+ RecordArrayOf<LangSys> 359+ langSys; /* Array of LangSysRecords--listed 360+ * alphabetically by LangSysTag */ 361+ public: 362+ DEFINE_SIZE_ARRAY_SIZED (4, langSys); 363+}; 364+struct RecordListOfScript : RecordListOf<Script> 365+{ 366+ bool subset (hb_subset_context_t *c, 367+ hb_subset_layout_context_t *l) const 368+ { 369+ TRACE_SUBSET (this); 370+ auto *out = c->serializer->start_embed (*this); 371+ if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); 372+ 373+ unsigned count = this->len; 374+ for (auto _ : + hb_zip (*this, hb_range (count))) 375+ { 376+ auto snap = c->serializer->snapshot (); 377+ l->cur_script_index = _.second; 378+ bool ret = _.first.subset (l, this); 379+ if (!ret) c->serializer->revert (snap); 380+ else out->len++; 381+ } 382+ 383+ return_trace (true); 384+ } 385+}; 386+ 387+struct RangeRecord 388+{ 389+ int cmp (hb_codepoint_t g) const 390+ { return g < first ? -1 : g <= last ? 0 : +1; } 391+ 392+ bool sanitize (hb_sanitize_context_t *c) const 393+ { 394+ TRACE_SANITIZE (this); 395+ return_trace (c->check_struct (this)); 396+ } 397+ 398+ bool intersects (const hb_set_t *glyphs) const 399+ { return glyphs->intersects (first, last); } 400+ 401+ template <typename set_t> 402+ bool collect_coverage (set_t *glyphs) const 403+ { return glyphs->add_range (first, last); } 404+ 405+ HBGlyphID first; /* First GlyphID in the range */ 406+ HBGlyphID last; /* Last GlyphID in the range */ 407+ HBUINT16 value; /* Value */ 408+ public: 409+ DEFINE_SIZE_STATIC (6); 410+}; 411+DECLARE_NULL_NAMESPACE_BYTES (OT, RangeRecord); 412+ 413+typedef RecordListOfScript ScriptList; 414+#endif // ENABLE_ICCARM 415+ 416 typedef RecordListOf<Feature> FeatureList; 417 418 419diff --git a/src/hb-ot-layout-gsubgpos.hh b/src/hb-ot-layout-gsubgpos.hh 420index c17bf92..f046c08 100644 421--- a/src/hb-ot-layout-gsubgpos.hh 422+++ b/src/hb-ot-layout-gsubgpos.hh 423@@ -535,7 +535,17 @@ struct hb_ot_apply_context_t : 424 bool prev () 425 { 426 assert (num_items > 0); 427- while (idx > num_items - 1) 428+ /* The alternate condition below is faster at string boundaries, 429+ * but produces subpar "unsafe-to-concat" values. */ 430+ unsigned stop = num_items - 1; 431+ if (c->buffer->flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) 432+ stop = 1 - 1; 433+ /*When looking back, limit how far we search; this function is mostly 434+ * used for looking back for base glyphs when attaching marks. If we 435+ * don't limit, we can get O(n^2) behavior where n is the number of 436+ * consecutive marks. */ 437+ stop = (unsigned) hb_max ((int) stop, (int) idx - HB_MAX_CONTEXT_LENGTH); 438+ while (idx > stop) 439 { 440 idx--; 441 const hb_glyph_info_t &info = c->buffer->out_info[idx]; 442diff --git a/src/hb-static.cc b/src/hb-static.cc 443index ec4b241..bef2ce9 100644 444--- a/src/hb-static.cc 445+++ b/src/hb-static.cc 446@@ -39,8 +39,13 @@ 447 #ifndef HB_NO_VISIBILITY 448 #include "hb-ot-name-language-static.hh" 449 450+#ifndef ENABLE_ICCARM 451 uint64_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)] = {}; 452 /*thread_local*/ uint64_t _hb_CrapPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)] = {}; 453+#else 454+uint64_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)] = {0}; 455+/*thread_local*/ uint64_t _hb_CrapPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)] = {0}; 456+#endif 457 458 DEFINE_NULL_NAMESPACE_BYTES (OT, Index) = {0xFF,0xFF}; 459 DEFINE_NULL_NAMESPACE_BYTES (OT, VarIdx) = {0xFF,0xFF,0xFF,0xFF}; 460