• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &not_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