Bug Summary

File:root/firefox-clang/obj-x86_64-pc-linux-gnu/gfx/harfbuzz/src/./../../../../gfx/harfbuzz/src/graph/../hb-ot-layout-common.hh
Warning:line 3962, column 7
Value stored to 'varStore' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_gfx_harfbuzz_src0.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/gfx/harfbuzz/src -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/gfx/harfbuzz/src -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -D _GLIBCXX_ASSERTIONS=1 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D PACKAGE_VERSION="moz" -D PACKAGE_BUGREPORT="http://bugzilla.mozilla.org/" -D HAVE_OT=1 -D HAVE_ROUND=1 -D HB_NO_BUFFER_VERIFY -D HB_NO_FALLBACK_SHAPE -D HB_NO_PAINT -D HB_NO_UCD -D HB_NO_UNICODE_FUNCS -D HB_NO_VAR_COMPOSITES -D HAVE_MMAP=1 -D HAVE_SYS_MMAN_H=1 -D HAVE_UNISTD_H=1 -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /root/firefox-clang/gfx/harfbuzz/src -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/gfx/harfbuzz/src -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/x86_64-linux-gnu/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/backward -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-character-conversion -std=gnu++20 -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-09-01-224014-2642839-1 -x c++ Unified_cpp_gfx_harfbuzz_src0.cpp
1/*
2 * Copyright © 2007,2008,2009 Red Hat, Inc.
3 * Copyright © 2010,2012 Google, Inc.
4 *
5 * This is part of HarfBuzz, a text shaping library.
6 *
7 * Permission is hereby granted, without written agreement and without
8 * license or royalty fees, to use, copy, modify, and distribute this
9 * software and its documentation for any purpose, provided that the
10 * above copyright notice and the following two paragraphs appear in
11 * all copies of this software.
12 *
13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17 * DAMAGE.
18 *
19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24 *
25 * Red Hat Author(s): Behdad Esfahbod
26 * Google Author(s): Behdad Esfahbod
27 */
28
29#ifndef HB_OT_LAYOUT_COMMON_HH
30#define HB_OT_LAYOUT_COMMON_HH
31
32#include "hb.hh"
33#include "hb-ot-layout.hh"
34#include "hb-open-type.hh"
35#include "hb-set.hh"
36#include "hb-bimap.hh"
37#include "hb-cache.hh"
38
39#include "OT/Layout/Common/Coverage.hh"
40#include "OT/Layout/types.hh"
41
42// TODO(garretrieger): cleanup these after migration.
43using OT::Layout::Common::Coverage;
44using OT::Layout::Common::RangeRecord;
45using OT::Layout::SmallTypes;
46using OT::Layout::MediumTypes;
47
48
49namespace OT {
50
51template<typename Iterator>
52static inline bool ClassDef_serialize (hb_serialize_context_t *c,
53 Iterator it);
54
55static bool ClassDef_remap_and_serialize (
56 hb_serialize_context_t *c,
57 const hb_set_t &klasses,
58 bool use_class_zero,
59 hb_sorted_vector_t<hb_codepoint_pair_t> &glyph_and_klass, /* IN/OUT */
60 hb_map_t *klass_map /*IN/OUT*/);
61
62struct hb_collect_feature_substitutes_with_var_context_t
63{
64 const hb_map_t *axes_index_tag_map;
65 const hb_hashmap_t<hb_tag_t, Triple> *axes_location;
66 hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *record_cond_idx_map;
67 hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map;
68 hb_set_t& catch_all_record_feature_idxes;
69
70 // not stored in subset_plan
71 hb_set_t *feature_indices;
72 bool apply;
73 bool variation_applied;
74 bool universal;
75 unsigned cur_record_idx;
76 hb_hashmap_t<hb::shared_ptr<hb_map_t>, unsigned> *conditionset_map;
77};
78
79struct hb_prune_langsys_context_t
80{
81 hb_prune_langsys_context_t (const void *table_,
82 hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *script_langsys_map_,
83 const hb_map_t *duplicate_feature_map_,
84 hb_set_t *new_collected_feature_indexes_)
85 :table (table_),
86 script_langsys_map (script_langsys_map_),
87 duplicate_feature_map (duplicate_feature_map_),
88 new_feature_indexes (new_collected_feature_indexes_),
89 script_count (0),langsys_feature_count (0) {}
90
91 bool visitScript ()
92 { return script_count++ < HB_MAX_SCRIPTS500; }
93
94 bool visitLangsys (unsigned feature_count)
95 {
96 langsys_feature_count += feature_count;
97 return langsys_feature_count < HB_MAX_LANGSYS_FEATURE_COUNT50000;
98 }
99
100 public:
101 const void *table;
102 hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *script_langsys_map;
103 const hb_map_t *duplicate_feature_map;
104 hb_set_t *new_feature_indexes;
105
106 private:
107 unsigned script_count;
108 unsigned langsys_feature_count;
109};
110
111struct hb_subset_layout_context_t :
112 hb_dispatch_context_t<hb_subset_layout_context_t, hb_empty_t, HB_DEBUG_SUBSET(0 +0)>
113{
114 const char *get_name () { return "SUBSET_LAYOUT"; }
115 static return_t default_return_value () { return hb_empty_t (); }
116
117 bool visitScript ()
118 {
119 return script_count++ < HB_MAX_SCRIPTS500;
120 }
121
122 bool visitLangSys ()
123 {
124 return langsys_count++ < HB_MAX_LANGSYS2000;
125 }
126
127 bool visitFeatureIndex (int count)
128 {
129 feature_index_count += count;
130 return feature_index_count < HB_MAX_FEATURE_INDICES8000;
131 }
132
133 bool visitLookupIndex()
134 {
135 lookup_index_count++;
136 return lookup_index_count < HB_MAX_LOOKUP_VISIT_COUNT35000;
137 }
138
139 hb_subset_context_t *subset_context;
140 const hb_tag_t table_tag;
141 const hb_map_t *lookup_index_map;
142 const hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *script_langsys_map;
143 const hb_map_t *feature_index_map;
144 const hb_map_t *feature_map_w_duplicates;
145 const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map;
146 hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map;
147 const hb_set_t *catch_all_record_feature_idxes;
148 const hb_hashmap_t<unsigned, hb_pair_t<const void*, const void*>> *feature_idx_tag_map;
149
150 unsigned cur_script_index;
151 unsigned cur_feature_var_record_idx;
152
153 hb_subset_layout_context_t (hb_subset_context_t *c_,
154 hb_tag_t tag_) :
155 subset_context (c_),
156 table_tag (tag_),
157 cur_script_index (0xFFFFu),
158 cur_feature_var_record_idx (0u),
159 script_count (0),
160 langsys_count (0),
161 feature_index_count (0),
162 lookup_index_count (0)
163 {
164 if (tag_ == HB_OT_TAG_GSUB((hb_tag_t)((((uint32_t)('G')&0xFF)<<24)|(((uint32_t
)('S')&0xFF)<<16)|(((uint32_t)('U')&0xFF)<<
8)|((uint32_t)('B')&0xFF)))
)
165 {
166 lookup_index_map = &c_->plan->gsub_lookups;
167 script_langsys_map = &c_->plan->gsub_langsys;
168 feature_index_map = &c_->plan->gsub_features;
169 feature_map_w_duplicates = &c_->plan->gsub_features_w_duplicates;
170 feature_substitutes_map = &c_->plan->gsub_feature_substitutes_map;
171 feature_record_cond_idx_map = c_->plan->user_axes_location.is_empty () ? nullptr : &c_->plan->gsub_feature_record_cond_idx_map;
172 catch_all_record_feature_idxes = &c_->plan->gsub_old_features;
173 feature_idx_tag_map = &c_->plan->gsub_old_feature_idx_tag_map;
174 }
175 else
176 {
177 lookup_index_map = &c_->plan->gpos_lookups;
178 script_langsys_map = &c_->plan->gpos_langsys;
179 feature_index_map = &c_->plan->gpos_features;
180 feature_map_w_duplicates = &c_->plan->gpos_features_w_duplicates;
181 feature_substitutes_map = &c_->plan->gpos_feature_substitutes_map;
182 feature_record_cond_idx_map = c_->plan->user_axes_location.is_empty () ? nullptr : &c_->plan->gpos_feature_record_cond_idx_map;
183 catch_all_record_feature_idxes = &c_->plan->gpos_old_features;
184 feature_idx_tag_map = &c_->plan->gpos_old_feature_idx_tag_map;
185 }
186 }
187
188 private:
189 unsigned script_count;
190 unsigned langsys_count;
191 unsigned feature_index_count;
192 unsigned lookup_index_count;
193};
194
195struct ItemVariationStore;
196struct hb_collect_variation_indices_context_t :
197 hb_dispatch_context_t<hb_collect_variation_indices_context_t>
198{
199 template <typename T>
200 return_t dispatch (const T &obj) { obj.collect_variation_indices (this); return hb_empty_t (); }
201 static return_t default_return_value () { return hb_empty_t (); }
202
203 hb_set_t *layout_variation_indices;
204 const hb_set_t *glyph_set;
205 const hb_map_t *gpos_lookups;
206
207 hb_collect_variation_indices_context_t (hb_set_t *layout_variation_indices_,
208 const hb_set_t *glyph_set_,
209 const hb_map_t *gpos_lookups_) :
210 layout_variation_indices (layout_variation_indices_),
211 glyph_set (glyph_set_),
212 gpos_lookups (gpos_lookups_) {}
213};
214
215template<typename OutputArray>
216struct subset_offset_array_t
217{
218 subset_offset_array_t (hb_subset_context_t *subset_context_,
219 OutputArray& out_,
220 const void *base_) : subset_context (subset_context_),
221 out (out_), base (base_) {}
222
223 template <typename T>
224 bool operator () (T&& offset)
225 {
226 auto snap = subset_context->serializer->snapshot ();
227 auto *o = out.serialize_append (subset_context->serializer);
228 if (unlikely (!o)__builtin_expect (bool(!o), 0)) return false;
229 bool ret = o->serialize_subset (subset_context, offset, base);
230 if (!ret)
231 {
232 out.pop ();
233 subset_context->serializer->revert (snap);
234 }
235 return ret;
236 }
237
238 private:
239 hb_subset_context_t *subset_context;
240 OutputArray &out;
241 const void *base;
242};
243
244
245template<typename OutputArray, typename Arg>
246struct subset_offset_array_arg_t
247{
248 subset_offset_array_arg_t (hb_subset_context_t *subset_context_,
249 OutputArray& out_,
250 const void *base_,
251 Arg &&arg_) : subset_context (subset_context_), out (out_),
252 base (base_), arg (arg_) {}
253
254 template <typename T>
255 bool operator () (T&& offset)
256 {
257 auto snap = subset_context->serializer->snapshot ();
258 auto *o = out.serialize_append (subset_context->serializer);
259 if (unlikely (!o)__builtin_expect (bool(!o), 0)) return false;
260 bool ret = o->serialize_subset (subset_context, offset, base, arg);
261 if (!ret)
262 {
263 out.pop ();
264 subset_context->serializer->revert (snap);
265 }
266 return ret;
267 }
268
269 private:
270 hb_subset_context_t *subset_context;
271 OutputArray &out;
272 const void *base;
273 Arg &&arg;
274};
275
276/*
277 * Helper to subset an array of offsets. Subsets the thing pointed to by each offset
278 * and discards the offset in the array if the subset operation results in an empty
279 * thing.
280 */
281struct
282{
283 template<typename OutputArray>
284 subset_offset_array_t<OutputArray>
285 operator () (hb_subset_context_t *subset_context, OutputArray& out,
286 const void *base) const
287 { return subset_offset_array_t<OutputArray> (subset_context, out, base); }
288
289 /* Variant with one extra argument passed to serialize_subset */
290 template<typename OutputArray, typename Arg>
291 subset_offset_array_arg_t<OutputArray, Arg>
292 operator () (hb_subset_context_t *subset_context, OutputArray& out,
293 const void *base, Arg &&arg) const
294 { return subset_offset_array_arg_t<OutputArray, Arg> (subset_context, out, base, arg); }
295}
296HB_FUNCOBJ (subset_offset_array)static const subset_offset_array __attribute__((unused));
297
298template<typename OutputArray>
299struct subset_record_array_t
300{
301 subset_record_array_t (hb_subset_layout_context_t *c_, OutputArray* out_,
302 const void *base_) : subset_layout_context (c_),
303 out (out_), base (base_) {}
304
305 template <typename T>
306 void
307 operator () (T&& record)
308 {
309 auto snap = subset_layout_context->subset_context->serializer->snapshot ();
310 bool ret = record.subset (subset_layout_context, base);
311 if (!ret) subset_layout_context->subset_context->serializer->revert (snap);
312 else out->len++;
313 }
314
315 private:
316 hb_subset_layout_context_t *subset_layout_context;
317 OutputArray *out;
318 const void *base;
319};
320
321template<typename OutputArray, typename Arg>
322struct subset_record_array_arg_t
323{
324 subset_record_array_arg_t (hb_subset_layout_context_t *c_, OutputArray* out_,
325 const void *base_,
326 Arg &&arg_) : subset_layout_context (c_),
327 out (out_), base (base_), arg (arg_) {}
328
329 template <typename T>
330 void
331 operator () (T&& record)
332 {
333 auto snap = subset_layout_context->subset_context->serializer->snapshot ();
334 bool ret = record.subset (subset_layout_context, base, arg);
335 if (!ret) subset_layout_context->subset_context->serializer->revert (snap);
336 else out->len++;
337 }
338
339 private:
340 hb_subset_layout_context_t *subset_layout_context;
341 OutputArray *out;
342 const void *base;
343 Arg &&arg;
344};
345
346/*
347 * Helper to subset a RecordList/record array. Subsets each Record in the array and
348 * discards the record if the subset operation returns false.
349 */
350struct
351{
352 template<typename OutputArray>
353 subset_record_array_t<OutputArray>
354 operator () (hb_subset_layout_context_t *c, OutputArray* out,
355 const void *base) const
356 { return subset_record_array_t<OutputArray> (c, out, base); }
357
358 /* Variant with one extra argument passed to subset */
359 template<typename OutputArray, typename Arg>
360 subset_record_array_arg_t<OutputArray, Arg>
361 operator () (hb_subset_layout_context_t *c, OutputArray* out,
362 const void *base, Arg &&arg) const
363 { return subset_record_array_arg_t<OutputArray, Arg> (c, out, base, arg); }
364}
365HB_FUNCOBJ (subset_record_array)static const subset_record_array __attribute__((unused));
366
367
368template<typename OutputArray>
369struct serialize_math_record_array_t
370{
371 serialize_math_record_array_t (hb_serialize_context_t *serialize_context_,
372 OutputArray& out_,
373 const void *base_) : serialize_context (serialize_context_),
374 out (out_), base (base_) {}
375
376 template <typename T>
377 bool operator () (T&& record)
378 {
379 if (!serialize_context->copy (record, base)) return false;
380 out.len++;
381 return true;
382 }
383
384 private:
385 hb_serialize_context_t *serialize_context;
386 OutputArray &out;
387 const void *base;
388};
389
390/*
391 * Helper to serialize an array of MATH records.
392 */
393struct
394{
395 template<typename OutputArray>
396 serialize_math_record_array_t<OutputArray>
397 operator () (hb_serialize_context_t *serialize_context, OutputArray& out,
398 const void *base) const
399 { return serialize_math_record_array_t<OutputArray> (serialize_context, out, base); }
400
401}
402HB_FUNCOBJ (serialize_math_record_array)static const serialize_math_record_array __attribute__((unused
))
;
403
404/*
405 *
406 * OpenType Layout Common Table Formats
407 *
408 */
409
410
411/*
412 * Script, ScriptList, LangSys, Feature, FeatureList, Lookup, LookupList
413 */
414
415struct IndexArray : Array16Of<Index>
416{
417 bool intersects (const hb_map_t *indexes) const
418 { return hb_any (*this, indexes); }
419
420 template <typename Iterator,
421 hb_requires (hb_is_iterator (Iterator))typename hb_enable_if<((hb_is_iterator_of<Iterator, typename
Iterator::item_t>::value))>::type* = nullptr
>
422 void serialize (hb_serialize_context_t *c,
423 hb_subset_layout_context_t *l,
424 Iterator it)
425 {
426 if (!it) return;
427 if (unlikely (!c->extend_min ((*this)))__builtin_expect (bool(!c->extend_min ((*this))), 0)) return;
428
429 for (const auto _ : it)
430 {
431 if (!l->visitLookupIndex()) break;
432
433 Index i;
434 i = _;
435 c->copy (i);
436 this->len++;
437 }
438 }
439
440 unsigned int get_indexes (unsigned int start_offset,
441 unsigned int *_count /* IN/OUT */,
442 unsigned int *_indexes /* OUT */) const
443 {
444 if (_count && _indexes)
445 {
446 + this->as_array ().sub_array (start_offset, _count)
447 | hb_sink (hb_array (_indexes, *_count))
448 ;
449 }
450 return this->len;
451 }
452
453 void add_indexes_to (hb_set_t* output /* OUT */) const
454 {
455 output->add_array (as_array ());
456 }
457};
458
459
460/* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#size */
461struct FeatureParamsSize
462{
463 bool sanitize (hb_sanitize_context_t *c) const
464 {
465 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
466 if (unlikely (!c->check_struct (this))__builtin_expect (bool(!c->check_struct (this)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 466);
467 hb_barrier ();
468
469 /* This subtable has some "history", if you will. Some earlier versions of
470 * Adobe tools calculated the offset of the FeatureParams subtable from the
471 * beginning of the FeatureList table! Now, that is dealt with in the
472 * Feature implementation. But we still need to be able to tell junk from
473 * real data. Note: We don't check that the nameID actually exists.
474 *
475 * Read Roberts wrote on 9/15/06 on opentype-list@indx.co.uk :
476 *
477 * Yes, it is correct that a new version of the AFDKO (version 2.0) will be
478 * coming out soon, and that the makeotf program will build a font with a
479 * 'size' feature that is correct by the specification.
480 *
481 * The specification for this feature tag is in the "OpenType Layout Tag
482 * Registry". You can see a copy of this at:
483 * https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#tag-size
484 *
485 * Here is one set of rules to determine if the 'size' feature is built
486 * correctly, or as by the older versions of MakeOTF. You may be able to do
487 * better.
488 *
489 * Assume that the offset to the size feature is according to specification,
490 * and make the following value checks. If it fails, assume the size
491 * feature is calculated as versions of MakeOTF before the AFDKO 2.0 built it.
492 * If this fails, reject the 'size' feature. The older makeOTF's calculated the
493 * offset from the beginning of the FeatureList table, rather than from the
494 * beginning of the 'size' Feature table.
495 *
496 * If "design size" == 0:
497 * fails check
498 *
499 * Else if ("subfamily identifier" == 0 and
500 * "range start" == 0 and
501 * "range end" == 0 and
502 * "range start" == 0 and
503 * "menu name ID" == 0)
504 * passes check: this is the format used when there is a design size
505 * specified, but there is no recommended size range.
506 *
507 * Else if ("design size" < "range start" or
508 * "design size" > "range end" or
509 * "range end" <= "range start" or
510 * "menu name ID" < 256 or
511 * "menu name ID" > 32767 or
512 * menu name ID is not a name ID which is actually in the name table)
513 * fails test
514 * Else
515 * passes test.
516 */
517
518 if (!designSize)
519 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 519);
520 else if (subfamilyID == 0 &&
521 subfamilyNameID == 0 &&
522 rangeStart == 0 &&
523 rangeEnd == 0)
524 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 524);
525 else if (designSize < rangeStart ||
526 designSize > rangeEnd ||
527 subfamilyNameID < 256 ||
528 subfamilyNameID > 32767)
529 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 529);
530 else
531 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 531);
532 }
533
534 void collect_name_ids (hb_set_t *nameids_to_retain /* OUT */) const
535 { nameids_to_retain->add (subfamilyNameID); }
536
537 bool subset (hb_subset_context_t *c) const
538 {
539 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
540 return_trace ((bool) c->serializer->embed (*this))return trace.ret ((bool) c->serializer->embed (*this), __PRETTY_FUNCTION__
, 540)
;
541 }
542
543 HBUINT16 designSize; /* Represents the design size in 720/inch
544 * units (decipoints). The design size entry
545 * must be non-zero. When there is a design
546 * size but no recommended size range, the
547 * rest of the array will consist of zeros. */
548 HBUINT16 subfamilyID; /* Has no independent meaning, but serves
549 * as an identifier that associates fonts
550 * in a subfamily. All fonts which share a
551 * Preferred or Font Family name and which
552 * differ only by size range shall have the
553 * same subfamily value, and no fonts which
554 * differ in weight or style shall have the
555 * same subfamily value. If this value is
556 * zero, the remaining fields in the array
557 * will be ignored. */
558 NameID subfamilyNameID;/* If the preceding value is non-zero, this
559 * value must be set in the range 256 - 32767
560 * (inclusive). It records the value of a
561 * field in the name table, which must
562 * contain English-language strings encoded
563 * in Windows Unicode and Macintosh Roman,
564 * and may contain additional strings
565 * localized to other scripts and languages.
566 * Each of these strings is the name an
567 * application should use, in combination
568 * with the family name, to represent the
569 * subfamily in a menu. Applications will
570 * choose the appropriate version based on
571 * their selection criteria. */
572 HBUINT16 rangeStart; /* Large end of the recommended usage range
573 * (inclusive), stored in 720/inch units
574 * (decipoints). */
575 HBUINT16 rangeEnd; /* Small end of the recommended usage range
576 (exclusive), stored in 720/inch units
577 * (decipoints). */
578 public:
579 DEFINE_SIZE_STATIC (10)void _instance_assertion_on_line_579 () const { static_assert
((sizeof (*this) == (10)), ""); } size_t get_size () const {
return (10); } static constexpr unsigned null_size = (10); static
constexpr unsigned min_size = (10); static constexpr unsigned
static_size = (10)
;
580};
581
582/* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#ssxx */
583struct FeatureParamsStylisticSet
584{
585 bool sanitize (hb_sanitize_context_t *c) const
586 {
587 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
588 /* Right now minorVersion is at zero. Which means, any table supports
589 * the uiNameID field. */
590 return_trace (c->check_struct (this))return trace.ret (c->check_struct (this), __PRETTY_FUNCTION__
, 590)
;
591 }
592
593 void collect_name_ids (hb_set_t *nameids_to_retain /* OUT */) const
594 { nameids_to_retain->add (uiNameID); }
595
596 bool subset (hb_subset_context_t *c) const
597 {
598 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
599 return_trace ((bool) c->serializer->embed (*this))return trace.ret ((bool) c->serializer->embed (*this), __PRETTY_FUNCTION__
, 599)
;
600 }
601
602 HBUINT16 version; /* (set to 0): This corresponds to a “minor”
603 * version number. Additional data may be
604 * added to the end of this Feature Parameters
605 * table in the future. */
606
607 NameID uiNameID; /* The 'name' table name ID that specifies a
608 * string (or strings, for multiple languages)
609 * for a user-interface label for this
610 * feature. The values of uiLabelNameId and
611 * sampleTextNameId are expected to be in the
612 * font-specific name ID range (256-32767),
613 * though that is not a requirement in this
614 * Feature Parameters specification. The
615 * user-interface label for the feature can
616 * be provided in multiple languages. An
617 * English string should be included as a
618 * fallback. The string should be kept to a
619 * minimal length to fit comfortably with
620 * different application interfaces. */
621 public:
622 DEFINE_SIZE_STATIC (4)void _instance_assertion_on_line_622 () const { static_assert
((sizeof (*this) == (4)), ""); } size_t get_size () const { return
(4); } static constexpr unsigned null_size = (4); static constexpr
unsigned min_size = (4); static constexpr unsigned static_size
= (4)
;
623};
624
625/* https://docs.microsoft.com/en-us/typography/opentype/spec/features_ae#cv01-cv99 */
626struct FeatureParamsCharacterVariants
627{
628 unsigned
629 get_characters (unsigned start_offset, unsigned *char_count, hb_codepoint_t *chars) const
630 {
631 if (char_count && chars)
632 {
633 + characters.as_array ().sub_array (start_offset, char_count)
634 | hb_sink (hb_array (chars, *char_count))
635 ;
636 }
637 return characters.len;
638 }
639
640 size_t get_size () const
641 { return hb_unsigned_mul_add_saturate (characters.len, HBUINT24::static_size, min_size); }
642
643 void collect_name_ids (hb_set_t *nameids_to_retain /* OUT */) const
644 {
645 if (featUILableNameID) nameids_to_retain->add (featUILableNameID);
646 if (featUITooltipTextNameID) nameids_to_retain->add (featUITooltipTextNameID);
647 if (sampleTextNameID) nameids_to_retain->add (sampleTextNameID);
648
649 if (!firstParamUILabelNameID || !numNamedParameters || numNamedParameters >= 0x7FFF)
650 return;
651
652 unsigned last_name_id = (unsigned) firstParamUILabelNameID + (unsigned) numNamedParameters - 1;
653 nameids_to_retain->add_range (firstParamUILabelNameID, last_name_id);
654 }
655
656 bool subset (hb_subset_context_t *c) const
657 {
658 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
659 return_trace ((bool) c->serializer->embed (*this))return trace.ret ((bool) c->serializer->embed (*this), __PRETTY_FUNCTION__
, 659)
;
660 }
661
662 bool sanitize (hb_sanitize_context_t *c) const
663 {
664 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
665 return_trace (c->check_struct (this) &&return trace.ret (c->check_struct (this) && characters
.sanitize (c), __PRETTY_FUNCTION__, 666)
666 characters.sanitize (c))return trace.ret (c->check_struct (this) && characters
.sanitize (c), __PRETTY_FUNCTION__, 666)
;
667 }
668
669 HBUINT16 format; /* Format number is set to 0. */
670 NameID featUILableNameID; /* The ‘name’ table name ID that
671 * specifies a string (or strings,
672 * for multiple languages) for a
673 * user-interface label for this
674 * feature. (May be NULL.) */
675 NameID featUITooltipTextNameID;/* The ‘name’ table name ID that
676 * specifies a string (or strings,
677 * for multiple languages) that an
678 * application can use for tooltip
679 * text for this feature. (May be
680 * nullptr.) */
681 NameID sampleTextNameID; /* The ‘name’ table name ID that
682 * specifies sample text that
683 * illustrates the effect of this
684 * feature. (May be NULL.) */
685 HBUINT16 numNamedParameters; /* Number of named parameters. (May
686 * be zero.) */
687 NameID firstParamUILabelNameID;/* The first ‘name’ table name ID
688 * used to specify strings for
689 * user-interface labels for the
690 * feature parameters. (Must be zero
691 * if numParameters is zero.) */
692 Array16Of<HBUINT24>
693 characters; /* Array of the Unicode Scalar Value
694 * of the characters for which this
695 * feature provides glyph variants.
696 * (May be zero.) */
697 public:
698 DEFINE_SIZE_ARRAY (14, characters)void _compiles_assertion_on_line_698 () const { (void) (characters
)[0].static_size; } void _instance_assertion_on_line_698 () const
{ static_assert ((sizeof (*this) == (14) + (1 +0) * sizeof (
(characters)[0])), ""); } static constexpr unsigned null_size
= (14); static constexpr unsigned min_size = (14)
;
699};
700
701struct FeatureParams
702{
703 bool sanitize (hb_sanitize_context_t *c, hb_tag_t tag) const
704 {
705#ifdef HB_NO_LAYOUT_FEATURE_PARAMS
706 return true;
707#endif
708 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
709 if (tag == HB_TAG ('s','i','z','e')((hb_tag_t)((((uint32_t)('s')&0xFF)<<24)|(((uint32_t
)('i')&0xFF)<<16)|(((uint32_t)('z')&0xFF)<<
8)|((uint32_t)('e')&0xFF)))
&& hb_barrier ())
710 return_trace (u.size.sanitize (c))return trace.ret (u.size.sanitize (c), __PRETTY_FUNCTION__, 710
)
;
711 if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')((hb_tag_t)((((uint32_t)('s')&0xFF)<<24)|(((uint32_t
)('s')&0xFF)<<16)|(((uint32_t)('\0')&0xFF)<<
8)|((uint32_t)('\0')&0xFF)))
) /* ssXX */
712 return_trace (u.stylisticSet.sanitize (c))return trace.ret (u.stylisticSet.sanitize (c), __PRETTY_FUNCTION__
, 712)
;
713 if ((tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')((hb_tag_t)((((uint32_t)('c')&0xFF)<<24)|(((uint32_t
)('v')&0xFF)<<16)|(((uint32_t)('\0')&0xFF)<<
8)|((uint32_t)('\0')&0xFF)))
) /* cvXX */
714 return_trace (u.characterVariants.sanitize (c))return trace.ret (u.characterVariants.sanitize (c), __PRETTY_FUNCTION__
, 714)
;
715 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 715);
716 }
717
718 void collect_name_ids (hb_tag_t tag, hb_set_t *nameids_to_retain /* OUT */) const
719 {
720#ifdef HB_NO_LAYOUT_FEATURE_PARAMS
721 return;
722#endif
723 if (tag == HB_TAG ('s','i','z','e')((hb_tag_t)((((uint32_t)('s')&0xFF)<<24)|(((uint32_t
)('i')&0xFF)<<16)|(((uint32_t)('z')&0xFF)<<
8)|((uint32_t)('e')&0xFF)))
&& hb_barrier ())
724 return (u.size.collect_name_ids (nameids_to_retain));
725 if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')((hb_tag_t)((((uint32_t)('s')&0xFF)<<24)|(((uint32_t
)('s')&0xFF)<<16)|(((uint32_t)('\0')&0xFF)<<
8)|((uint32_t)('\0')&0xFF)))
) /* ssXX */
726 return (u.stylisticSet.collect_name_ids (nameids_to_retain));
727 if ((tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')((hb_tag_t)((((uint32_t)('c')&0xFF)<<24)|(((uint32_t
)('v')&0xFF)<<16)|(((uint32_t)('\0')&0xFF)<<
8)|((uint32_t)('\0')&0xFF)))
) /* cvXX */
728 return (u.characterVariants.collect_name_ids (nameids_to_retain));
729 }
730
731 bool subset (hb_subset_context_t *c, const Tag* tag) const
732 {
733 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
734 if (!tag) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 734);
735 if (*tag == HB_TAG ('s','i','z','e')((hb_tag_t)((((uint32_t)('s')&0xFF)<<24)|(((uint32_t
)('i')&0xFF)<<16)|(((uint32_t)('z')&0xFF)<<
8)|((uint32_t)('e')&0xFF)))
&& hb_barrier ())
736 return_trace (u.size.subset (c))return trace.ret (u.size.subset (c), __PRETTY_FUNCTION__, 736
)
;
737 if ((*tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')((hb_tag_t)((((uint32_t)('s')&0xFF)<<24)|(((uint32_t
)('s')&0xFF)<<16)|(((uint32_t)('\0')&0xFF)<<
8)|((uint32_t)('\0')&0xFF)))
) /* ssXX */
738 return_trace (u.stylisticSet.subset (c))return trace.ret (u.stylisticSet.subset (c), __PRETTY_FUNCTION__
, 738)
;
739 if ((*tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')((hb_tag_t)((((uint32_t)('c')&0xFF)<<24)|(((uint32_t
)('v')&0xFF)<<16)|(((uint32_t)('\0')&0xFF)<<
8)|((uint32_t)('\0')&0xFF)))
) /* cvXX */
740 return_trace (u.characterVariants.subset (c))return trace.ret (u.characterVariants.subset (c), __PRETTY_FUNCTION__
, 740)
;
741 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 741);
742 }
743
744#ifndef HB_NO_LAYOUT_FEATURE_PARAMS
745 const FeatureParamsSize& get_size_params (hb_tag_t tag) const
746 {
747 if (tag == HB_TAG ('s','i','z','e')((hb_tag_t)((((uint32_t)('s')&0xFF)<<24)|(((uint32_t
)('i')&0xFF)<<16)|(((uint32_t)('z')&0xFF)<<
8)|((uint32_t)('e')&0xFF)))
&& hb_barrier ())
748 return u.size;
749 return Null (FeatureParamsSize)NullHelper<FeatureParamsSize>::get_null ();
750 }
751 const FeatureParamsStylisticSet& get_stylistic_set_params (hb_tag_t tag) const
752 {
753 if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')((hb_tag_t)((((uint32_t)('s')&0xFF)<<24)|(((uint32_t
)('s')&0xFF)<<16)|(((uint32_t)('\0')&0xFF)<<
8)|((uint32_t)('\0')&0xFF)))
) /* ssXX */
754 return u.stylisticSet;
755 return Null (FeatureParamsStylisticSet)NullHelper<FeatureParamsStylisticSet>::get_null ();
756 }
757 const FeatureParamsCharacterVariants& get_character_variants_params (hb_tag_t tag) const
758 {
759 if ((tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')((hb_tag_t)((((uint32_t)('c')&0xFF)<<24)|(((uint32_t
)('v')&0xFF)<<16)|(((uint32_t)('\0')&0xFF)<<
8)|((uint32_t)('\0')&0xFF)))
) /* cvXX */
760 return u.characterVariants;
761 return Null (FeatureParamsCharacterVariants)NullHelper<FeatureParamsCharacterVariants>::get_null ();
762 }
763#endif
764
765 private:
766 union {
767 FeatureParamsSize size;
768 FeatureParamsStylisticSet stylisticSet;
769 FeatureParamsCharacterVariants characterVariants;
770 } u;
771 public:
772 DEFINE_SIZE_MIN (0)void _instance_assertion_on_line_772 () const { static_assert
((sizeof (*this) >= (0)), ""); } static constexpr unsigned
null_size = (0); static constexpr unsigned min_size = (0)
;
773};
774
775struct Record_sanitize_closure_t {
776 hb_tag_t tag;
777 const void *list_base;
778};
779
780struct Feature
781{
782 unsigned int get_lookup_count () const
783 { return lookupIndex.len; }
784 hb_tag_t get_lookup_index (unsigned int i) const
785 { return lookupIndex[i]; }
786 unsigned int get_lookup_indexes (unsigned int start_index,
787 unsigned int *lookup_count /* IN/OUT */,
788 unsigned int *lookup_tags /* OUT */) const
789 { return lookupIndex.get_indexes (start_index, lookup_count, lookup_tags); }
790 void add_lookup_indexes_to (hb_set_t *lookup_indexes) const
791 { lookupIndex.add_indexes_to (lookup_indexes); }
792
793 const FeatureParams &get_feature_params () const
794 { return this+featureParams; }
795
796 bool intersects_lookup_indexes (const hb_map_t *lookup_indexes) const
797 { return lookupIndex.intersects (lookup_indexes); }
798
799 void collect_name_ids (hb_tag_t tag, hb_set_t *nameids_to_retain /* OUT */) const
800 {
801 if (featureParams)
802 get_feature_params ().collect_name_ids (tag, nameids_to_retain);
803 }
804
805 bool subset (hb_subset_context_t *c,
806 hb_subset_layout_context_t *l,
807 const Tag *tag = nullptr) const
808 {
809 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
810 auto *out = c->serializer->start_embed (*this);
811 if (unlikely (!c->serializer->extend_min (out))__builtin_expect (bool(!c->serializer->extend_min (out)
), 0)
) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 811);
812
813 out->featureParams.serialize_subset (c, featureParams, this, tag);
814
815 auto it =
816 + hb_iter (lookupIndex)
817 | hb_filter (l->lookup_index_map)
818 | hb_map (l->lookup_index_map)
819 ;
820
821 out->lookupIndex.serialize (c->serializer, l, it);
822 // The decision to keep or drop this feature is already made before we get here
823 // so always retain it.
824 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 824);
825 }
826
827 bool sanitize (hb_sanitize_context_t *c,
828 const Record_sanitize_closure_t *closure = nullptr) const
829 {
830 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
831 return_trace (c->check_struct (this) &&return trace.ret (c->check_struct (this) && featureParams
.sanitize (c, this, closure ? closure->tag : ((hb_tag_t)((
((uint32_t)(0)&0xFF)<<24)|(((uint32_t)(0)&0xFF)
<<16)|(((uint32_t)(0)&0xFF)<<8)|((uint32_t)(0
)&0xFF)))) && lookupIndex.sanitize (c), __PRETTY_FUNCTION__
, 833)
832 featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE) &&return trace.ret (c->check_struct (this) && featureParams
.sanitize (c, this, closure ? closure->tag : ((hb_tag_t)((
((uint32_t)(0)&0xFF)<<24)|(((uint32_t)(0)&0xFF)
<<16)|(((uint32_t)(0)&0xFF)<<8)|((uint32_t)(0
)&0xFF)))) && lookupIndex.sanitize (c), __PRETTY_FUNCTION__
, 833)
833 lookupIndex.sanitize (c))return trace.ret (c->check_struct (this) && featureParams
.sanitize (c, this, closure ? closure->tag : ((hb_tag_t)((
((uint32_t)(0)&0xFF)<<24)|(((uint32_t)(0)&0xFF)
<<16)|(((uint32_t)(0)&0xFF)<<8)|((uint32_t)(0
)&0xFF)))) && lookupIndex.sanitize (c), __PRETTY_FUNCTION__
, 833)
;
834 }
835
836 Offset16To<FeatureParams>
837 featureParams; /* Offset to Feature Parameters table (if one
838 * has been defined for the feature), relative
839 * to the beginning of the Feature Table; = Null
840 * if not required */
841 IndexArray lookupIndex; /* Array of LookupList indices */
842 public:
843 DEFINE_SIZE_ARRAY_SIZED (4, lookupIndex)size_t get_size () const { return (4 - (lookupIndex).min_size
+ (lookupIndex).get_size ()); } void _compiles_assertion_on_line_843
() const { (void) (lookupIndex)[0].static_size; } void _instance_assertion_on_line_843
() const { static_assert ((sizeof (*this) == (4) + (1 +0) * sizeof
((lookupIndex)[0])), ""); } static constexpr unsigned null_size
= (4); static constexpr unsigned min_size = (4)
;
844};
845
846template <typename Type>
847struct Record
848{
849 int cmp (hb_tag_t a) const { return tag.cmp (a); }
850
851 bool subset (hb_subset_layout_context_t *c, const void *base, const void *f_sub = nullptr) const
852 {
853 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
854 auto *out = c->subset_context->serializer->embed (this);
855 if (unlikely (!out)__builtin_expect (bool(!out), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 855);
856
857 if (!f_sub)
858 return_trace (out->offset.serialize_subset (c->subset_context, offset, base, c, &tag))return trace.ret (out->offset.serialize_subset (c->subset_context
, offset, base, c, &tag), __PRETTY_FUNCTION__, 858)
;
859
860 const Feature& f = *reinterpret_cast<const Feature *> (f_sub);
861 auto *s = c->subset_context->serializer;
862 s->push ();
863
864 out->offset = 0;
865 bool ret = f.subset (c->subset_context, c, &tag);
866 if (ret)
867 s->add_link (out->offset, s->pop_pack ());
868 else
869 s->pop_discard ();
870
871 return_trace (ret)return trace.ret (ret, __PRETTY_FUNCTION__, 871);
872 }
873
874 bool sanitize (hb_sanitize_context_t *c, const void *base) const
875 {
876 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
877 const Record_sanitize_closure_t closure = {tag, base};
878 return_trace (c->check_struct (this) &&return trace.ret (c->check_struct (this) && offset
.sanitize (c, base, &closure), __PRETTY_FUNCTION__, 879)
879 offset.sanitize (c, base, &closure))return trace.ret (c->check_struct (this) && offset
.sanitize (c, base, &closure), __PRETTY_FUNCTION__, 879)
;
880 }
881
882 Tag tag; /* 4-byte Tag identifier */
883 Offset16To<Type>
884 offset; /* Offset from beginning of object holding
885 * the Record */
886 public:
887 DEFINE_SIZE_STATIC (6)void _instance_assertion_on_line_887 () const { static_assert
((sizeof (*this) == (6)), ""); } size_t get_size () const { return
(6); } static constexpr unsigned null_size = (6); static constexpr
unsigned min_size = (6); static constexpr unsigned static_size
= (6)
;
888};
889
890template <typename Type>
891struct RecordArrayOf : SortedArray16Of<Record<Type>>
892{
893 const Offset16To<Type>& get_offset (unsigned int i) const
894 { return (*this)[i].offset; }
895 Offset16To<Type>& get_offset (unsigned int i)
896 { return (*this)[i].offset; }
897 const Tag& get_tag (unsigned int i) const
898 { return (*this)[i].tag; }
899 unsigned int get_tags (unsigned int start_offset,
900 unsigned int *record_count /* IN/OUT */,
901 hb_tag_t *record_tags /* OUT */) const
902 {
903 if (record_count && record_tags)
904 {
905 + this->as_array ().sub_array (start_offset, record_count)
906 | hb_map (&Record<Type>::tag)
907 | hb_sink (hb_array (record_tags, *record_count))
908 ;
909 }
910 return this->len;
911 }
912 bool find_index (hb_tag_t tag, unsigned int *index) const
913 {
914 return this->bfind (tag, index, HB_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX);
915 }
916};
917
918template <typename Type>
919struct RecordListOf : RecordArrayOf<Type>
920{
921 const Type& operator [] (unsigned int i) const
922 { return this+this->get_offset (i); }
923
924 bool subset (hb_subset_context_t *c,
925 hb_subset_layout_context_t *l) const
926 {
927 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
928 auto *out = c->serializer->start_embed (*this);
929 if (unlikely (!c->serializer->extend_min (out))__builtin_expect (bool(!c->serializer->extend_min (out)
), 0)
) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 929);
930
931 + this->iter ()
932 | hb_apply (subset_record_array (l, out, this))
933 ;
934 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 934);
935 }
936
937 bool sanitize (hb_sanitize_context_t *c) const
938 {
939 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
940 return_trace (RecordArrayOf<Type>::sanitize (c, this))return trace.ret (RecordArrayOf<Type>::sanitize (c, this
), __PRETTY_FUNCTION__, 940)
;
941 }
942};
943
944struct RecordListOfFeature : RecordListOf<Feature>
945{
946 bool subset (hb_subset_context_t *c,
947 hb_subset_layout_context_t *l) const
948 {
949 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
950 auto *out = c->serializer->start_embed (*this);
951 if (unlikely (!c->serializer->extend_min (out))__builtin_expect (bool(!c->serializer->extend_min (out)
), 0)
) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 951);
952
953 + hb_enumerate (*this)
954 | hb_filter (l->feature_index_map, hb_first)
955 | hb_apply ([l, out, this] (const hb_pair_t<unsigned, const Record<Feature>&>& _)
956 {
957 const Feature *f_sub = nullptr;
958 const Feature **f = nullptr;
959 if (l->feature_substitutes_map->has (_.first, &f))
960 f_sub = *f;
961
962 subset_record_array (l, out, this, f_sub) (_.second);
963 })
964 ;
965
966 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 966);
967 }
968};
969
970typedef RecordListOf<Feature> FeatureList;
971
972
973struct LangSys
974{
975 unsigned int get_feature_count () const
976 { return featureIndex.len; }
977 hb_tag_t get_feature_index (unsigned int i) const
978 { return featureIndex[i]; }
979 unsigned int get_feature_indexes (unsigned int start_offset,
980 unsigned int *feature_count /* IN/OUT */,
981 unsigned int *feature_indexes /* OUT */) const
982 { return featureIndex.get_indexes (start_offset, feature_count, feature_indexes); }
983 void add_feature_indexes_to (hb_set_t *feature_indexes) const
984 { featureIndex.add_indexes_to (feature_indexes); }
985
986 bool has_required_feature () const { return reqFeatureIndex != 0xFFFFu; }
987 unsigned int get_required_feature_index () const
988 {
989 if (reqFeatureIndex == 0xFFFFu)
990 return Index::NOT_FOUND_INDEX;
991 return reqFeatureIndex;
992 }
993
994 LangSys* copy (hb_serialize_context_t *c) const
995 {
996 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
997 return_trace (c->embed (*this))return trace.ret (c->embed (*this), __PRETTY_FUNCTION__, 997
)
;
998 }
999
1000 bool compare (const LangSys& o, const hb_map_t *feature_index_map) const
1001 {
1002 if (reqFeatureIndex != o.reqFeatureIndex)
1003 return false;
1004
1005 auto iter =
1006 + hb_iter (featureIndex)
1007 | hb_filter (feature_index_map)
1008 | hb_map (feature_index_map)
1009 ;
1010
1011 auto o_iter =
1012 + hb_iter (o.featureIndex)
1013 | hb_filter (feature_index_map)
1014 | hb_map (feature_index_map)
1015 ;
1016
1017 for (; iter && o_iter; iter++, o_iter++)
1018 {
1019 unsigned a = *iter;
1020 unsigned b = *o_iter;
1021 if (a != b) return false;
1022 }
1023
1024 if (iter || o_iter) return false;
1025
1026 return true;
1027 }
1028
1029 void collect_features (hb_prune_langsys_context_t *c) const
1030 {
1031 if (!has_required_feature () && !get_feature_count ()) return;
1032 if (has_required_feature () &&
1033 c->duplicate_feature_map->has (reqFeatureIndex))
1034 c->new_feature_indexes->add (get_required_feature_index ());
1035
1036 + hb_iter (featureIndex)
1037 | hb_filter (c->duplicate_feature_map)
1038 | hb_sink (c->new_feature_indexes)
1039 ;
1040 }
1041
1042 bool subset (hb_subset_context_t *c,
1043 hb_subset_layout_context_t *l,
1044 const Tag *tag = nullptr) const
1045 {
1046 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
1047 auto *out = c->serializer->start_embed (*this);
1048 if (unlikely (!c->serializer->extend_min (out))__builtin_expect (bool(!c->serializer->extend_min (out)
), 0)
) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 1048);
1049
1050 const uint32_t *v;
1051 out->reqFeatureIndex = l->feature_map_w_duplicates->has (reqFeatureIndex, &v) ? *v : 0xFFFFu;
1052
1053 if (!l->visitFeatureIndex (featureIndex.len))
1054 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 1054);
1055
1056 auto it =
1057 + hb_iter (featureIndex)
1058 | hb_filter (l->feature_map_w_duplicates)
1059 | hb_map (l->feature_map_w_duplicates)
1060 ;
1061
1062 bool ret = bool (it);
1063 out->featureIndex.serialize (c->serializer, l, it);
1064 return_trace (ret)return trace.ret (ret, __PRETTY_FUNCTION__, 1064);
1065 }
1066
1067 bool sanitize (hb_sanitize_context_t *c,
1068 const Record_sanitize_closure_t * = nullptr) const
1069 {
1070 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
1071 return_trace (c->check_struct (this) && featureIndex.sanitize (c))return trace.ret (c->check_struct (this) && featureIndex
.sanitize (c), __PRETTY_FUNCTION__, 1071)
;
1072 }
1073
1074 Offset16 lookupOrderZ; /* = Null (reserved for an offset to a
1075 * reordering table) */
1076 HBUINT16 reqFeatureIndex;/* Index of a feature required for this
1077 * language system--if no required features
1078 * = 0xFFFFu */
1079 IndexArray featureIndex; /* Array of indices into the FeatureList */
1080 public:
1081 DEFINE_SIZE_ARRAY_SIZED (6, featureIndex)size_t get_size () const { return (6 - (featureIndex).min_size
+ (featureIndex).get_size ()); } void _compiles_assertion_on_line_1081
() const { (void) (featureIndex)[0].static_size; } void _instance_assertion_on_line_1081
() const { static_assert ((sizeof (*this) == (6) + (1 +0) * sizeof
((featureIndex)[0])), ""); } static constexpr unsigned null_size
= (6); static constexpr unsigned min_size = (6)
;
1082};
1083DECLARE_NULL_NAMESPACE_BYTES (OT, LangSys)} extern __attribute__((__visibility__("hidden"))) const unsigned
char _hb_Null_OT_LangSys[hb_null_size<OT::LangSys>::value
]; template <> struct Null<OT::LangSys> { static OT
::LangSys const & get_null () { return *reinterpret_cast<
const OT::LangSys *> (_hb_Null_OT_LangSys); } }; namespace
OT { static_assert (true, "")
;
1084
1085struct Script
1086{
1087 unsigned int get_lang_sys_count () const
1088 { return langSys.len; }
1089 const Tag& get_lang_sys_tag (unsigned int i) const
1090 { return langSys.get_tag (i); }
1091 unsigned int get_lang_sys_tags (unsigned int start_offset,
1092 unsigned int *lang_sys_count /* IN/OUT */,
1093 hb_tag_t *lang_sys_tags /* OUT */) const
1094 { return langSys.get_tags (start_offset, lang_sys_count, lang_sys_tags); }
1095 const LangSys& get_lang_sys (unsigned int i) const
1096 {
1097 if (i == Index::NOT_FOUND_INDEX) return get_default_lang_sys ();
1098 return this+langSys[i].offset;
1099 }
1100 bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const
1101 { return langSys.find_index (tag, index); }
1102
1103 bool has_default_lang_sys () const { return defaultLangSys != 0; }
1104 const LangSys& get_default_lang_sys () const { return this+defaultLangSys; }
1105
1106 void prune_langsys (hb_prune_langsys_context_t *c,
1107 unsigned script_index) const
1108 {
1109 if (!has_default_lang_sys () && !get_lang_sys_count ()) return;
1110 if (!c->visitScript ()) return;
1111
1112 if (!c->script_langsys_map->has (script_index))
1113 {
1114 if (unlikely (!c->script_langsys_map->set (script_index, hb::unique_ptr<hb_set_t> {hb_set_create ()}))__builtin_expect (bool(!c->script_langsys_map->set (script_index
, hb::unique_ptr<hb_set_t> {hb_set_create ()})), 0)
)
1115 return;
1116 }
1117
1118 if (has_default_lang_sys ())
1119 {
1120 //only collect features from non-redundant langsys
1121 const LangSys& d = get_default_lang_sys ();
1122 if (c->visitLangsys (d.get_feature_count ())) {
1123 d.collect_features (c);
1124 }
1125
1126 for (auto _ : + hb_enumerate (langSys))
1127 {
1128 const LangSys& l = this+_.second.offset;
1129 if (!c->visitLangsys (l.get_feature_count ())) continue;
1130 if (l.compare (d, c->duplicate_feature_map)) continue;
1131
1132 l.collect_features (c);
1133 c->script_langsys_map->get (script_index)->add (_.first);
1134 }
1135 }
1136 else
1137 {
1138 for (auto _ : + hb_enumerate (langSys))
1139 {
1140 const LangSys& l = this+_.second.offset;
1141 if (!c->visitLangsys (l.get_feature_count ())) continue;
1142 l.collect_features (c);
1143 c->script_langsys_map->get (script_index)->add (_.first);
1144 }
1145 }
1146 }
1147
1148 bool subset (hb_subset_context_t *c,
1149 hb_subset_layout_context_t *l,
1150 const Tag *tag) const
1151 {
1152 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
1153 if (!l->visitScript ()) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 1153);
1154 if (tag && !c->plan->layout_scripts.has (*tag))
1155 return false;
1156
1157 auto *out = c->serializer->start_embed (*this);
1158 if (unlikely (!c->serializer->extend_min (out))__builtin_expect (bool(!c->serializer->extend_min (out)
), 0)
) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 1158);
1159
1160 bool defaultLang = false;
1161 if (has_default_lang_sys ())
1162 {
1163 c->serializer->push ();
1164 const LangSys& ls = this+defaultLangSys;
1165 bool ret = ls.subset (c, l);
1166 if (!ret && tag && *tag != HB_TAG ('D', 'F', 'L', 'T')((hb_tag_t)((((uint32_t)('D')&0xFF)<<24)|(((uint32_t
)('F')&0xFF)<<16)|(((uint32_t)('L')&0xFF)<<
8)|((uint32_t)('T')&0xFF)))
)
1167 {
1168 c->serializer->pop_discard ();
1169 out->defaultLangSys = 0;
1170 }
1171 else
1172 {
1173 c->serializer->add_link (out->defaultLangSys, c->serializer->pop_pack ());
1174 defaultLang = true;
1175 }
1176 }
1177
1178 const hb_set_t *active_langsys = l->script_langsys_map->get (l->cur_script_index);
1179 if (active_langsys)
1180 {
1181 + hb_enumerate (langSys)
1182 | hb_filter (active_langsys, hb_first)
1183 | hb_map (hb_second)
1184 | hb_filter ([=] (const Record<LangSys>& record) {return l->visitLangSys (); })
1185 | hb_apply (subset_record_array (l, &(out->langSys), this))
1186 ;
1187 }
1188
1189 return_trace (bool (out->langSys.len) || defaultLang || l->table_tag == HB_OT_TAG_GSUB)return trace.ret (bool (out->langSys.len) || defaultLang ||
l->table_tag == ((hb_tag_t)((((uint32_t)('G')&0xFF)<<
24)|(((uint32_t)('S')&0xFF)<<16)|(((uint32_t)('U')&
0xFF)<<8)|((uint32_t)('B')&0xFF))), __PRETTY_FUNCTION__
, 1189)
;
1190 }
1191
1192 bool sanitize (hb_sanitize_context_t *c,
1193 const Record_sanitize_closure_t * = nullptr) const
1194 {
1195 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
1196 return_trace (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this))return trace.ret (defaultLangSys.sanitize (c, this) &&
langSys.sanitize (c, this), __PRETTY_FUNCTION__, 1196)
;
1197 }
1198
1199 protected:
1200 Offset16To<LangSys>
1201 defaultLangSys; /* Offset to DefaultLangSys table--from
1202 * beginning of Script table--may be Null */
1203 RecordArrayOf<LangSys>
1204 langSys; /* Array of LangSysRecords--listed
1205 * alphabetically by LangSysTag */
1206 public:
1207 DEFINE_SIZE_ARRAY_SIZED (4, langSys)size_t get_size () const { return (4 - (langSys).min_size + (
langSys).get_size ()); } void _compiles_assertion_on_line_1207
() const { (void) (langSys)[0].static_size; } void _instance_assertion_on_line_1207
() const { static_assert ((sizeof (*this) == (4) + (1 +0) * sizeof
((langSys)[0])), ""); } static constexpr unsigned null_size =
(4); static constexpr unsigned min_size = (4)
;
1208};
1209
1210struct RecordListOfScript : RecordListOf<Script>
1211{
1212 bool subset (hb_subset_context_t *c,
1213 hb_subset_layout_context_t *l) const
1214 {
1215 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
1216 auto *out = c->serializer->start_embed (*this);
1217 if (unlikely (!c->serializer->extend_min (out))__builtin_expect (bool(!c->serializer->extend_min (out)
), 0)
) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 1217);
1218
1219 for (auto _ : + hb_enumerate (*this))
1220 {
1221 auto snap = c->serializer->snapshot ();
1222 l->cur_script_index = _.first;
1223 bool ret = _.second.subset (l, this);
1224 if (!ret) c->serializer->revert (snap);
1225 else out->len++;
1226 }
1227
1228 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 1228);
1229 }
1230};
1231
1232typedef RecordListOfScript ScriptList;
1233
1234
1235
1236struct LookupFlag : HBUINT16
1237{
1238 enum Flags {
1239 RightToLeft = 0x0001u,
1240 IgnoreBaseGlyphs = 0x0002u,
1241 IgnoreLigatures = 0x0004u,
1242 IgnoreMarks = 0x0008u,
1243 IgnoreFlags = 0x000Eu,
1244 UseMarkFilteringSet = 0x0010u,
1245 Reserved = 0x00E0u,
1246 MarkAttachmentType = 0xFF00u
1247 };
1248 public:
1249 DEFINE_SIZE_STATIC (2)void _instance_assertion_on_line_1249 () const { static_assert
((sizeof (*this) == (2)), ""); } size_t get_size () const { return
(2); } static constexpr unsigned null_size = (2); static constexpr
unsigned min_size = (2); static constexpr unsigned static_size
= (2)
;
1250};
1251
1252} /* namespace OT */
1253/* This has to be outside the namespace. */
1254HB_MARK_AS_FLAG_T (OT::LookupFlag::Flags)extern "C++" { static inline constexpr OT::LookupFlag::Flags operator
| (OT::LookupFlag::Flags l, OT::LookupFlag::Flags r) { return
OT::LookupFlag::Flags ((unsigned) l | (unsigned) r); } static
inline constexpr OT::LookupFlag::Flags operator & (OT::LookupFlag
::Flags l, OT::LookupFlag::Flags r) { return OT::LookupFlag::
Flags ((unsigned) l & (unsigned) r); } static inline constexpr
OT::LookupFlag::Flags operator ^ (OT::LookupFlag::Flags l, OT
::LookupFlag::Flags r) { return OT::LookupFlag::Flags ((unsigned
) l ^ (unsigned) r); } static inline constexpr unsigned operator
~ (OT::LookupFlag::Flags r) { return (~(unsigned) r); } static
inline OT::LookupFlag::Flags& operator |= (OT::LookupFlag
::Flags &l, OT::LookupFlag::Flags r) { l = l | r; return l
; } static inline OT::LookupFlag::Flags& operator &= (
OT::LookupFlag::Flags& l, OT::LookupFlag::Flags r) { l = l
& r; return l; } static inline OT::LookupFlag::Flags&
operator ^= (OT::LookupFlag::Flags& l, OT::LookupFlag::Flags
r) { l = l ^ r; return l; } } static_assert (true, "")
;
1255namespace OT {
1256
1257struct Lookup
1258{
1259 unsigned int get_subtable_count () const { return subTable.len; }
1260
1261 template <typename TSubTable>
1262 const Array16OfOffset16To<TSubTable>& get_subtables () const
1263 { return reinterpret_cast<const Array16OfOffset16To<TSubTable> &> (subTable); }
1264 template <typename TSubTable>
1265 Array16OfOffset16To<TSubTable>& get_subtables ()
1266 { return reinterpret_cast<Array16OfOffset16To<TSubTable> &> (subTable); }
1267
1268 template <typename TSubTable>
1269 const TSubTable& get_subtable (unsigned int i) const
1270 { return this+get_subtables<TSubTable> ()[i]; }
1271 template <typename TSubTable>
1272 TSubTable& get_subtable (unsigned int i)
1273 { return this+get_subtables<TSubTable> ()[i]; }
1274
1275 size_t get_size () const
1276 {
1277 const HBUINT16 &markFilteringSet = StructAfter<const HBUINT16> (subTable);
1278 if (lookupFlag & LookupFlag::UseMarkFilteringSet)
1279 return (const char *) &StructAfter<const char> (markFilteringSet) - (const char *) this;
1280 return (const char *) &markFilteringSet - (const char *) this;
1281 }
1282
1283 unsigned int get_type () const { return lookupType; }
1284
1285 /* lookup_props is a 32-bit integer where the lower 16-bit is LookupFlag and
1286 * higher 16-bit is mark-filtering-set if the lookup uses one.
1287 * Not to be confused with glyph_props which is very similar. */
1288 uint32_t get_props () const
1289 {
1290 unsigned int flag = lookupFlag;
1291 if (unlikely (flag & LookupFlag::UseMarkFilteringSet)__builtin_expect (bool(flag & LookupFlag::UseMarkFilteringSet
), 0)
)
1292 {
1293 const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
1294 flag += (markFilteringSet << 16);
1295 }
1296 return flag;
1297 }
1298
1299 template <typename TSubTable, typename context_t, typename ...Ts>
1300 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
1301 {
1302 unsigned int lookup_type = get_type ();
1303 TRACE_DISPATCH (this, lookup_type)hb_no_trace_t<typename context_t::return_t> trace;
1304 unsigned int count = get_subtable_count ();
1305 for (unsigned int i = 0; i < count; i++) {
1306 typename context_t::return_t r = get_subtable<TSubTable> (i).dispatch (c, lookup_type, ds...);
1307 if (c->stop_sublookup_iteration (r))
1308 return_trace (r)return trace.ret (r, __PRETTY_FUNCTION__, 1308);
1309 }
1310 return_trace (c->default_return_value ())return trace.ret (c->default_return_value (), __PRETTY_FUNCTION__
, 1310)
;
1311 }
1312
1313 bool serialize (hb_serialize_context_t *c,
1314 unsigned int lookup_type,
1315 uint32_t lookup_props,
1316 unsigned int num_subtables)
1317 {
1318 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
1319 if (unlikely (!c->extend_min (this))__builtin_expect (bool(!c->extend_min (this)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 1319);
1320 lookupType = lookup_type;
1321 lookupFlag = lookup_props & 0xFFFFu;
1322 if (unlikely (!subTable.serialize (c, num_subtables))__builtin_expect (bool(!subTable.serialize (c, num_subtables)
), 0)
) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 1322);
1323 if (lookupFlag & LookupFlag::UseMarkFilteringSet)
1324 {
1325 if (unlikely (!c->extend (this))__builtin_expect (bool(!c->extend (this)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 1325);
1326 HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
1327 markFilteringSet = lookup_props >> 16;
1328 }
1329 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 1329);
1330 }
1331
1332 template <typename TSubTable>
1333 bool subset (hb_subset_context_t *c) const
1334 {
1335 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
1336 auto *out = c->serializer->start_embed (*this);
1337 if (unlikely (!c->serializer->extend_min (out))__builtin_expect (bool(!c->serializer->extend_min (out)
), 0)
) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 1337);
1338 out->lookupType = lookupType;
1339 out->lookupFlag = lookupFlag;
1340
1341 const hb_set_t *glyphset = c->plan->glyphset_gsub ();
1342 unsigned int lookup_type = get_type ();
1343 + hb_iter (get_subtables <TSubTable> ())
1344 | hb_filter ([this, glyphset, lookup_type] (const Offset16To<TSubTable> &_) { return (this+_).intersects (glyphset, lookup_type); })
1345 | hb_apply (subset_offset_array (c, out->get_subtables<TSubTable> (), this, lookup_type))
1346 ;
1347
1348 if (lookupFlag & LookupFlag::UseMarkFilteringSet)
1349 {
1350 const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
1351 hb_codepoint_t *idx;
1352 if (!c->plan->used_mark_sets_map.has (markFilteringSet, &idx))
1353 {
1354 unsigned new_flag = lookupFlag;
1355 new_flag &= ~LookupFlag::UseMarkFilteringSet;
1356 // https://github.com/harfbuzz/harfbuzz/issues/5499
1357 // If we remove UseMarkFilteringSet flag because the set is now empty,
1358 // we need to add IgnoreMarks flag, otherwise the lookup will not
1359 // ignore any marks, which changes the behavior.
1360 new_flag |= LookupFlag::IgnoreMarks;
1361 out->lookupFlag = new_flag;
1362 }
1363 else
1364 {
1365 if (unlikely (!c->serializer->extend (out))__builtin_expect (bool(!c->serializer->extend (out)), 0
)
) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 1365);
1366 HBUINT16 &outMarkFilteringSet = StructAfter<HBUINT16> (out->subTable);
1367 outMarkFilteringSet = *idx;
1368 }
1369 }
1370
1371 // Always keep the lookup even if it's empty. The rest of layout subsetting depends on lookup
1372 // indices being consistent with those computed during planning. So if an empty lookup is
1373 // discarded during the subset phase it will invalidate all subsequent lookup indices.
1374 // Generally we shouldn't end up with an empty lookup as we pre-prune them during the planning
1375 // phase, but it can happen in rare cases such as when during closure subtable is considered
1376 // degenerate (see: https://github.com/harfbuzz/harfbuzz/issues/3853)
1377 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 1377);
1378 }
1379
1380 template <typename TSubTable>
1381 bool sanitize (hb_sanitize_context_t *c) const
1382 {
1383 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
1384 if (!(c->check_struct (this) && subTable.sanitize (c))) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 1384);
1385 hb_barrier ();
1386
1387 unsigned subtables = get_subtable_count ();
1388 if (unlikely (!c->visit_subtables (subtables))__builtin_expect (bool(!c->visit_subtables (subtables)), 0
)
) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 1388);
1389
1390 if (lookupFlag & LookupFlag::UseMarkFilteringSet)
1391 {
1392 const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
1393 if (!markFilteringSet.sanitize (c)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 1393);
1394 }
1395
1396 if (unlikely (!get_subtables<TSubTable> ().sanitize (c, this, get_type ()))__builtin_expect (bool(!get_subtables<TSubTable> ().sanitize
(c, this, get_type ())), 0)
)
1397 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 1397);
1398
1399 if (unlikely (get_type () == TSubTable::Extension)__builtin_expect (bool(get_type () == TSubTable::Extension), 0
)
)
1400 {
1401 hb_barrier ();
1402
1403 /* The spec says all subtables of an Extension lookup should
1404 * have the same type, which shall not be the Extension type
1405 * itself (but we already checked for that).
1406 * This is specially important if one has a reverse type!
1407 */
1408 unsigned int type = get_subtable<TSubTable> (0).u.extension.get_type ();
1409 for (unsigned int i = 1; i < subtables; i++)
1410 if (get_subtable<TSubTable> (i).u.extension.get_type () != type)
1411 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 1411);
1412 }
1413 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 1413);
1414 }
1415
1416 protected:
1417 HBUINT16 lookupType; /* Different enumerations for GSUB and GPOS */
1418 HBUINT16 lookupFlag; /* Lookup qualifiers */
1419 Array16Of<Offset16>
1420 subTable; /* Array of SubTables */
1421/*HBUINT16 markFilteringSetX[HB_VAR_ARRAY];*//* Index (base 0) into GDEF mark glyph sets
1422 * structure. This field is only present if bit
1423 * UseMarkFilteringSet of lookup flags is set. */
1424 public:
1425 DEFINE_SIZE_ARRAY (6, subTable)void _compiles_assertion_on_line_1425 () const { (void) (subTable
)[0].static_size; } void _instance_assertion_on_line_1425 () const
{ static_assert ((sizeof (*this) == (6) + (1 +0) * sizeof ((
subTable)[0])), ""); } static constexpr unsigned null_size = (
6); static constexpr unsigned min_size = (6)
;
1426};
1427
1428template <typename Types>
1429using LookupList = List16OfOffsetTo<Lookup, typename Types::HBUINT>;
1430
1431template <typename TLookup, typename OffsetType>
1432struct LookupOffsetList : List16OfOffsetTo<TLookup, OffsetType>
1433{
1434 bool subset (hb_subset_context_t *c,
1435 hb_subset_layout_context_t *l) const
1436 {
1437 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
1438 auto *out = c->serializer->start_embed (this);
1439 if (unlikely (!c->serializer->extend_min (out))__builtin_expect (bool(!c->serializer->extend_min (out)
), 0)
) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 1439);
1440
1441 + hb_enumerate (*this)
1442 | hb_filter (l->lookup_index_map, hb_first)
1443 | hb_map (hb_second)
1444 | hb_apply (subset_offset_array (c, *out, this))
1445 ;
1446 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 1446);
1447 }
1448
1449 bool sanitize (hb_sanitize_context_t *c) const
1450 {
1451 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
1452 return_trace (List16OfOffset16To<TLookup>::sanitize (c, this))return trace.ret (List16OfOffset16To<TLookup>::sanitize
(c, this), __PRETTY_FUNCTION__, 1452)
;
1453 }
1454};
1455
1456
1457/*
1458 * Coverage Table
1459 */
1460
1461
1462static bool ClassDef_remap_and_serialize (hb_serialize_context_t *c,
1463 const hb_set_t &klasses,
1464 bool use_class_zero,
1465 hb_sorted_vector_t<hb_codepoint_pair_t> &glyph_and_klass, /* IN/OUT */
1466 hb_map_t *klass_map /*IN/OUT*/)
1467{
1468 if (!klass_map)
1469 return ClassDef_serialize (c, glyph_and_klass.iter ());
1470
1471 /* any glyph not assigned a class value falls into Class zero (0),
1472 * if any glyph assigned to class 0, remapping must start with 0->0*/
1473 if (!use_class_zero)
1474 klass_map->set (0, 0);
1475
1476 unsigned idx = klass_map->has (0) ? 1 : 0;
1477 for (const unsigned k: klasses)
1478 {
1479 if (klass_map->has (k)) continue;
1480 klass_map->set (k, idx);
1481 idx++;
1482 }
1483
1484
1485 for (unsigned i = 0; i < glyph_and_klass.length; i++)
1486 {
1487 hb_codepoint_t klass = glyph_and_klass[i].second;
1488 glyph_and_klass[i].second = klass_map->get (klass);
1489 }
1490
1491 c->propagate_error (glyph_and_klass, klasses);
1492 return ClassDef_serialize (c, glyph_and_klass.iter ());
1493}
1494
1495/*
1496 * Class Definition Table
1497 */
1498
1499template <typename Types>
1500struct ClassDefFormat1_3
1501{
1502 friend struct ClassDef;
1503
1504 private:
1505 unsigned int get_class (hb_codepoint_t glyph_id) const
1506 {
1507 return classValue[(unsigned int) (glyph_id - startGlyph)];
1508 }
1509
1510 unsigned get_population () const
1511 {
1512 return classValue.len;
1513 }
1514
1515 template<typename Iterator,
1516 hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))typename hb_enable_if<(((hb_is_source_of<Iterator, hb_codepoint_t
>::value && Iterator::is_sorted_iterator)))>::type
* = nullptr
>
1517 bool serialize (hb_serialize_context_t *c,
1518 Iterator it)
1519 {
1520 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
1521 if (unlikely (!c->extend_min (this))__builtin_expect (bool(!c->extend_min (this)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 1521);
1522
1523 if (unlikely (!it)__builtin_expect (bool(!it), 0))
1524 {
1525 classFormat = 1;
1526 startGlyph = 0;
1527 classValue.len = 0;
1528 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 1528);
1529 }
1530
1531 hb_codepoint_t glyph_min = (*it).first;
1532 hb_codepoint_t glyph_max = + it
1533 | hb_map (hb_first)
1534 | hb_reduce (hb_max, 0u);
1535 unsigned glyph_count = glyph_max - glyph_min + 1;
1536
1537 startGlyph = glyph_min;
1538 if (unlikely (!classValue.serialize (c, glyph_count))__builtin_expect (bool(!classValue.serialize (c, glyph_count)
), 0)
) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 1538);
1539 for (const hb_pair_t<hb_codepoint_t, uint32_t> gid_klass_pair : + it)
1540 {
1541 unsigned idx = gid_klass_pair.first - glyph_min;
1542 classValue[idx] = gid_klass_pair.second;
1543 }
1544 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 1544);
1545 }
1546
1547 bool subset (hb_subset_context_t *c,
1548 hb_map_t *klass_map = nullptr /*OUT*/,
1549 bool keep_empty_table = true,
1550 bool use_class_zero = true,
1551 const Coverage* glyph_filter = nullptr) const
1552 {
1553 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
1554
1555 hb_sorted_vector_t<hb_codepoint_pair_t> glyph_and_klass;
1556 hb_set_t orig_klasses;
1557
1558 hb_codepoint_t start = startGlyph;
1559 hb_codepoint_t end = start + classValue.len;
1560
1561 for (const hb_codepoint_t gid : + hb_range (start, end))
1562 {
1563 hb_codepoint_t new_gid = c->plan->map_gsub_glyph (gid);
1564 if (new_gid == HB_MAP_VALUE_INVALID((hb_codepoint_t) -1)) continue;
1565 if (glyph_filter && !glyph_filter->has(gid)) continue;
1566
1567 unsigned klass = classValue[gid - start];
1568 if (!klass) continue;
1569
1570 glyph_and_klass.push (hb_pair (new_gid, klass));
1571 orig_klasses.add (klass);
1572 }
1573
1574 if (use_class_zero)
1575 {
1576 const hb_set_t& glyphset = *c->plan->glyphset_gsub ();
1577 unsigned glyph_count = glyph_filter
1578 ? hb_len (hb_iter (glyphset) | hb_filter (glyph_filter))
1579 : glyphset.get_population ();
1580 use_class_zero = glyph_count <= glyph_and_klass.length;
1581 }
1582 if (!ClassDef_remap_and_serialize (c->serializer,
1583 orig_klasses,
1584 use_class_zero,
1585 glyph_and_klass,
1586 klass_map))
1587 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 1587);
1588 return_trace (keep_empty_table || (bool) glyph_and_klass)return trace.ret (keep_empty_table || (bool) glyph_and_klass,
__PRETTY_FUNCTION__, 1588)
;
1589 }
1590
1591 bool sanitize (hb_sanitize_context_t *c) const
1592 {
1593 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
1594 return_trace (c->check_struct (this) && classValue.sanitize (c))return trace.ret (c->check_struct (this) && classValue
.sanitize (c), __PRETTY_FUNCTION__, 1594)
;
1595 }
1596
1597 unsigned cost () const { return 1; }
1598
1599 template <typename set_t>
1600 bool collect_coverage (set_t *glyphs) const
1601 {
1602 unsigned int start = 0;
1603 unsigned int count = classValue.len;
1604 for (unsigned int i = 0; i < count; i++)
1605 {
1606 if (classValue[i])
1607 continue;
1608
1609 if (start != i)
1610 if (unlikely (!glyphs->add_range (startGlyph + start, startGlyph + i))__builtin_expect (bool(!glyphs->add_range (startGlyph + start
, startGlyph + i)), 0)
)
1611 return false;
1612
1613 start = i + 1;
1614 }
1615 if (start != count)
1616 if (unlikely (!glyphs->add_range (startGlyph + start, startGlyph + count))__builtin_expect (bool(!glyphs->add_range (startGlyph + start
, startGlyph + count)), 0)
)
1617 return false;
1618
1619 return true;
1620 }
1621
1622 template <typename set_t>
1623 bool collect_class (set_t *glyphs, unsigned klass) const
1624 {
1625 unsigned int count = classValue.len;
1626 for (unsigned int i = 0; i < count; i++)
1627 if (classValue[i] == klass) glyphs->add (startGlyph + i);
1628 return true;
1629 }
1630
1631 bool intersects (const hb_set_t *glyphs) const
1632 {
1633 hb_codepoint_t start = startGlyph;
1634 hb_codepoint_t end = startGlyph + classValue.len;
1635 for (hb_codepoint_t iter = startGlyph - 1;
1636 glyphs->next (&iter) && iter < end;)
1637 if (classValue[iter - start]) return true;
1638 return false;
1639 }
1640 bool intersects_class (const hb_set_t *glyphs, uint16_t klass) const
1641 {
1642 unsigned int count = classValue.len;
1643 if (klass == 0)
1644 {
1645 /* Match if there's any glyph that is not listed! */
1646 hb_codepoint_t g = HB_SET_VALUE_INVALID((hb_codepoint_t) -1);
1647 if (!glyphs->next (&g)) return false;
1648 if (g < startGlyph) return true;
1649 g = startGlyph + count - 1;
1650 if (glyphs->next (&g)) return true;
1651 /* Fall through. */
1652 }
1653 /* TODO Speed up, using set overlap first? */
1654 /* TODO(iter) Rewrite as dagger. */
1655 const HBUINT16 *arr = classValue.arrayZ;
1656 for (unsigned int i = 0; i < count; i++)
1657 if (arr[i] == klass && glyphs->has (startGlyph + i))
1658 return true;
1659 return false;
1660 }
1661
1662 void intersected_class_glyphs (const hb_set_t *glyphs, unsigned klass, hb_set_t *intersect_glyphs) const
1663 {
1664 unsigned count = classValue.len;
1665 if (klass == 0)
1666 {
1667 unsigned start_glyph = startGlyph;
1668 for (uint32_t g = HB_SET_VALUE_INVALID((hb_codepoint_t) -1);
1669 glyphs->next (&g) && g < start_glyph;)
1670 intersect_glyphs->add (g);
1671
1672 for (uint32_t g = startGlyph + count - 1;
1673 glyphs-> next (&g);)
1674 intersect_glyphs->add (g);
1675
1676 return;
1677 }
1678
1679 for (unsigned i = 0; i < count; i++)
1680 if (classValue[i] == klass && glyphs->has (startGlyph + i))
1681 intersect_glyphs->add (startGlyph + i);
1682
1683#if 0
1684 /* The following implementation is faster asymptotically, but slower
1685 * in practice. */
1686 unsigned start_glyph = startGlyph;
1687 unsigned end_glyph = start_glyph + count;
1688 for (unsigned g = startGlyph - 1;
1689 glyphs->next (&g) && g < end_glyph;)
1690 if (classValue.arrayZ[g - start_glyph] == klass)
1691 intersect_glyphs->add (g);
1692#endif
1693 }
1694
1695 void intersected_classes (const hb_set_t *glyphs, hb_set_t *intersect_classes) const
1696 {
1697 if (glyphs->is_empty ()) return;
1698 hb_codepoint_t end_glyph = startGlyph + classValue.len - 1;
1699 if (glyphs->get_min () < startGlyph ||
1700 glyphs->get_max () > end_glyph)
1701 intersect_classes->add (0);
1702
1703 for (const auto& _ : + hb_enumerate (classValue))
1704 {
1705 hb_codepoint_t g = startGlyph + _.first;
1706 if (glyphs->has (g))
1707 intersect_classes->add (_.second);
1708 }
1709 }
1710
1711 protected:
1712 HBUINT16 classFormat; /* Format identifier--format = 1 */
1713 typename Types::HBGlyphID
1714 startGlyph; /* First GlyphID of the classValueArray */
1715 typename Types::template ArrayOf<HBUINT16>
1716 classValue; /* Array of Class Values--one per GlyphID */
1717 public:
1718 DEFINE_SIZE_ARRAY (2 + 2 * Types::size, classValue)void _compiles_assertion_on_line_1718 () const { (void) (classValue
)[0].static_size; } void _instance_assertion_on_line_1718 () const
{ static_assert ((sizeof (*this) == (2 + 2 * Types::size) + (
1 +0) * sizeof ((classValue)[0])), ""); } static constexpr unsigned
null_size = (2 + 2 * Types::size); static constexpr unsigned
min_size = (2 + 2 * Types::size)
;
1719};
1720
1721template <typename Types>
1722struct ClassDefFormat2_4
1723{
1724 friend struct ClassDef;
1725
1726 private:
1727 unsigned int get_class (hb_codepoint_t glyph_id) const
1728 {
1729 return rangeRecord.bsearch (glyph_id).value;
1730 }
1731
1732 unsigned get_population () const
1733 {
1734 typename Types::large_int ret = 0;
1735 for (const auto &r : rangeRecord)
1736 ret += r.get_population ();
1737 return ret > UINT_MAX(2147483647 *2U +1U) ? UINT_MAX(2147483647 *2U +1U) : (unsigned) ret;
1738 }
1739
1740 template<typename Iterator,
1741 hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))typename hb_enable_if<(((hb_is_source_of<Iterator, hb_codepoint_t
>::value && Iterator::is_sorted_iterator)))>::type
* = nullptr
>
1742 bool serialize (hb_serialize_context_t *c,
1743 Iterator it)
1744 {
1745 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
1746 if (unlikely (!c->extend_min (this))__builtin_expect (bool(!c->extend_min (this)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 1746);
1747
1748 if (unlikely (!it)__builtin_expect (bool(!it), 0))
1749 {
1750 classFormat = 2;
1751 rangeRecord.len = 0;
1752 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 1752);
1753 }
1754
1755 unsigned unsorted = false;
1756 unsigned num_ranges = 1;
1757 hb_codepoint_t prev_gid = (*it).first;
1758 unsigned prev_klass = (*it).second;
1759
1760 RangeRecord<Types> range_rec;
1761 range_rec.first = prev_gid;
1762 range_rec.last = prev_gid;
1763 range_rec.value = prev_klass;
1764
1765 auto *record = c->copy (range_rec);
1766 if (unlikely (!record)__builtin_expect (bool(!record), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 1766);
1767
1768 for (const auto gid_klass_pair : + (++it))
1769 {
1770 hb_codepoint_t cur_gid = gid_klass_pair.first;
1771 unsigned cur_klass = gid_klass_pair.second;
1772
1773 if (cur_gid != prev_gid + 1 ||
1774 cur_klass != prev_klass)
1775 {
1776
1777 if (unlikely (cur_gid < prev_gid)__builtin_expect (bool(cur_gid < prev_gid), 0))
1778 unsorted = true;
1779
1780 if (unlikely (!record)__builtin_expect (bool(!record), 0)) break;
1781 record->last = prev_gid;
1782 num_ranges++;
1783
1784 range_rec.first = cur_gid;
1785 range_rec.last = cur_gid;
1786 range_rec.value = cur_klass;
1787
1788 record = c->copy (range_rec);
1789 }
1790
1791 prev_klass = cur_klass;
1792 prev_gid = cur_gid;
1793 }
1794
1795 if (unlikely (c->in_error ())__builtin_expect (bool(c->in_error ()), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 1795);
1796
1797 if (likely (record)__builtin_expect (bool(record), 1)) record->last = prev_gid;
1798 rangeRecord.len = num_ranges;
1799
1800 if (unlikely (unsorted)__builtin_expect (bool(unsorted), 0))
1801 rangeRecord.as_array ().qsort (RangeRecord<Types>::cmp_range);
1802
1803 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 1803);
1804 }
1805
1806 bool subset (hb_subset_context_t *c,
1807 hb_map_t *klass_map = nullptr /*OUT*/,
1808 bool keep_empty_table = true,
1809 bool use_class_zero = true,
1810 const Coverage* glyph_filter = nullptr) const
1811 {
1812 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
1813 const hb_set_t &glyph_set = *c->plan->glyphset_gsub ();
1814
1815 hb_sorted_vector_t<hb_codepoint_pair_t> glyph_and_klass;
1816 hb_set_t orig_klasses;
1817
1818 if (glyph_set.get_population () * hb_bit_storage ((unsigned) rangeRecord.len)
1819 < get_population ())
1820 {
1821 for (hb_codepoint_t g : glyph_set)
1822 {
1823 unsigned klass = get_class (g);
1824 if (!klass) continue;
1825 hb_codepoint_t new_gid = c->plan->map_gsub_glyph (g);
1826 if (new_gid == HB_MAP_VALUE_INVALID((hb_codepoint_t) -1)) continue;
1827 if (glyph_filter && !glyph_filter->has (g)) continue;
1828 glyph_and_klass.push (hb_pair (new_gid, klass));
1829 orig_klasses.add (klass);
1830 }
1831 }
1832 else
1833 {
1834 unsigned num_source_glyphs = c->plan->source->get_num_glyphs ();
1835 for (auto &range : rangeRecord)
1836 {
1837 unsigned klass = range.value;
1838 if (!klass) continue;
1839 hb_codepoint_t start = range.first;
1840 hb_codepoint_t end = hb_min (range.last + 1, num_source_glyphs);
1841 for (hb_codepoint_t g = start; g < end; g++)
1842 {
1843 hb_codepoint_t new_gid = c->plan->map_gsub_glyph (g);
1844 if (new_gid == HB_MAP_VALUE_INVALID((hb_codepoint_t) -1)) continue;
1845 if (glyph_filter && !glyph_filter->has (g)) continue;
1846
1847 glyph_and_klass.push (hb_pair (new_gid, klass));
1848 orig_klasses.add (klass);
1849 }
1850 }
1851 }
1852
1853 const hb_set_t& glyphset = *c->plan->glyphset_gsub ();
1854 unsigned glyph_count = glyph_filter
1855 ? hb_len (hb_iter (glyphset) | hb_filter (glyph_filter))
1856 : glyphset.get_population ();
1857 use_class_zero = use_class_zero && glyph_count <= glyph_and_klass.length;
1858 if (!ClassDef_remap_and_serialize (c->serializer,
1859 orig_klasses,
1860 use_class_zero,
1861 glyph_and_klass,
1862 klass_map))
1863 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 1863);
1864 return_trace (keep_empty_table || (bool) glyph_and_klass)return trace.ret (keep_empty_table || (bool) glyph_and_klass,
__PRETTY_FUNCTION__, 1864)
;
1865 }
1866
1867 bool sanitize (hb_sanitize_context_t *c) const
1868 {
1869 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
1870 return_trace (rangeRecord.sanitize (c))return trace.ret (rangeRecord.sanitize (c), __PRETTY_FUNCTION__
, 1870)
;
1871 }
1872
1873 unsigned cost () const { return hb_bit_storage ((unsigned) rangeRecord.len); /* bsearch cost */ }
1874
1875 template <typename set_t>
1876 bool collect_coverage (set_t *glyphs) const
1877 {
1878 for (auto &range : rangeRecord)
1879 if (range.value)
1880 if (unlikely (!range.collect_coverage (glyphs))__builtin_expect (bool(!range.collect_coverage (glyphs)), 0))
1881 return false;
1882 return true;
1883 }
1884
1885 template <typename set_t>
1886 bool collect_class (set_t *glyphs, unsigned int klass) const
1887 {
1888 for (auto &range : rangeRecord)
1889 {
1890 if (range.value == klass)
1891 if (unlikely (!range.collect_coverage (glyphs))__builtin_expect (bool(!range.collect_coverage (glyphs)), 0))
1892 return false;
1893 }
1894 return true;
1895 }
1896
1897 bool intersects (const hb_set_t *glyphs) const
1898 {
1899 if (rangeRecord.len > glyphs->get_population () * hb_bit_storage ((unsigned) rangeRecord.len))
1900 {
1901 for (auto g : *glyphs)
1902 if (get_class (g))
1903 return true;
1904 return false;
1905 }
1906
1907 return hb_any (+ hb_iter (rangeRecord)
1908 | hb_map ([glyphs] (const RangeRecord<Types> &range) { return range.intersects (*glyphs) && range.value; }));
1909 }
1910 bool intersects_class (const hb_set_t *glyphs, uint16_t klass) const
1911 {
1912 if (klass == 0)
1913 {
1914 /* Match if there's any glyph that is not listed! */
1915 hb_codepoint_t g = HB_SET_VALUE_INVALID((hb_codepoint_t) -1);
1916 hb_codepoint_t last = HB_SET_VALUE_INVALID((hb_codepoint_t) -1);
1917 auto it = hb_iter (rangeRecord);
1918 for (auto &range : it)
1919 {
1920 if (it->first == last + 1)
1921 {
1922 it++;
1923 continue;
1924 }
1925
1926 if (!glyphs->next (&g))
1927 break;
1928 if (g < range.first)
1929 return true;
1930 g = range.last;
1931 last = g;
1932 }
1933 if (g != HB_SET_VALUE_INVALID((hb_codepoint_t) -1) && glyphs->next (&g))
1934 return true;
1935 /* Fall through. */
1936 }
1937 for (const auto &range : rangeRecord)
1938 if (range.value == klass && range.intersects (*glyphs))
1939 return true;
1940 return false;
1941 }
1942
1943 void intersected_class_glyphs (const hb_set_t *glyphs, unsigned klass, hb_set_t *intersect_glyphs) const
1944 {
1945 if (klass == 0)
1946 {
1947 hb_codepoint_t g = HB_SET_VALUE_INVALID((hb_codepoint_t) -1);
1948 for (auto &range : rangeRecord)
1949 {
1950 if (!glyphs->next (&g))
1951 goto done;
1952 while (g < range.first)
1953 {
1954 intersect_glyphs->add (g);
1955 if (!glyphs->next (&g))
1956 goto done;
1957 }
1958 g = range.last;
1959 }
1960 while (glyphs->next (&g))
1961 intersect_glyphs->add (g);
1962 done:
1963
1964 return;
1965 }
1966
1967 unsigned count = rangeRecord.len;
1968 if (count > glyphs->get_population () * hb_bit_storage (count))
1969 {
1970 for (auto g : *glyphs)
1971 {
1972 unsigned i;
1973 if (rangeRecord.as_array ().bfind (g, &i) &&
1974 rangeRecord.arrayZ[i].value == klass)
1975 intersect_glyphs->add (g);
1976 }
1977 return;
1978 }
1979
1980 for (auto &range : rangeRecord)
1981 {
1982 if (range.value != klass) continue;
1983
1984 unsigned end = range.last + 1;
1985 for (hb_codepoint_t g = range.first - 1;
1986 glyphs->next (&g) && g < end;)
1987 intersect_glyphs->add (g);
1988 }
1989 }
1990
1991 void intersected_classes (const hb_set_t *glyphs, hb_set_t *intersect_classes) const
1992 {
1993 if (glyphs->is_empty ()) return;
1994
1995 hb_codepoint_t g = HB_SET_VALUE_INVALID((hb_codepoint_t) -1);
1996 for (auto &range : rangeRecord)
1997 {
1998 if (!glyphs->next (&g))
1999 break;
2000 if (g < range.first)
2001 {
2002 intersect_classes->add (0);
2003 break;
2004 }
2005 g = range.last;
2006 }
2007 if (g != HB_SET_VALUE_INVALID((hb_codepoint_t) -1) && glyphs->next (&g))
2008 intersect_classes->add (0);
2009
2010 for (const auto& range : rangeRecord)
2011 if (range.intersects (*glyphs))
2012 intersect_classes->add (range.value);
2013 }
2014
2015 protected:
2016 HBUINT16 classFormat; /* Format identifier--format = 2 */
2017 typename Types::template SortedArrayOf<RangeRecord<Types>>
2018 rangeRecord; /* Array of glyph ranges--ordered by
2019 * Start GlyphID */
2020 public:
2021 DEFINE_SIZE_ARRAY (2 + Types::size, rangeRecord)void _compiles_assertion_on_line_2021 () const { (void) (rangeRecord
)[0].static_size; } void _instance_assertion_on_line_2021 () const
{ static_assert ((sizeof (*this) == (2 + Types::size) + (1 +
0) * sizeof ((rangeRecord)[0])), ""); } static constexpr unsigned
null_size = (2 + Types::size); static constexpr unsigned min_size
= (2 + Types::size)
;
2022};
2023
2024struct ClassDef
2025{
2026 /* Has interface. */
2027 unsigned operator [] (hb_codepoint_t k) const { return get (k); }
2028 bool has (hb_codepoint_t k) const { return (*this)[k]; }
2029 /* Projection. */
2030 hb_codepoint_t operator () (hb_codepoint_t k) const { return get (k); }
2031
2032 unsigned int get (hb_codepoint_t k) const { return get_class (k); }
2033 unsigned int get_class (hb_codepoint_t glyph_id) const
2034 {
2035 switch (u.format.v) {
2036 case 1: hb_barrier (); return u.format1.get_class (glyph_id);
2037 case 2: hb_barrier (); return u.format2.get_class (glyph_id);
2038#ifndef HB_NO_BEYOND_64K
2039 case 3: hb_barrier (); return u.format3.get_class (glyph_id);
2040 case 4: hb_barrier (); return u.format4.get_class (glyph_id);
2041#endif
2042 default:return 0;
2043 }
2044 }
2045 unsigned int get_class (hb_codepoint_t glyph_id,
2046 hb_ot_layout_mapping_cache_t *cache) const
2047 {
2048 unsigned klass;
2049 if (cache && cache->get (glyph_id, &klass)) return klass;
2050 klass = get_class (glyph_id);
2051 if (cache) cache->set (glyph_id, klass);
2052 return klass;
2053 }
2054
2055 unsigned get_population () const
2056 {
2057 switch (u.format.v) {
2058 case 1: hb_barrier (); return u.format1.get_population ();
2059 case 2: hb_barrier (); return u.format2.get_population ();
2060#ifndef HB_NO_BEYOND_64K
2061 case 3: hb_barrier (); return u.format3.get_population ();
2062 case 4: hb_barrier (); return u.format4.get_population ();
2063#endif
2064 default:return NOT_COVERED((unsigned int) -1);
2065 }
2066 }
2067
2068 template<typename Iterator,
2069 hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))typename hb_enable_if<(((hb_is_source_of<Iterator, hb_codepoint_t
>::value && Iterator::is_sorted_iterator)))>::type
* = nullptr
>
2070 bool serialize (hb_serialize_context_t *c, Iterator it_with_class_zero)
2071 {
2072 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
2073 if (unlikely (!c->extend_min (this))__builtin_expect (bool(!c->extend_min (this)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 2073);
2074
2075 auto it = + it_with_class_zero | hb_filter (hb_second);
2076
2077 unsigned format = 2;
2078 hb_codepoint_t glyph_max = 0;
2079 if (likely (it)__builtin_expect (bool(it), 1))
2080 {
2081 hb_codepoint_t glyph_min = (*it).first;
2082 glyph_max = glyph_min;
2083
2084 unsigned num_glyphs = 0;
2085 unsigned num_ranges = 1;
2086 hb_codepoint_t prev_gid = glyph_min;
2087 unsigned prev_klass = (*it).second;
2088
2089 for (const auto gid_klass_pair : it)
2090 {
2091 hb_codepoint_t cur_gid = gid_klass_pair.first;
2092 unsigned cur_klass = gid_klass_pair.second;
2093 num_glyphs++;
2094 if (cur_gid == glyph_min) continue;
2095 if (cur_gid > glyph_max) glyph_max = cur_gid;
2096 if (cur_gid != prev_gid + 1 ||
2097 cur_klass != prev_klass)
2098 num_ranges++;
2099
2100 prev_gid = cur_gid;
2101 prev_klass = cur_klass;
2102 }
2103
2104 if (num_glyphs && 1 + (glyph_max - glyph_min + 1) <= num_ranges * 3)
2105 format = 1;
2106 }
2107
2108#ifndef HB_NO_BEYOND_64K
2109 if (glyph_max > 0xFFFFu)
2110 u.format.v += 2;
2111 if (unlikely (glyph_max > 0xFFFFFFu)__builtin_expect (bool(glyph_max > 0xFFFFFFu), 0))
2112#else
2113 if (unlikely (glyph_max > 0xFFFFu)__builtin_expect (bool(glyph_max > 0xFFFFu), 0))
2114#endif
2115 {
2116 c->check_success (false, HB_SERIALIZE_ERROR_INT_OVERFLOW);
2117 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 2117);
2118 }
2119
2120 u.format.v = format;
2121
2122 switch (u.format.v)
2123 {
2124 case 1: hb_barrier (); return_trace (u.format1.serialize (c, it))return trace.ret (u.format1.serialize (c, it), __PRETTY_FUNCTION__
, 2124)
;
2125 case 2: hb_barrier (); return_trace (u.format2.serialize (c, it))return trace.ret (u.format2.serialize (c, it), __PRETTY_FUNCTION__
, 2125)
;
2126#ifndef HB_NO_BEYOND_64K
2127 case 3: hb_barrier (); return_trace (u.format3.serialize (c, it))return trace.ret (u.format3.serialize (c, it), __PRETTY_FUNCTION__
, 2127)
;
2128 case 4: hb_barrier (); return_trace (u.format4.serialize (c, it))return trace.ret (u.format4.serialize (c, it), __PRETTY_FUNCTION__
, 2128)
;
2129#endif
2130 default:return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 2130);
2131 }
2132 }
2133
2134 bool subset (hb_subset_context_t *c,
2135 hb_map_t *klass_map = nullptr /*OUT*/,
2136 bool keep_empty_table = true,
2137 bool use_class_zero = true,
2138 const Coverage* glyph_filter = nullptr) const
2139 {
2140 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
2141 switch (u.format.v) {
2142 case 1: hb_barrier (); return_trace (u.format1.subset (c, klass_map, keep_empty_table, use_class_zero, glyph_filter))return trace.ret (u.format1.subset (c, klass_map, keep_empty_table
, use_class_zero, glyph_filter), __PRETTY_FUNCTION__, 2142)
;
2143 case 2: hb_barrier (); return_trace (u.format2.subset (c, klass_map, keep_empty_table, use_class_zero, glyph_filter))return trace.ret (u.format2.subset (c, klass_map, keep_empty_table
, use_class_zero, glyph_filter), __PRETTY_FUNCTION__, 2143)
;
2144#ifndef HB_NO_BEYOND_64K
2145 case 3: hb_barrier (); return_trace (u.format3.subset (c, klass_map, keep_empty_table, use_class_zero, glyph_filter))return trace.ret (u.format3.subset (c, klass_map, keep_empty_table
, use_class_zero, glyph_filter), __PRETTY_FUNCTION__, 2145)
;
2146 case 4: hb_barrier (); return_trace (u.format4.subset (c, klass_map, keep_empty_table, use_class_zero, glyph_filter))return trace.ret (u.format4.subset (c, klass_map, keep_empty_table
, use_class_zero, glyph_filter), __PRETTY_FUNCTION__, 2146)
;
2147#endif
2148 default:return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 2148);
2149 }
2150 }
2151
2152 bool sanitize (hb_sanitize_context_t *c) const
2153 {
2154 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
2155 if (!u.format.v.sanitize (c)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 2155);
2156 hb_barrier ();
2157 switch (u.format.v) {
2158 case 1: hb_barrier (); return_trace (u.format1.sanitize (c))return trace.ret (u.format1.sanitize (c), __PRETTY_FUNCTION__
, 2158)
;
2159 case 2: hb_barrier (); return_trace (u.format2.sanitize (c))return trace.ret (u.format2.sanitize (c), __PRETTY_FUNCTION__
, 2159)
;
2160#ifndef HB_NO_BEYOND_64K
2161 case 3: hb_barrier (); return_trace (u.format3.sanitize (c))return trace.ret (u.format3.sanitize (c), __PRETTY_FUNCTION__
, 2161)
;
2162 case 4: hb_barrier (); return_trace (u.format4.sanitize (c))return trace.ret (u.format4.sanitize (c), __PRETTY_FUNCTION__
, 2162)
;
2163#endif
2164 default:return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 2164);
2165 }
2166 }
2167
2168 unsigned cost () const
2169 {
2170 switch (u.format.v) {
2171 case 1: hb_barrier (); return u.format1.cost ();
2172 case 2: hb_barrier (); return u.format2.cost ();
2173#ifndef HB_NO_BEYOND_64K
2174 case 3: hb_barrier (); return u.format3.cost ();
2175 case 4: hb_barrier (); return u.format4.cost ();
2176#endif
2177 default:return 0u;
2178 }
2179 }
2180
2181 /* Might return false if array looks unsorted.
2182 * Used for faster rejection of corrupt data. */
2183 template <typename set_t>
2184 bool collect_coverage (set_t *glyphs) const
2185 {
2186 switch (u.format.v) {
2187 case 1: hb_barrier (); return u.format1.collect_coverage (glyphs);
2188 case 2: hb_barrier (); return u.format2.collect_coverage (glyphs);
2189#ifndef HB_NO_BEYOND_64K
2190 case 3: hb_barrier (); return u.format3.collect_coverage (glyphs);
2191 case 4: hb_barrier (); return u.format4.collect_coverage (glyphs);
2192#endif
2193 default:return false;
2194 }
2195 }
2196
2197 /* Might return false if array looks unsorted.
2198 * Used for faster rejection of corrupt data. */
2199 template <typename set_t>
2200 bool collect_class (set_t *glyphs, unsigned int klass) const
2201 {
2202 switch (u.format.v) {
2203 case 1: hb_barrier (); return u.format1.collect_class (glyphs, klass);
2204 case 2: hb_barrier (); return u.format2.collect_class (glyphs, klass);
2205#ifndef HB_NO_BEYOND_64K
2206 case 3: hb_barrier (); return u.format3.collect_class (glyphs, klass);
2207 case 4: hb_barrier (); return u.format4.collect_class (glyphs, klass);
2208#endif
2209 default:return false;
2210 }
2211 }
2212
2213 bool intersects (const hb_set_t *glyphs) const
2214 {
2215 switch (u.format.v) {
2216 case 1: hb_barrier (); return u.format1.intersects (glyphs);
2217 case 2: hb_barrier (); return u.format2.intersects (glyphs);
2218#ifndef HB_NO_BEYOND_64K
2219 case 3: hb_barrier (); return u.format3.intersects (glyphs);
2220 case 4: hb_barrier (); return u.format4.intersects (glyphs);
2221#endif
2222 default:return false;
2223 }
2224 }
2225 bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const
2226 {
2227 switch (u.format.v) {
2228 case 1: hb_barrier (); return u.format1.intersects_class (glyphs, klass);
2229 case 2: hb_barrier (); return u.format2.intersects_class (glyphs, klass);
2230#ifndef HB_NO_BEYOND_64K
2231 case 3: hb_barrier (); return u.format3.intersects_class (glyphs, klass);
2232 case 4: hb_barrier (); return u.format4.intersects_class (glyphs, klass);
2233#endif
2234 default:return false;
2235 }
2236 }
2237
2238 void intersected_class_glyphs (const hb_set_t *glyphs, unsigned klass, hb_set_t *intersect_glyphs) const
2239 {
2240 switch (u.format.v) {
2241 case 1: hb_barrier (); return u.format1.intersected_class_glyphs (glyphs, klass, intersect_glyphs);
2242 case 2: hb_barrier (); return u.format2.intersected_class_glyphs (glyphs, klass, intersect_glyphs);
2243#ifndef HB_NO_BEYOND_64K
2244 case 3: hb_barrier (); return u.format3.intersected_class_glyphs (glyphs, klass, intersect_glyphs);
2245 case 4: hb_barrier (); return u.format4.intersected_class_glyphs (glyphs, klass, intersect_glyphs);
2246#endif
2247 default:return;
2248 }
2249 }
2250
2251 void intersected_classes (const hb_set_t *glyphs, hb_set_t *intersect_classes) const
2252 {
2253 switch (u.format.v) {
2254 case 1: hb_barrier (); return u.format1.intersected_classes (glyphs, intersect_classes);
2255 case 2: hb_barrier (); return u.format2.intersected_classes (glyphs, intersect_classes);
2256#ifndef HB_NO_BEYOND_64K
2257 case 3: hb_barrier (); return u.format3.intersected_classes (glyphs, intersect_classes);
2258 case 4: hb_barrier (); return u.format4.intersected_classes (glyphs, intersect_classes);
2259#endif
2260 default:return;
2261 }
2262 }
2263
2264
2265 protected:
2266 union {
2267 struct { HBUINT16 v; } format; /* Format identifier */
2268 ClassDefFormat1_3<SmallTypes> format1;
2269 ClassDefFormat2_4<SmallTypes> format2;
2270#ifndef HB_NO_BEYOND_64K
2271 ClassDefFormat1_3<MediumTypes>format3;
2272 ClassDefFormat2_4<MediumTypes>format4;
2273#endif
2274 } u;
2275 public:
2276 DEFINE_SIZE_UNION (2, format.v)void _compiles_assertion_on_line_2276 () const { (void) this->
u.format.v.static_size; } void _instance_assertion_on_line_2276
() const { static_assert ((sizeof(this->u.format.v) == (2
)), ""); } static constexpr unsigned null_size = (2); static constexpr
unsigned min_size = (2)
;
2277};
2278
2279template<typename Iterator>
2280static inline bool ClassDef_serialize (hb_serialize_context_t *c,
2281 Iterator it)
2282{ return (c->start_embed<ClassDef> ()->serialize (c, it)); }
2283
2284
2285/*
2286 * Item Variation Store
2287 */
2288
2289/* ported from fonttools (class _Encoding) */
2290struct delta_row_encoding_t
2291{
2292 /* each byte represents a region, value is one of 0/1/2/4, which means bytes
2293 * needed for this region */
2294 struct chars_t : hb_vector_t<uint8_t>
2295 {
2296 int cmp (const chars_t& other) const
2297 {
2298 return as_array ().cmp (other.as_array ());
2299 }
2300
2301 hb_pair_t<unsigned, unsigned> get_width ()
2302 {
2303 unsigned width = 0;
2304 unsigned columns = 0;
2305 for (unsigned i = 0; i < length; i++)
2306 {
2307 unsigned v = arrayZ[i];
2308 width += v;
2309 columns += (v != 0);
2310 }
2311 return hb_pair (width, columns);
2312 }
2313
2314 HB_HOT__attribute__((hot))
2315 hb_pair_t<unsigned, unsigned> combine_width (const chars_t& other) const
2316 {
2317 unsigned combined_width = 0;
2318 unsigned combined_columns = 0;
2319 for (unsigned i = 0; i < length; i++)
2320 {
2321 unsigned v = hb_max (arrayZ[i], other.arrayZ[i]);
2322 combined_width += v;
2323 combined_columns += (v != 0);
2324 }
2325 return hb_pair (combined_width, combined_columns);
2326 }
2327 };
2328
2329 hb_pair_t<unsigned, unsigned> combine_width (const delta_row_encoding_t& other_encoding) const { return chars.combine_width (other_encoding.chars); }
2330
2331 // Actual data
2332
2333 chars_t chars;
2334 unsigned width = 0;
2335 unsigned overhead = 0;
2336 hb_vector_t<const hb_vector_t<int>*> items;
2337
2338 delta_row_encoding_t () = default;
2339 delta_row_encoding_t (hb_vector_t<const hb_vector_t<int>*> &&rows, unsigned num_cols)
2340 {
2341 assert (rows)(static_cast <bool> (rows) ? void (0) : __assert_fail (
"rows", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2342
2343 items = std::move (rows);
2344
2345 if (unlikely (!chars.resize (num_cols))__builtin_expect (bool(!chars.resize (num_cols)), 0))
2346 return;
2347
2348 calculate_chars ();
2349 }
2350
2351 void merge (const delta_row_encoding_t& other)
2352 {
2353 items.alloc (items.length + other.items.length);
2354 for (auto &row : other.items)
2355 add_row (row);
2356
2357 // Merge chars
2358 assert (chars.length == other.chars.length)(static_cast <bool> (chars.length == other.chars.length
) ? void (0) : __assert_fail ("chars.length == other.chars.length"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2359 for (unsigned i = 0; i < chars.length; i++)
2360 chars.arrayZ[i] = hb_max (chars.arrayZ[i], other.chars.arrayZ[i]);
2361 chars_changed ();
2362 }
2363
2364 void chars_changed ()
2365 {
2366 auto _ = chars.get_width ();
2367 width = _.first;
2368 overhead = get_chars_overhead (_.second);
2369 }
2370
2371 void calculate_chars ()
2372 {
2373 assert (items)(static_cast <bool> (items) ? void (0) : __assert_fail (
"items", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2374
2375 bool long_words = false;
2376
2377 for (auto &row : items)
2378 {
2379 assert (row->length == chars.length)(static_cast <bool> (row->length == chars.length) ? void
(0) : __assert_fail ("row->length == chars.length", __builtin_FILE
(), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__))
;
2380
2381 /* 0/1/2 byte encoding */
2382 for (unsigned i = 0; i < row->length; i++)
2383 {
2384 int v = row->arrayZ[i];
2385 if (v == 0)
2386 continue;
2387 else if (v > 32767 || v < -32768)
2388 {
2389 long_words = true;
2390 chars.arrayZ[i] = hb_max (chars.arrayZ[i], 4);
2391 }
2392 else if (v > 127 || v < -128)
2393 chars.arrayZ[i] = hb_max (chars.arrayZ[i], 2);
2394 else
2395 chars.arrayZ[i] = hb_max (chars.arrayZ[i], 1);
2396 }
2397 }
2398
2399 if (long_words)
2400 {
2401 // Convert 1s to 2s
2402 for (auto &v : chars)
2403 if (v == 1)
2404 v = 2;
2405 }
2406
2407 chars_changed ();
2408 }
2409
2410 bool is_empty () const
2411 { return !items; }
2412
2413 static inline unsigned get_chars_overhead (unsigned num_columns)
2414 {
2415 unsigned c = 4 + 6; // 4 bytes for LOffset, 6 bytes for VarData header
2416 return c + num_columns * 2;
2417 }
2418
2419 unsigned get_gain (unsigned additional_bytes_per_rows = 1) const
2420 {
2421 int count = items.length;
2422 return hb_max (0, (int) overhead - count * (int) additional_bytes_per_rows);
2423 }
2424
2425 int gain_from_merging (const delta_row_encoding_t& other_encoding) const
2426 {
2427 // Back of the envelope calculations to reject early.
2428 signed additional_bytes_per_rows = other_encoding.width - width;
2429 if (additional_bytes_per_rows > 0)
2430 {
2431 if (get_gain (additional_bytes_per_rows) == 0)
2432 return 0;
2433 }
2434 else
2435 {
2436 if (other_encoding.get_gain (-additional_bytes_per_rows) == 0)
2437 return 0;
2438 }
2439
2440 auto pair = combine_width (other_encoding);
2441 unsigned combined_width = pair.first;
2442 unsigned combined_columns = pair.second;
2443
2444 int combined_gain = (int) overhead + (int) other_encoding.overhead;
2445 combined_gain -= (combined_width - (int) width) * items.length;
2446 combined_gain -= (combined_width - (int) other_encoding.width) * other_encoding.items.length;
2447 combined_gain -= get_chars_overhead (combined_columns);
2448
2449 return combined_gain;
2450 }
2451
2452 bool add_row (const hb_vector_t<int>* row)
2453 { return items.push (row); }
2454
2455 static int cmp (const void *pa, const void *pb)
2456 {
2457 const delta_row_encoding_t *a = (const delta_row_encoding_t *)pa;
2458 const delta_row_encoding_t *b = (const delta_row_encoding_t *)pb;
2459
2460 if (a->width != b->width)
2461 return (int) a->width - (int) b->width;
2462
2463 return b->chars.cmp (a->chars);
2464 }
2465};
2466
2467struct VarRegionAxis
2468{
2469 float evaluate (int coord) const
2470 {
2471 int peak = peakCoord.to_int ();
2472 if (peak == 0 || coord == peak)
2473 return 1.f;
2474 else if (coord == 0) // Faster
2475 return 0.f;
2476
2477 int start = startCoord.to_int (), end = endCoord.to_int ();
2478
2479 /* TODO Move these to sanitize(). */
2480 if (unlikely (start > peak || peak > end)__builtin_expect (bool(start > peak || peak > end), 0))
2481 return 1.f;
2482 if (unlikely (start < 0 && end > 0)__builtin_expect (bool(start < 0 && end > 0), 0
)
)
2483 return 1.f;
2484
2485 if (coord <= start || end <= coord)
2486 return 0.f;
2487
2488 /* Interpolate */
2489 if (coord < peak)
2490 return float (coord - start) / (peak - start);
2491 else
2492 return float (end - coord) / (end - peak);
2493 }
2494
2495 bool sanitize (hb_sanitize_context_t *c) const
2496 {
2497 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
2498 return_trace (c->check_struct (this))return trace.ret (c->check_struct (this), __PRETTY_FUNCTION__
, 2498)
;
2499 }
2500
2501 bool serialize (hb_serialize_context_t *c) const
2502 {
2503 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
2504 return_trace (c->embed (this))return trace.ret (c->embed (this), __PRETTY_FUNCTION__, 2504
)
;
2505 }
2506
2507 public:
2508 F2DOT14 startCoord;
2509 F2DOT14 peakCoord;
2510 F2DOT14 endCoord;
2511 public:
2512 DEFINE_SIZE_STATIC (6)void _instance_assertion_on_line_2512 () const { static_assert
((sizeof (*this) == (6)), ""); } size_t get_size () const { return
(6); } static constexpr unsigned null_size = (6); static constexpr
unsigned min_size = (6); static constexpr unsigned static_size
= (6)
;
2513};
2514struct SparseVarRegionAxis
2515{
2516 float evaluate (const int *coords, unsigned int coord_len) const
2517 {
2518 unsigned i = axisIndex;
2519 int coord = i < coord_len ? coords[i] : 0;
2520 return axis.evaluate (coord);
2521 }
2522
2523 bool sanitize (hb_sanitize_context_t *c) const
2524 {
2525 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
2526 return_trace (c->check_struct (this))return trace.ret (c->check_struct (this), __PRETTY_FUNCTION__
, 2526)
;
2527 }
2528
2529 bool serialize (hb_serialize_context_t *c) const
2530 {
2531 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
2532 return_trace (c->embed (this))return trace.ret (c->embed (this), __PRETTY_FUNCTION__, 2532
)
;
2533 }
2534
2535 public:
2536 HBUINT16 axisIndex;
2537 VarRegionAxis axis;
2538 public:
2539 DEFINE_SIZE_STATIC (8)void _instance_assertion_on_line_2539 () const { static_assert
((sizeof (*this) == (8)), ""); } size_t get_size () const { return
(8); } static constexpr unsigned null_size = (8); static constexpr
unsigned min_size = (8); static constexpr unsigned static_size
= (8)
;
2540};
2541
2542struct hb_scalar_cache_t
2543{
2544 private:
2545 static constexpr unsigned STATIC_LENGTH = 128;
2546 static constexpr int INVALID = INT_MIN(-2147483647 -1);
2547 static constexpr float MULTIPLIER = 1 << ((sizeof (int) * 8) - 2);
2548 static constexpr float DIVISOR = 1.f / MULTIPLIER;
2549
2550 public:
2551 hb_scalar_cache_t () {}
2552
2553 hb_scalar_cache_t (const hb_scalar_cache_t&) = delete;
2554 hb_scalar_cache_t (hb_scalar_cache_t&&) = delete;
2555 hb_scalar_cache_t& operator= (const hb_scalar_cache_t&) = delete;
2556 hb_scalar_cache_t& operator= (hb_scalar_cache_t&&) = delete;
2557
2558 static hb_scalar_cache_t *create (unsigned int count,
2559 hb_scalar_cache_t *scratch_cache = nullptr)
2560 {
2561 if (!count) return (hb_scalar_cache_t *) &Null(hb_scalar_cache_t)NullHelper<hb_scalar_cache_t>::get_null ();
2562
2563 if (scratch_cache && count <= STATIC_LENGTH)
2564 {
2565 scratch_cache->length = count;
2566 scratch_cache->clear ();
2567 return scratch_cache;
2568 }
2569
2570 auto *cache = (hb_scalar_cache_t *) hb_malloc (sizeof (hb_scalar_cache_t) - sizeof (static_values) + sizeof (static_values[0]) * count);
2571 if (unlikely (!cache)__builtin_expect (bool(!cache), 0)) return (hb_scalar_cache_t *) &Null(hb_scalar_cache_t)NullHelper<hb_scalar_cache_t>::get_null ();
2572
2573 cache->length = count;
2574 cache->clear ();
2575
2576 return cache;
2577 }
2578
2579 static void destroy (hb_scalar_cache_t *cache,
2580 hb_scalar_cache_t *scratch_cache = nullptr)
2581 {
2582 if (cache != &Null(hb_scalar_cache_t)NullHelper<hb_scalar_cache_t>::get_null () && cache != scratch_cache)
2583 hb_free (cache);
2584 }
2585
2586 void clear ()
2587 {
2588 auto *values = &static_values[0];
2589 unsigned i = 0;
2590#ifndef HB_OPTIMIZE_SIZE
2591 for (; i + 3 < length; i += 4)
2592 {
2593 values[i + 0] = INVALID;
2594 values[i + 1] = INVALID;
2595 values[i + 2] = INVALID;
2596 values[i + 3] = INVALID;
2597 }
2598#endif
2599 for (; i < length; i++)
2600 values[i] = INVALID;
2601 }
2602
2603 HB_ALWAYS_INLINE__attribute__((always_inline)) inline
2604 bool get (unsigned i, float *value) const
2605 {
2606 if (unlikely (i >= length)__builtin_expect (bool(i >= length), 0))
2607 {
2608 *value = 0.f;
2609 return true;
2610 }
2611 auto *values = &static_values[0];
2612 auto *cached_value = &values[i];
2613 // Super hot. Most common path is that we have a cached value of 0.
2614 int v = *cached_value;
2615 if (likely (!v)__builtin_expect (bool(!v), 1))
2616 {
2617 *value = 0.f;
2618 return true;
2619 }
2620 if (v == INVALID)
2621 return false;
2622 *value = v * DIVISOR;
2623 return true;
2624 }
2625
2626 HB_ALWAYS_INLINE__attribute__((always_inline)) inline
2627 void set (unsigned i, float value)
2628 {
2629 if (unlikely (i >= length)__builtin_expect (bool(i >= length), 0)) return;
2630 auto *values = &static_values[0];
2631 auto *cached_value = &values[i];
2632 *cached_value = roundf(value * MULTIPLIER)_hb_roundf(value * MULTIPLIER);
2633 }
2634
2635 public:
2636 unsigned length;
2637 private:
2638 mutable hb_atomic_t<int> static_values[STATIC_LENGTH];
2639};
2640
2641struct VarRegionList
2642{
2643 private:
2644 float evaluate_impl (unsigned int region_index,
2645 const int *coords, unsigned int coord_len) const
2646 {
2647 const VarRegionAxis *axes = axesZ.arrayZ + (region_index * axisCount);
2648 float v = 1.f;
2649
2650 unsigned int count = axisCount;
2651 for (unsigned int i = 0; i < count; i++)
2652 {
2653 int coord = i < coord_len ? coords[i] : 0;
2654 float factor = axes[i].evaluate (coord);
2655 if (factor == 0.f)
2656 {
2657 v = 0.f;
2658 break;
2659 }
2660 v *= factor;
2661 }
2662
2663 return v;
2664 }
2665
2666 public:
2667 HB_ALWAYS_INLINE__attribute__((always_inline)) inline
2668 float evaluate (unsigned int region_index,
2669 const int *coords, unsigned int coord_len,
2670 hb_scalar_cache_t *cache = nullptr) const
2671 {
2672 if (unlikely (region_index >= regionCount)__builtin_expect (bool(region_index >= regionCount), 0))
2673 return 0.;
2674
2675 float v;
2676 if (cache && cache->get (region_index, &v))
2677 return v;
2678
2679 v = evaluate_impl (region_index, coords, coord_len);
2680
2681 if (cache)
2682 cache->set (region_index, v);
2683 return v;
2684 }
2685
2686 bool sanitize (hb_sanitize_context_t *c) const
2687 {
2688 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
2689 return_trace (c->check_struct (this) &&return trace.ret (c->check_struct (this) && hb_barrier
() && axesZ.sanitize (c, axisCount * regionCount), __PRETTY_FUNCTION__
, 2691)
2690 hb_barrier () &&return trace.ret (c->check_struct (this) && hb_barrier
() && axesZ.sanitize (c, axisCount * regionCount), __PRETTY_FUNCTION__
, 2691)
2691 axesZ.sanitize (c, axisCount * regionCount))return trace.ret (c->check_struct (this) && hb_barrier
() && axesZ.sanitize (c, axisCount * regionCount), __PRETTY_FUNCTION__
, 2691)
;
2692 }
2693
2694 bool serialize (hb_serialize_context_t *c,
2695 const hb_vector_t<hb_tag_t>& axis_tags,
2696 const hb_vector_t<const hb_hashmap_t<hb_tag_t, Triple>*>& regions)
2697 {
2698 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
2699 unsigned axis_count = axis_tags.length;
2700 unsigned region_count = regions.length;
2701 if (!axis_count || !region_count) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 2701);
2702 if (unlikely (hb_unsigned_mul_overflows (axis_count * region_count,__builtin_expect (bool(hb_unsigned_mul_overflows (axis_count *
region_count, VarRegionAxis::static_size)), 0)
2703 VarRegionAxis::static_size))__builtin_expect (bool(hb_unsigned_mul_overflows (axis_count *
region_count, VarRegionAxis::static_size)), 0)
) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 2703);
2704 if (unlikely (!c->extend_min (this))__builtin_expect (bool(!c->extend_min (this)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 2704);
2705 axisCount = axis_count;
2706 regionCount = region_count;
2707
2708 for (unsigned r = 0; r < region_count; r++)
2709 {
2710 const auto& region = regions[r];
2711 for (unsigned i = 0; i < axis_count; i++)
2712 {
2713 hb_tag_t tag = axis_tags.arrayZ[i];
2714 VarRegionAxis var_region_rec;
2715 Triple *coords;
2716 if (region->has (tag, &coords))
2717 {
2718 var_region_rec.startCoord.set_float (coords->minimum);
2719 var_region_rec.peakCoord.set_float (coords->middle);
2720 var_region_rec.endCoord.set_float (coords->maximum);
2721 }
2722 else
2723 {
2724 var_region_rec.startCoord.set_int (0);
2725 var_region_rec.peakCoord.set_int (0);
2726 var_region_rec.endCoord.set_int (0);
2727 }
2728 if (!var_region_rec.serialize (c))
2729 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 2729);
2730 }
2731 }
2732 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 2732);
2733 }
2734
2735 bool serialize (hb_serialize_context_t *c, const VarRegionList *src, const hb_inc_bimap_t &region_map)
2736 {
2737 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
2738 if (unlikely (!c->extend_min (this))__builtin_expect (bool(!c->extend_min (this)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 2738);
2739 axisCount = src->axisCount;
2740 regionCount = region_map.get_population ();
2741 if (unlikely (hb_unsigned_mul_overflows (axisCount * regionCount,__builtin_expect (bool(hb_unsigned_mul_overflows (axisCount *
regionCount, VarRegionAxis::static_size)), 0)
2742 VarRegionAxis::static_size))__builtin_expect (bool(hb_unsigned_mul_overflows (axisCount *
regionCount, VarRegionAxis::static_size)), 0)
) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 2742);
2743 if (unlikely (!c->extend (this))__builtin_expect (bool(!c->extend (this)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 2743);
2744 unsigned int region_count = src->regionCount;
2745 for (unsigned int r = 0; r < regionCount; r++)
2746 {
2747 unsigned int backward = region_map.backward (r);
2748 if (backward >= region_count) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 2748);
2749 hb_memcpy (&axesZ[axisCount * r], &src->axesZ[axisCount * backward], VarRegionAxis::static_size * axisCount);
2750 }
2751
2752 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 2752);
2753 }
2754
2755 bool get_var_region (unsigned region_index,
2756 const hb_map_t& axes_old_index_tag_map,
2757 hb_hashmap_t<hb_tag_t, Triple>& axis_tuples /* OUT */) const
2758 {
2759 if (region_index >= regionCount) return false;
2760 const VarRegionAxis* axis_region = axesZ.arrayZ + (region_index * axisCount);
2761 for (unsigned i = 0; i < axisCount; i++)
2762 {
2763 hb_tag_t *axis_tag;
2764 if (!axes_old_index_tag_map.has (i, &axis_tag))
2765 return false;
2766
2767 float min_val = axis_region->startCoord.to_float ();
2768 float def_val = axis_region->peakCoord.to_float ();
2769 float max_val = axis_region->endCoord.to_float ();
2770
2771 if (def_val != 0.f)
2772 axis_tuples.set (*axis_tag, Triple ((double) min_val, (double) def_val, (double) max_val));
2773 axis_region++;
2774 }
2775 return !axis_tuples.in_error ();
2776 }
2777
2778 bool get_var_regions (const hb_map_t& axes_old_index_tag_map,
2779 hb_vector_t<hb_hashmap_t<hb_tag_t, Triple>>& regions /* OUT */) const
2780 {
2781 if (!regions.alloc (regionCount))
2782 return false;
2783
2784 for (unsigned i = 0; i < regionCount; i++)
2785 {
2786 hb_hashmap_t<hb_tag_t, Triple> axis_tuples;
2787 if (!get_var_region (i, axes_old_index_tag_map, axis_tuples))
2788 return false;
2789 regions.push (std::move (axis_tuples));
2790 }
2791 return !regions.in_error ();
2792 }
2793
2794 size_t get_size () const
2795 { return hb_unsigned_add_saturate (min_size,
2796 hb_unsigned_mul_saturate (VarRegionAxis::static_size,
2797 axisCount, regionCount)); }
2798
2799 public:
2800 HBUINT16 axisCount;
2801 HBUINT15 regionCount;
2802 protected:
2803 UnsizedArrayOf<VarRegionAxis>
2804 axesZ;
2805 public:
2806 DEFINE_SIZE_ARRAY (4, axesZ)void _compiles_assertion_on_line_2806 () const { (void) (axesZ
)[0].static_size; } void _instance_assertion_on_line_2806 () const
{ static_assert ((sizeof (*this) == (4) + (1 +0) * sizeof ((
axesZ)[0])), ""); } static constexpr unsigned null_size = (4)
; static constexpr unsigned min_size = (4)
;
2807};
2808
2809/* Whether a variation region is unreachable given per-axis reachable
2810 * final-coordinate ranges, in F2Dot14 units (avar2 partial-instancing
2811 * culling; see hb_subset_plan_t::avar2_reachable_ranges). A region is dead
2812 * if some axis's tent evaluates to zero over the axis's entire reachable
2813 * range. Mirrors the runtime evaluation: invalid tents evaluate as
2814 * constant 1 and never kill a region. */
2815static inline bool
2816_hb_avar2_region_is_dead (const hb_hashmap_t<hb_tag_t, Triple> &axis_tuples,
2817 const hb_hashmap_t<hb_tag_t, Triple> &reachable_ranges)
2818{
2819 for (auto _ : axis_tuples)
2820 {
2821 Triple *range;
2822 if (!reachable_ranges.has (_.first, &range)) continue;
2823 const Triple &tent = _.second;
2824 int start = (int) roundf ((float) tent.minimum * 16384.f)_hb_roundf((float) tent.minimum * 16384.f);
2825 int peak = (int) roundf ((float) tent.middle * 16384.f)_hb_roundf((float) tent.middle * 16384.f);
2826 int end = (int) roundf ((float) tent.maximum * 16384.f)_hb_roundf((float) tent.maximum * 16384.f);
2827 if (!peak) continue;
2828 if (start > peak || peak > end) continue;
2829 if (start < 0 && end > 0) continue;
2830 int lo = (int) roundf ((float) range->minimum * 16384.f)_hb_roundf((float) range->minimum * 16384.f);
2831 int hi = (int) roundf ((float) range->maximum * 16384.f)_hb_roundf((float) range->maximum * 16384.f);
2832 /* Strict comparisons: the scalar is 1 (not 0) at v == peak, so a tent
2833 * whose peak sits exactly on the range boundary is still live there.
2834 * (Reachable ranges are padded by one F2Dot14 unit at their producer,
2835 * which already covers this; strictness keeps the predicate correct on
2836 * its own terms.) */
2837 if (hi < start || lo > end)
2838 return true;
2839 }
2840 return false;
2841}
2842
2843struct SparseVariationRegion : Array16Of<SparseVarRegionAxis>
2844{
2845 float evaluate (const int *coords, unsigned int coord_len) const
2846 {
2847 float v = 1.f;
2848 unsigned int count = len;
2849 for (unsigned int i = 0; i < count; i++)
2850 {
2851 float factor = arrayZ[i].evaluate (coords, coord_len);
2852 if (factor == 0.f)
2853 return 0.;
2854 v *= factor;
2855 }
2856 return v;
2857 }
2858};
2859
2860struct SparseVarRegionList
2861{
2862 HB_ALWAYS_INLINE__attribute__((always_inline)) inline
2863 float evaluate (unsigned int region_index,
2864 const int *coords, unsigned int coord_len,
2865 hb_scalar_cache_t *cache = nullptr) const
2866 {
2867 if (unlikely (region_index >= regions.len)__builtin_expect (bool(region_index >= regions.len), 0))
2868 return 0.;
2869
2870 float v;
2871 if (cache && cache->get (region_index, &v))
2872 return v;
2873
2874 const SparseVariationRegion &region = this+regions[region_index];
2875
2876 v = region.evaluate (coords, coord_len);
2877 if (cache)
2878 cache->set (region_index, v);
2879
2880 return v;
2881 }
2882
2883 bool sanitize (hb_sanitize_context_t *c) const
2884 {
2885 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
2886 return_trace (regions.sanitize (c, this))return trace.ret (regions.sanitize (c, this), __PRETTY_FUNCTION__
, 2886)
;
2887 }
2888
2889 public:
2890 Array16Of<Offset32To<SparseVariationRegion>>
2891 regions;
2892 public:
2893 DEFINE_SIZE_ARRAY (2, regions)void _compiles_assertion_on_line_2893 () const { (void) (regions
)[0].static_size; } void _instance_assertion_on_line_2893 () const
{ static_assert ((sizeof (*this) == (2) + (1 +0) * sizeof ((
regions)[0])), ""); } static constexpr unsigned null_size = (
2); static constexpr unsigned min_size = (2)
;
2894};
2895
2896
2897struct VarData
2898{
2899 unsigned int get_item_count () const
2900 { return itemCount; }
2901
2902 unsigned int get_region_index_count () const
2903 { return regionIndices.len; }
2904
2905 unsigned get_region_index (unsigned i) const
2906 { return i >= regionIndices.len ? -1 : regionIndices[i]; }
2907
2908 size_t get_row_size () const
2909 { return (wordCount () + regionIndices.len) * (longWords () ? 2 : 1); }
2910
2911 size_t get_size () const
2912 { return hb_unsigned_add_saturate (min_size - regionIndices.min_size,
2913 regionIndices.get_size (),
2914 hb_unsigned_mul_saturate (itemCount, get_row_size ())); }
2915
2916 float _get_delta (unsigned int inner,
2917 const int *coords, unsigned int coord_count,
2918 const VarRegionList &regions,
2919 hb_scalar_cache_t *cache = nullptr) const
2920 {
2921 if (unlikely (inner >= itemCount)__builtin_expect (bool(inner >= itemCount), 0))
2922 return 0.;
2923 bool is_long = longWords ();
2924 unsigned int count = regionIndices.len;
2925 unsigned word_count = wordCount ();
2926 unsigned int scount = is_long ? count : word_count;
2927 unsigned int lcount = is_long ? word_count : 0;
2928
2929 const HBUINT8 *bytes = get_delta_bytes ();
2930 const HBUINT8 *row = bytes + inner * get_row_size ();
2931
2932 float delta = 0.;
2933 unsigned int i = 0;
2934
2935 const HBINT32 *lcursor = reinterpret_cast<const HBINT32 *> (row);
2936 for (; i < lcount; i++)
2937 {
2938 float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count, cache);
2939 if (scalar)
2940 delta += scalar * *lcursor;
2941 lcursor++;
2942 }
2943 const HBINT16 *scursor = reinterpret_cast<const HBINT16 *> (lcursor);
2944 for (; i < scount; i++)
2945 {
2946 float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count, cache);
2947 if (scalar)
2948 delta += scalar * *scursor;
2949 scursor++;
2950 }
2951 const HBINT8 *bcursor = reinterpret_cast<const HBINT8 *> (scursor);
2952 for (; i < count; i++)
2953 {
2954 float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count, cache);
2955 if (scalar)
2956 delta += scalar * *bcursor;
2957 bcursor++;
2958 }
2959
2960 return delta;
2961 }
2962
2963 HB_ALWAYS_INLINE__attribute__((always_inline)) inline
2964 float get_delta (unsigned int inner,
2965 const int *coords, unsigned int coord_count,
2966 const VarRegionList &regions,
2967 hb_scalar_cache_t *cache = nullptr) const
2968 {
2969 unsigned int count = regionIndices.len;
2970 if (!count) return 0.f; // This is quite common, so optimize it.
2971 return _get_delta (inner, coords, coord_count, regions, cache);
2972 }
2973
2974 void get_region_scalars (const int *coords, unsigned int coord_count,
2975 const VarRegionList &regions,
2976 float *scalars /*OUT */,
2977 unsigned int num_scalars) const
2978 {
2979 unsigned count = hb_min (num_scalars, regionIndices.len);
2980 for (unsigned int i = 0; i < count; i++)
2981 scalars[i] = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count);
2982 for (unsigned int i = count; i < num_scalars; i++)
2983 scalars[i] = 0.f;
2984 }
2985
2986 bool sanitize (hb_sanitize_context_t *c) const
2987 {
2988 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
2989 return_trace (c->check_struct (this) &&return trace.ret (c->check_struct (this) && regionIndices
.sanitize (c) && hb_barrier () && wordCount (
) <= regionIndices.len && c->check_range (get_delta_bytes
(), itemCount, get_row_size ()), __PRETTY_FUNCTION__, 2995)
2990 regionIndices.sanitize (c) &&return trace.ret (c->check_struct (this) && regionIndices
.sanitize (c) && hb_barrier () && wordCount (
) <= regionIndices.len && c->check_range (get_delta_bytes
(), itemCount, get_row_size ()), __PRETTY_FUNCTION__, 2995)
2991 hb_barrier () &&return trace.ret (c->check_struct (this) && regionIndices
.sanitize (c) && hb_barrier () && wordCount (
) <= regionIndices.len && c->check_range (get_delta_bytes
(), itemCount, get_row_size ()), __PRETTY_FUNCTION__, 2995)
2992 wordCount () <= regionIndices.len &&return trace.ret (c->check_struct (this) && regionIndices
.sanitize (c) && hb_barrier () && wordCount (
) <= regionIndices.len && c->check_range (get_delta_bytes
(), itemCount, get_row_size ()), __PRETTY_FUNCTION__, 2995)
2993 c->check_range (get_delta_bytes (),return trace.ret (c->check_struct (this) && regionIndices
.sanitize (c) && hb_barrier () && wordCount (
) <= regionIndices.len && c->check_range (get_delta_bytes
(), itemCount, get_row_size ()), __PRETTY_FUNCTION__, 2995)
2994 itemCount,return trace.ret (c->check_struct (this) && regionIndices
.sanitize (c) && hb_barrier () && wordCount (
) <= regionIndices.len && c->check_range (get_delta_bytes
(), itemCount, get_row_size ()), __PRETTY_FUNCTION__, 2995)
2995 get_row_size ()))return trace.ret (c->check_struct (this) && regionIndices
.sanitize (c) && hb_barrier () && wordCount (
) <= regionIndices.len && c->check_range (get_delta_bytes
(), itemCount, get_row_size ()), __PRETTY_FUNCTION__, 2995)
;
2996 }
2997
2998 bool serialize (hb_serialize_context_t *c,
2999 bool has_long,
3000 const hb_vector_t<const hb_vector_t<int>*>& rows)
3001 {
3002 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
3003 unsigned row_count = rows.length;
3004 if (!row_count) {
3005 // Nothing to serialize, will be empty.
3006 return false;
3007 }
3008
3009 if (unlikely (!c->extend_min (this))__builtin_expect (bool(!c->extend_min (this)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3009);
3010 if (unlikely (!c->check_assign (itemCount, row_count,__builtin_expect (bool(!c->check_assign (itemCount, row_count
, HB_SERIALIZE_ERROR_INT_OVERFLOW)), 0)
3011 HB_SERIALIZE_ERROR_INT_OVERFLOW))__builtin_expect (bool(!c->check_assign (itemCount, row_count
, HB_SERIALIZE_ERROR_INT_OVERFLOW)), 0)
)
3012 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3012);
3013
3014 int min_threshold = has_long ? -65536 : -128;
3015 int max_threshold = has_long ? +65535 : +127;
3016 enum delta_size_t { kZero=0, kNonWord, kWord };
3017 hb_vector_t<delta_size_t> delta_sz;
3018 unsigned num_regions = rows[0]->length;
3019 if (!delta_sz.resize (num_regions))
3020 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3020);
3021
3022 unsigned word_count = 0;
3023 for (unsigned r = 0; r < num_regions; r++)
3024 {
3025 for (unsigned i = 0; i < row_count; i++)
3026 {
3027 int delta = rows[i]->arrayZ[r];
3028 if (delta < min_threshold || delta > max_threshold)
3029 {
3030 delta_sz[r] = kWord;
3031 word_count++;
3032 break;
3033 }
3034 else if (delta != 0)
3035 {
3036 delta_sz[r] = kNonWord;
3037 }
3038 }
3039 }
3040
3041 /* reorder regions: words and then non-words*/
3042 unsigned word_index = 0;
3043 unsigned non_word_index = word_count;
3044 hb_map_t ri_map;
3045 for (unsigned r = 0; r < num_regions; r++)
3046 {
3047 if (!delta_sz[r]) continue;
3048 unsigned new_r = (delta_sz[r] == kWord)? word_index++ : non_word_index++;
3049 if (!ri_map.set (new_r, r))
3050 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3050);
3051 }
3052
3053 wordSizeCount = word_count | (has_long ? 0x8000u /* LONG_WORDS */ : 0);
3054
3055 unsigned ri_count = ri_map.get_population ();
3056 regionIndices.len = ri_count;
3057 if (unlikely (!c->extend (this))__builtin_expect (bool(!c->extend (this)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3057);
3058
3059 for (unsigned r = 0; r < ri_count; r++)
3060 {
3061 hb_codepoint_t *idx;
3062 if (!ri_map.has (r, &idx))
3063 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3063);
3064 regionIndices[r] = *idx;
3065 }
3066
3067 HBUINT8 *delta_bytes = get_delta_bytes ();
3068 unsigned row_size = get_row_size ();
3069 for (unsigned int i = 0; i < row_count; i++)
3070 {
3071 for (unsigned int r = 0; r < ri_count; r++)
3072 {
3073 int delta = rows[i]->arrayZ[ri_map[r]];
3074 set_item_delta_fast (i, r, delta, delta_bytes, row_size);
3075 }
3076 }
3077 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 3077);
3078 }
3079
3080 bool serialize (hb_serialize_context_t *c,
3081 const VarData *src,
3082 const hb_inc_bimap_t &inner_map,
3083 const hb_inc_bimap_t &region_map,
3084 const hb_set_t *culled_regions = nullptr)
3085 {
3086 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
3087 if (unlikely (!c->extend_min (this))__builtin_expect (bool(!c->extend_min (this)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3087);
3088 itemCount = inner_map.get_next_value ();
3089
3090 /* Optimize word count */
3091 unsigned ri_count = src->regionIndices.len;
3092 enum delta_size_t { kZero=0, kNonWord, kWord };
3093 hb_vector_t<delta_size_t> delta_sz;
3094 hb_vector_t<unsigned int> ri_map; /* maps new index to old index */
3095 delta_sz.resize (ri_count);
3096 ri_map.resize (ri_count);
3097 unsigned int new_word_count = 0;
3098 unsigned int r;
3099
3100 const HBUINT8 *src_delta_bytes = src->get_delta_bytes ();
3101 unsigned src_row_size = src->get_row_size ();
3102 unsigned src_word_count = src->wordCount ();
3103 bool src_long_words = src->longWords ();
3104
3105 bool has_long = false;
3106 if (src_long_words)
3107 {
3108 for (r = 0; r < src_word_count; r++)
3109 {
3110 for (unsigned old_gid : inner_map.keys())
3111 {
3112 int32_t delta = src->get_item_delta_fast (old_gid, r, src_delta_bytes, src_row_size);
3113 if (delta < -65536 || 65535 < delta)
3114 {
3115 has_long = true;
3116 break;
3117 }
3118 }
3119 }
3120 }
3121
3122 signed min_threshold = has_long ? -65536 : -128;
3123 signed max_threshold = has_long ? +65535 : +127;
3124 for (r = 0; r < ri_count; r++)
3125 {
3126 bool short_circuit = src_long_words == has_long && src_word_count <= r;
3127
3128 delta_sz[r] = kZero;
3129 if (culled_regions && culled_regions->has (src->regionIndices[r]))
3130 continue; /* unreachable region: drop its column */
3131 for (unsigned old_gid : inner_map.keys())
3132 {
3133 int32_t delta = src->get_item_delta_fast (old_gid, r, src_delta_bytes, src_row_size);
3134 if (delta < min_threshold || max_threshold < delta)
3135 {
3136 delta_sz[r] = kWord;
3137 new_word_count++;
3138 break;
3139 }
3140 else if (delta != 0)
3141 {
3142 delta_sz[r] = kNonWord;
3143 if (short_circuit)
3144 break;
3145 }
3146 }
3147 }
3148
3149 unsigned int word_index = 0;
3150 unsigned int non_word_index = new_word_count;
3151 unsigned int new_ri_count = 0;
3152 for (r = 0; r < ri_count; r++)
3153 if (delta_sz[r])
3154 {
3155 unsigned new_r = (delta_sz[r] == kWord)? word_index++ : non_word_index++;
3156 ri_map[new_r] = r;
3157 new_ri_count++;
3158 }
3159
3160 wordSizeCount = new_word_count | (has_long ? 0x8000u /* LONG_WORDS */ : 0);
3161
3162 regionIndices.len = new_ri_count;
3163
3164 if (unlikely (!c->extend (this))__builtin_expect (bool(!c->extend (this)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3164);
3165
3166 for (r = 0; r < new_ri_count; r++)
3167 regionIndices[r] = region_map[src->regionIndices[ri_map[r]]];
3168
3169 HBUINT8 *delta_bytes = get_delta_bytes ();
3170 unsigned row_size = get_row_size ();
3171 unsigned count = itemCount;
3172 for (unsigned int i = 0; i < count; i++)
3173 {
3174 unsigned int old = inner_map.backward (i);
3175 for (unsigned int r = 0; r < new_ri_count; r++)
3176 set_item_delta_fast (i, r,
3177 src->get_item_delta_fast (old, ri_map[r],
3178 src_delta_bytes, src_row_size),
3179 delta_bytes, row_size);
3180 }
3181
3182 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 3182);
3183 }
3184
3185 void collect_region_refs (hb_set_t &region_indices, const hb_inc_bimap_t &inner_map) const
3186 {
3187 const HBUINT8 *delta_bytes = get_delta_bytes ();
3188 unsigned row_size = get_row_size ();
3189
3190 for (unsigned int r = 0; r < regionIndices.len; r++)
3191 {
3192 unsigned int region = regionIndices.arrayZ[r];
3193 if (region_indices.has (region)) continue;
3194 for (hb_codepoint_t old_gid : inner_map.keys())
3195 if (get_item_delta_fast (old_gid, r, delta_bytes, row_size) != 0)
3196 {
3197 region_indices.add (region);
3198 break;
3199 }
3200 }
3201 }
3202
3203 public:
3204 const HBUINT8 *get_delta_bytes () const
3205 { return &StructAfter<HBUINT8> (regionIndices); }
3206
3207 protected:
3208 HBUINT8 *get_delta_bytes ()
3209 { return &StructAfter<HBUINT8> (regionIndices); }
3210
3211 public:
3212 int32_t get_item_delta_fast (unsigned int item, unsigned int region,
3213 const HBUINT8 *delta_bytes, unsigned row_size) const
3214 {
3215 if (unlikely (item >= itemCount || region >= regionIndices.len)__builtin_expect (bool(item >= itemCount || region >= regionIndices
.len), 0)
) return 0;
3216
3217 const HBINT8 *p = (const HBINT8 *) delta_bytes + item * row_size;
3218 unsigned word_count = wordCount ();
3219 bool is_long = longWords ();
3220 if (is_long)
3221 {
3222 if (region < word_count)
3223 return ((const HBINT32 *) p)[region];
3224 else
3225 return ((const HBINT16 *)(p + HBINT32::static_size * word_count))[region - word_count];
3226 }
3227 else
3228 {
3229 if (region < word_count)
3230 return ((const HBINT16 *) p)[region];
3231 else
3232 return (p + HBINT16::static_size * word_count)[region - word_count];
3233 }
3234 }
3235 int32_t get_item_delta (unsigned int item, unsigned int region) const
3236 {
3237 return get_item_delta_fast (item, region,
3238 get_delta_bytes (),
3239 get_row_size ());
3240 }
3241
3242 protected:
3243 void set_item_delta_fast (unsigned int item, unsigned int region, int32_t delta,
3244 HBUINT8 *delta_bytes, unsigned row_size)
3245 {
3246 HBINT8 *p = (HBINT8 *) delta_bytes + item * row_size;
3247 unsigned word_count = wordCount ();
3248 bool is_long = longWords ();
3249 if (is_long)
3250 {
3251 if (region < word_count)
3252 ((HBINT32 *) p)[region] = delta;
3253 else
3254 ((HBINT16 *)(p + HBINT32::static_size * word_count))[region - word_count] = delta;
3255 }
3256 else
3257 {
3258 if (region < word_count)
3259 ((HBINT16 *) p)[region] = delta;
3260 else
3261 (p + HBINT16::static_size * word_count)[region - word_count] = delta;
3262 }
3263 }
3264 void set_item_delta (unsigned int item, unsigned int region, int32_t delta)
3265 {
3266 set_item_delta_fast (item, region, delta,
3267 get_delta_bytes (),
3268 get_row_size ());
3269 }
3270
3271 bool longWords () const { return wordSizeCount & 0x8000u /* LONG_WORDS */; }
3272 unsigned wordCount () const { return wordSizeCount & 0x7FFFu /* WORD_DELTA_COUNT_MASK */; }
3273
3274 protected:
3275 HBUINT16 itemCount;
3276 HBUINT16 wordSizeCount;
3277 Array16Of<HBUINT16> regionIndices;
3278/*UnsizedArrayOf<HBUINT8>bytesX;*/
3279 public:
3280 DEFINE_SIZE_ARRAY (6, regionIndices)void _compiles_assertion_on_line_3280 () const { (void) (regionIndices
)[0].static_size; } void _instance_assertion_on_line_3280 () const
{ static_assert ((sizeof (*this) == (6) + (1 +0) * sizeof ((
regionIndices)[0])), ""); } static constexpr unsigned null_size
= (6); static constexpr unsigned min_size = (6)
;
3281};
3282
3283struct MultiVarData
3284{
3285 size_t get_size () const
3286 { return hb_unsigned_add_saturate (min_size - regionIndices.min_size,
3287 regionIndices.get_size (),
3288 StructAfter<CFF2Index> (regionIndices).get_size ()); }
3289
3290 void get_delta (unsigned int inner,
3291 const int *coords, unsigned int coord_count,
3292 const SparseVarRegionList &regions,
3293 hb_array_t<float> out,
3294 hb_scalar_cache_t *cache = nullptr) const
3295 {
3296 auto &deltaSets = StructAfter<decltype (deltaSetsX)> (regionIndices);
3297
3298 auto values_iter = deltaSets.fetcher (inner);
3299 unsigned regionCount = regionIndices.len;
3300 unsigned skip = 0;
3301 for (unsigned regionIndex = 0; regionIndex < regionCount; regionIndex++)
3302 {
3303 float scalar = regions.evaluate (regionIndices.arrayZ[regionIndex],
3304 coords, coord_count,
3305 cache);
3306 // We skip lazily. Helps with the tail end.
3307 if (scalar == 0.0f)
3308 skip += out.length;
3309 else
3310 {
3311 if (skip)
3312 {
3313 values_iter.skip (skip);
3314 skip = 0;
3315 }
3316 values_iter.add_to (out, scalar);
3317 }
3318 }
3319 }
3320
3321 bool sanitize (hb_sanitize_context_t *c) const
3322 {
3323 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
3324 return_trace (format.sanitize (c) &&return trace.ret (format.sanitize (c) && hb_barrier (
) && format == 1 && regionIndices.sanitize (c
) && hb_barrier () && StructAfter<decltype
(deltaSetsX)> (regionIndices).sanitize (c), __PRETTY_FUNCTION__
, 3329)
3325 hb_barrier () &&return trace.ret (format.sanitize (c) && hb_barrier (
) && format == 1 && regionIndices.sanitize (c
) && hb_barrier () && StructAfter<decltype
(deltaSetsX)> (regionIndices).sanitize (c), __PRETTY_FUNCTION__
, 3329)
3326 format == 1 &&return trace.ret (format.sanitize (c) && hb_barrier (
) && format == 1 && regionIndices.sanitize (c
) && hb_barrier () && StructAfter<decltype
(deltaSetsX)> (regionIndices).sanitize (c), __PRETTY_FUNCTION__
, 3329)
3327 regionIndices.sanitize (c) &&return trace.ret (format.sanitize (c) && hb_barrier (
) && format == 1 && regionIndices.sanitize (c
) && hb_barrier () && StructAfter<decltype
(deltaSetsX)> (regionIndices).sanitize (c), __PRETTY_FUNCTION__
, 3329)
3328 hb_barrier () &&return trace.ret (format.sanitize (c) && hb_barrier (
) && format == 1 && regionIndices.sanitize (c
) && hb_barrier () && StructAfter<decltype
(deltaSetsX)> (regionIndices).sanitize (c), __PRETTY_FUNCTION__
, 3329)
3329 StructAfter<decltype (deltaSetsX)> (regionIndices).sanitize (c))return trace.ret (format.sanitize (c) && hb_barrier (
) && format == 1 && regionIndices.sanitize (c
) && hb_barrier () && StructAfter<decltype
(deltaSetsX)> (regionIndices).sanitize (c), __PRETTY_FUNCTION__
, 3329)
;
3330 }
3331
3332 protected:
3333 HBUINT8 format; // 1
3334 Array16Of<HBUINT16> regionIndices;
3335 TupleList deltaSetsX;
3336 public:
3337 DEFINE_SIZE_MIN (8)void _instance_assertion_on_line_3337 () const { static_assert
((sizeof (*this) >= (8)), ""); } static constexpr unsigned
null_size = (8); static constexpr unsigned min_size = (8)
;
3338};
3339
3340struct ItemVariationStore
3341{
3342 friend struct item_variations_t;
3343
3344 hb_scalar_cache_t *create_cache () const
3345 {
3346#ifdef HB_NO_VAR
3347 return hb_scalar_cache_t::create (0);
3348#endif
3349 return hb_scalar_cache_t::create ((this+regions).regionCount);
3350 }
3351
3352 static void destroy_cache (hb_scalar_cache_t *cache)
3353 {
3354 hb_scalar_cache_t::destroy (cache);
3355 }
3356
3357 private:
3358 float get_delta (unsigned int outer, unsigned int inner,
3359 const int *coords, unsigned int coord_count,
3360 hb_scalar_cache_t *cache = nullptr) const
3361 {
3362#ifdef HB_NO_VAR
3363 return 0.f;
3364#endif
3365
3366 if (unlikely (outer >= dataSets.len)__builtin_expect (bool(outer >= dataSets.len), 0))
3367 return 0.f;
3368
3369 return (this+dataSets[outer]).get_delta (inner,
3370 coords, coord_count,
3371 this+regions,
3372 cache);
3373 }
3374
3375 public:
3376 bool has_delta_set (unsigned int index) const
3377 {
3378#ifdef HB_NO_VAR
3379 return false;
3380#endif
3381
3382 unsigned int outer = index >> 16;
3383 unsigned int inner = index & 0xFFFF;
3384 return outer < dataSets.len &&
3385 inner < (this+dataSets[outer]).get_item_count ();
3386 }
3387
3388 float get_delta (unsigned int index,
3389 const int *coords, unsigned int coord_count,
3390 hb_scalar_cache_t *cache = nullptr) const
3391 {
3392 unsigned int outer = index >> 16;
3393 unsigned int inner = index & 0xFFFF;
3394 return get_delta (outer, inner, coords, coord_count, cache);
3395 }
3396 float get_delta (unsigned int index,
3397 hb_array_t<const int> coords,
3398 hb_scalar_cache_t *cache = nullptr) const
3399 {
3400 return get_delta (index,
3401 coords.arrayZ, coords.length,
3402 cache);
3403 }
3404
3405 bool sanitize (hb_sanitize_context_t *c) const
3406 {
3407#ifdef HB_NO_VAR
3408 return true;
3409#endif
3410
3411 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
3412 return_trace (c->check_struct (this) &&return trace.ret (c->check_struct (this) && hb_barrier
() && format == 1 && regions.sanitize (c, this
) && dataSets.sanitize (c, this), __PRETTY_FUNCTION__
, 3416)
3413 hb_barrier () &&return trace.ret (c->check_struct (this) && hb_barrier
() && format == 1 && regions.sanitize (c, this
) && dataSets.sanitize (c, this), __PRETTY_FUNCTION__
, 3416)
3414 format == 1 &&return trace.ret (c->check_struct (this) && hb_barrier
() && format == 1 && regions.sanitize (c, this
) && dataSets.sanitize (c, this), __PRETTY_FUNCTION__
, 3416)
3415 regions.sanitize (c, this) &&return trace.ret (c->check_struct (this) && hb_barrier
() && format == 1 && regions.sanitize (c, this
) && dataSets.sanitize (c, this), __PRETTY_FUNCTION__
, 3416)
3416 dataSets.sanitize (c, this))return trace.ret (c->check_struct (this) && hb_barrier
() && format == 1 && regions.sanitize (c, this
) && dataSets.sanitize (c, this), __PRETTY_FUNCTION__
, 3416)
;
3417 }
3418
3419 bool serialize (hb_serialize_context_t *c,
3420 bool has_long,
3421 const hb_vector_t<hb_tag_t>& axis_tags,
3422 const hb_vector_t<const hb_hashmap_t<hb_tag_t, Triple>*>& region_list,
3423 const hb_vector_t<delta_row_encoding_t>& vardata_encodings)
3424 {
3425 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
3426#ifdef HB_NO_VAR
3427 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3427);
3428#endif
3429 if (unlikely (!c->extend_min (this))__builtin_expect (bool(!c->extend_min (this)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3429);
3430
3431 format = 1;
3432 if (!regions.serialize_serialize (c, axis_tags, region_list))
3433 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3433);
3434
3435 unsigned num_var_data = vardata_encodings.length;
3436 if (!num_var_data) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3436);
3437 if (unlikely (!c->check_assign (dataSets.len, num_var_data,__builtin_expect (bool(!c->check_assign (dataSets.len, num_var_data
, HB_SERIALIZE_ERROR_INT_OVERFLOW)), 0)
3438 HB_SERIALIZE_ERROR_INT_OVERFLOW))__builtin_expect (bool(!c->check_assign (dataSets.len, num_var_data
, HB_SERIALIZE_ERROR_INT_OVERFLOW)), 0)
)
3439 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3439);
3440
3441 if (unlikely (!c->extend (dataSets))__builtin_expect (bool(!c->extend (dataSets)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3441);
3442 for (unsigned i = 0; i < num_var_data; i++)
3443 if (!dataSets[i].serialize_serialize (c, has_long, vardata_encodings[i].items))
3444 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3444);
3445
3446 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 3446);
3447 }
3448
3449 bool serialize (hb_serialize_context_t *c,
3450 const ItemVariationStore *src,
3451 const hb_array_t <const hb_inc_bimap_t> &inner_maps,
3452 const hb_set_t *culled_regions = nullptr)
3453 {
3454 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
3455#ifdef HB_NO_VAR
3456 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3456);
3457#endif
3458
3459 if (unlikely (!c->extend_min (this))__builtin_expect (bool(!c->extend_min (this)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3459);
3460
3461 unsigned int set_count = 0;
3462 for (unsigned int i = 0; i < inner_maps.length; i++)
3463 if (inner_maps[i].get_population ())
3464 set_count++;
3465
3466 format = 1;
3467
3468 const auto &src_regions = src+src->regions;
3469
3470 hb_set_t region_indices;
3471 for (unsigned int i = 0; i < inner_maps.length; i++)
3472 (src+src->dataSets[i]).collect_region_refs (region_indices, inner_maps[i]);
3473
3474 if (region_indices.in_error ())
3475 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3475);
3476
3477 region_indices.del_range ((src_regions).regionCount, hb_set_t::INVALID);
3478
3479 if (culled_regions)
3480 region_indices.subtract (*culled_regions);
3481
3482 /* TODO use constructor when our data-structures support that. */
3483 hb_inc_bimap_t region_map;
3484 + hb_iter (region_indices)
3485 | hb_apply ([&region_map] (unsigned _) { region_map.add(_); })
3486 ;
3487 if (region_map.in_error())
3488 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3488);
3489
3490 if (unlikely (!regions.serialize_serialize (c, &src_regions, region_map))__builtin_expect (bool(!regions.serialize_serialize (c, &
src_regions, region_map)), 0)
)
3491 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3491);
3492
3493 dataSets.len = set_count;
3494 if (unlikely (!c->extend (dataSets))__builtin_expect (bool(!c->extend (dataSets)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3494);
3495
3496 /* TODO: The following code could be simplified when
3497 * List16OfOffset16To::subset () can take a custom param to be passed to VarData::serialize () */
3498 unsigned int set_index = 0;
3499 for (unsigned int i = 0; i < inner_maps.length; i++)
3500 {
3501 if (!inner_maps[i].get_population ()) continue;
3502 if (unlikely (!dataSets[set_index++]__builtin_expect (bool(!dataSets[set_index++] .serialize_serialize
(c, &(src+src->dataSets[i]), inner_maps[i], region_map
, culled_regions)), 0)
3503 .serialize_serialize (c, &(src+src->dataSets[i]), inner_maps[i], region_map,__builtin_expect (bool(!dataSets[set_index++] .serialize_serialize
(c, &(src+src->dataSets[i]), inner_maps[i], region_map
, culled_regions)), 0)
3504 culled_regions))__builtin_expect (bool(!dataSets[set_index++] .serialize_serialize
(c, &(src+src->dataSets[i]), inner_maps[i], region_map
, culled_regions)), 0)
)
3505 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3505);
3506 }
3507
3508 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 3508);
3509 }
3510
3511 ItemVariationStore *copy (hb_serialize_context_t *c) const
3512 {
3513 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
3514 auto *out = c->start_embed (this);
3515 if (unlikely (!out)__builtin_expect (bool(!out), 0)) return_trace (nullptr)return trace.ret (nullptr, __PRETTY_FUNCTION__, 3515);
3516
3517 hb_vector_t <hb_inc_bimap_t> inner_maps;
3518 unsigned count = dataSets.len;
3519 for (unsigned i = 0; i < count; i++)
3520 {
3521 hb_inc_bimap_t *map = inner_maps.push ();
3522 if (unlikely (!c->propagate_error(inner_maps))__builtin_expect (bool(!c->propagate_error(inner_maps)), 0
)
)
3523 return_trace(nullptr)return trace.ret (nullptr, __PRETTY_FUNCTION__, 3523);
3524 auto &data = this+dataSets[i];
3525
3526 unsigned itemCount = data.get_item_count ();
3527 for (unsigned j = 0; j < itemCount; j++)
3528 map->add (j);
3529 }
3530
3531 if (unlikely (!out->serialize (c, this, inner_maps))__builtin_expect (bool(!out->serialize (c, this, inner_maps
)), 0)
) return_trace (nullptr)return trace.ret (nullptr, __PRETTY_FUNCTION__, 3531);
3532
3533 return_trace (out)return trace.ret (out, __PRETTY_FUNCTION__, 3533);
3534 }
3535
3536 /* Collect regions that a partial avar2 instance can never reach, per the
3537 * plan's reachable final-coordinate ranges. */
3538 bool collect_dead_regions (const hb_map_t &axes_old_index_tag_map,
3539 const hb_hashmap_t<hb_tag_t, Triple> &reachable_ranges,
3540 hb_set_t &dead_regions /* OUT */) const
3541 {
3542#ifndef HB_NO_VAR
3543 if (!reachable_ranges.get_population ()) return true;
3544 const VarRegionList &region_list = this+regions;
3545 unsigned count = region_list.regionCount;
3546 for (unsigned i = 0; i < count; i++)
3547 {
3548 hb_hashmap_t<hb_tag_t, Triple> axis_tuples;
3549 if (!region_list.get_var_region (i, axes_old_index_tag_map, axis_tuples))
3550 return false;
3551 if (_hb_avar2_region_is_dead (axis_tuples, reachable_ranges))
3552 dead_regions.add (i);
3553 }
3554 return !dead_regions.in_error ();
3555#else
3556 return true;
3557#endif
3558 }
3559
3560 bool subset (hb_subset_context_t *c, const hb_array_t<const hb_inc_bimap_t> &inner_maps) const
3561 {
3562 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
3563#ifdef HB_NO_VAR
3564 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3564);
3565#endif
3566
3567 ItemVariationStore *varstore_prime = c->serializer->start_embed<ItemVariationStore> ();
3568 if (unlikely (!varstore_prime)__builtin_expect (bool(!varstore_prime), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3568);
3569
3570 /* avar2 partial instancing: cull unreachable regions. */
3571 hb_set_t dead_regions;
3572 if (c->plan->has_avar2)
3573 if (!collect_dead_regions (c->plan->axes_old_index_tag_map,
3574 c->plan->avar2_reachable_ranges,
3575 dead_regions))
3576 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3576);
3577
3578 varstore_prime->serialize (c->serializer, this, inner_maps,
3579 dead_regions.get_population () ? &dead_regions : nullptr);
3580
3581 return_trace (return trace.ret (!c->serializer->in_error() &&
varstore_prime->dataSets, __PRETTY_FUNCTION__, 3583)
3582 !c->serializer->in_error()return trace.ret (!c->serializer->in_error() &&
varstore_prime->dataSets, __PRETTY_FUNCTION__, 3583)
3583 && varstore_prime->dataSets)return trace.ret (!c->serializer->in_error() &&
varstore_prime->dataSets, __PRETTY_FUNCTION__, 3583)
;
3584 }
3585
3586 unsigned int get_region_index_count (unsigned int major) const
3587 {
3588#ifdef HB_NO_VAR
3589 return 0;
3590#endif
3591 return (this+dataSets[major]).get_region_index_count ();
3592 }
3593
3594 void get_region_scalars (unsigned int major,
3595 const int *coords, unsigned int coord_count,
3596 float *scalars /*OUT*/,
3597 unsigned int num_scalars) const
3598 {
3599#ifdef HB_NO_VAR
3600 for (unsigned i = 0; i < num_scalars; i++)
3601 scalars[i] = 0.f;
3602 return;
3603#endif
3604
3605 (this+dataSets[major]).get_region_scalars (coords, coord_count,
3606 this+regions,
3607 &scalars[0], num_scalars);
3608 }
3609
3610 unsigned int get_sub_table_count () const
3611 {
3612#ifdef HB_NO_VAR
3613 return 0;
3614#endif
3615 return dataSets.len;
3616 }
3617
3618 const VarData& get_sub_table (unsigned i) const
3619 {
3620#ifdef HB_NO_VAR
3621 return Null (VarData)NullHelper<VarData>::get_null ();
3622#endif
3623 return this+dataSets[i];
3624 }
3625
3626 const VarRegionList& get_region_list () const
3627 {
3628#ifdef HB_NO_VAR
3629 return Null (VarRegionList)NullHelper<VarRegionList>::get_null ();
3630#endif
3631 return this+regions;
3632 }
3633
3634 protected:
3635 HBUINT16 format;
3636 Offset32To<VarRegionList> regions;
3637 Array16OfOffset32To<VarData> dataSets;
3638 public:
3639 DEFINE_SIZE_ARRAY_SIZED (8, dataSets)size_t get_size () const { return (8 - (dataSets).min_size + (
dataSets).get_size ()); } void _compiles_assertion_on_line_3639
() const { (void) (dataSets)[0].static_size; } void _instance_assertion_on_line_3639
() const { static_assert ((sizeof (*this) == (8) + (1 +0) * sizeof
((dataSets)[0])), ""); } static constexpr unsigned null_size
= (8); static constexpr unsigned min_size = (8)
;
3640};
3641
3642struct MultiItemVariationStore
3643{
3644 hb_scalar_cache_t *create_cache (hb_scalar_cache_t *static_cache = nullptr) const
3645 {
3646#ifdef HB_NO_VAR
3647 return hb_scalar_cache_t::create (0);
3648#endif
3649 auto &r = this+regions;
3650 unsigned count = r.regions.len;
3651
3652 return hb_scalar_cache_t::create (count, static_cache);
3653 }
3654
3655 static void destroy_cache (hb_scalar_cache_t *cache,
3656 hb_scalar_cache_t *static_cache = nullptr)
3657 {
3658 hb_scalar_cache_t::destroy (cache, static_cache);
3659 }
3660
3661 private:
3662 void get_delta (unsigned int outer, unsigned int inner,
3663 const int *coords, unsigned int coord_count,
3664 hb_array_t<float> out,
3665 hb_scalar_cache_t *cache = nullptr) const
3666 {
3667#ifdef HB_NO_VAR
3668 return;
3669#endif
3670
3671 if (unlikely (outer >= dataSets.len)__builtin_expect (bool(outer >= dataSets.len), 0))
3672 return;
3673
3674 return (this+dataSets[outer]).get_delta (inner,
3675 coords, coord_count,
3676 this+regions,
3677 out,
3678 cache);
3679 }
3680
3681 public:
3682 void get_delta (unsigned int index,
3683 const int *coords, unsigned int coord_count,
3684 hb_array_t<float> out,
3685 hb_scalar_cache_t *cache = nullptr) const
3686 {
3687 unsigned int outer = index >> 16;
3688 unsigned int inner = index & 0xFFFF;
3689 get_delta (outer, inner, coords, coord_count, out, cache);
3690 }
3691 void get_delta (unsigned int index,
3692 hb_array_t<const int> coords,
3693 hb_array_t<float> out,
3694 hb_scalar_cache_t *cache = nullptr) const
3695 {
3696 return get_delta (index,
3697 coords.arrayZ, coords.length,
3698 out,
3699 cache);
3700 }
3701
3702 bool sanitize (hb_sanitize_context_t *c) const
3703 {
3704#ifdef HB_NO_VAR
3705 return true;
3706#endif
3707
3708 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
3709 return_trace (c->check_struct (this) &&return trace.ret (c->check_struct (this) && hb_barrier
() && format == 1 && regions.sanitize (c, this
) && dataSets.sanitize (c, this), __PRETTY_FUNCTION__
, 3713)
3710 hb_barrier () &&return trace.ret (c->check_struct (this) && hb_barrier
() && format == 1 && regions.sanitize (c, this
) && dataSets.sanitize (c, this), __PRETTY_FUNCTION__
, 3713)
3711 format == 1 &&return trace.ret (c->check_struct (this) && hb_barrier
() && format == 1 && regions.sanitize (c, this
) && dataSets.sanitize (c, this), __PRETTY_FUNCTION__
, 3713)
3712 regions.sanitize (c, this) &&return trace.ret (c->check_struct (this) && hb_barrier
() && format == 1 && regions.sanitize (c, this
) && dataSets.sanitize (c, this), __PRETTY_FUNCTION__
, 3713)
3713 dataSets.sanitize (c, this))return trace.ret (c->check_struct (this) && hb_barrier
() && format == 1 && regions.sanitize (c, this
) && dataSets.sanitize (c, this), __PRETTY_FUNCTION__
, 3713)
;
3714 }
3715
3716 protected:
3717 HBUINT16 format; // 1
3718 Offset32To<SparseVarRegionList> regions;
3719 Array16OfOffset32To<MultiVarData> dataSets;
3720 public:
3721 DEFINE_SIZE_ARRAY_SIZED (8, dataSets)size_t get_size () const { return (8 - (dataSets).min_size + (
dataSets).get_size ()); } void _compiles_assertion_on_line_3721
() const { (void) (dataSets)[0].static_size; } void _instance_assertion_on_line_3721
() const { static_assert ((sizeof (*this) == (8) + (1 +0) * sizeof
((dataSets)[0])), ""); } static constexpr unsigned null_size
= (8); static constexpr unsigned min_size = (8)
;
3722};
3723
3724template <typename MapCountT>
3725struct DeltaSetIndexMapFormat01
3726{
3727 friend struct DeltaSetIndexMap;
3728
3729 size_t get_size () const
3730 { return hb_unsigned_mul_add_saturate (mapCount, get_width (), min_size); }
3731
3732 private:
3733 DeltaSetIndexMapFormat01* copy (hb_serialize_context_t *c) const
3734 {
3735 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
3736 return_trace (c->embed (this))return trace.ret (c->embed (this), __PRETTY_FUNCTION__, 3736
)
;
3737 }
3738
3739 template <typename T>
3740 bool serialize (hb_serialize_context_t *c, const T &plan)
3741 {
3742 unsigned int width = plan.get_width ();
3743 unsigned int inner_bit_count = plan.get_inner_bit_count ();
3744 const hb_array_t<const uint32_t> output_map = plan.get_output_map ();
3745
3746 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
3747 if (unlikely (output_map.length && ((((inner_bit_count-1)&~0xF)!=0) || (((width-1)&~0x3)!=0)))__builtin_expect (bool(output_map.length && ((((inner_bit_count
-1)&~0xF)!=0) || (((width-1)&~0x3)!=0))), 0)
)
3748 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3748);
3749 if (unlikely (!c->extend_min (this))__builtin_expect (bool(!c->extend_min (this)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3749);
3750
3751 entryFormat = ((width-1)<<4)|(inner_bit_count-1);
3752 mapCount = output_map.length;
3753 HBUINT8 *p = c->allocate_size<HBUINT8> (width * output_map.length);
3754 if (unlikely (!p)__builtin_expect (bool(!p), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3754);
3755 for (unsigned int i = 0; i < output_map.length; i++)
3756 {
3757 unsigned int v = output_map.arrayZ[i];
3758 if (v)
3759 {
3760 unsigned int outer = v >> 16;
3761 unsigned int inner = v & 0xFFFF;
3762 unsigned int u = (outer << inner_bit_count) | inner;
3763 for (unsigned int w = width; w > 0;)
3764 {
3765 p[--w] = u;
3766 u >>= 8;
3767 }
3768 }
3769 p += width;
3770 }
3771 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 3771);
3772 }
3773
3774 HB_ALWAYS_INLINE__attribute__((always_inline)) inline
3775 uint32_t map (unsigned int v) const /* Returns 16.16 outer.inner. */
3776 {
3777 /* If count is zero, pass value unchanged. This takes
3778 * care of direct mapping for advance map. */
3779 if (!mapCount)
3780 return v;
3781 return _map (v);
3782 }
3783
3784 HB_HOT__attribute__((hot))
3785 uint32_t _map (unsigned int v) const /* Returns 16.16 outer.inner. */
3786 {
3787 if (v >= mapCount)
3788 v = mapCount - 1;
3789
3790 unsigned int u = 0;
3791 { /* Fetch it. */
3792 unsigned int w = get_width ();
3793 const HBUINT8 *p = mapDataZ.arrayZ + w * v;
3794 for (; w; w--)
3795 u = (u << 8) + *p++;
3796 }
3797
3798 { /* Repack it. */
3799 unsigned int n = get_inner_bit_count ();
3800 unsigned int outer = u >> n;
3801 unsigned int inner = u & ((1 << n) - 1);
3802 u = (outer<<16) | inner;
3803 }
3804
3805 return u;
3806 }
3807
3808 unsigned get_map_count () const { return mapCount; }
3809 unsigned get_width () const { return ((entryFormat >> 4) & 3) + 1; }
3810 unsigned get_inner_bit_count () const { return (entryFormat & 0xF) + 1; }
3811
3812
3813 bool sanitize (hb_sanitize_context_t *c) const
3814 {
3815 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
3816 return_trace (c->check_struct (this) &&return trace.ret (c->check_struct (this) && hb_barrier
() && c->check_range (mapDataZ.arrayZ, mapCount, get_width
()), __PRETTY_FUNCTION__, 3820)
3817 hb_barrier () &&return trace.ret (c->check_struct (this) && hb_barrier
() && c->check_range (mapDataZ.arrayZ, mapCount, get_width
()), __PRETTY_FUNCTION__, 3820)
3818 c->check_range (mapDataZ.arrayZ,return trace.ret (c->check_struct (this) && hb_barrier
() && c->check_range (mapDataZ.arrayZ, mapCount, get_width
()), __PRETTY_FUNCTION__, 3820)
3819 mapCount,return trace.ret (c->check_struct (this) && hb_barrier
() && c->check_range (mapDataZ.arrayZ, mapCount, get_width
()), __PRETTY_FUNCTION__, 3820)
3820 get_width ()))return trace.ret (c->check_struct (this) && hb_barrier
() && c->check_range (mapDataZ.arrayZ, mapCount, get_width
()), __PRETTY_FUNCTION__, 3820)
;
3821 }
3822
3823 protected:
3824 HBUINT8 format; /* Format identifier--format = 0 */
3825 HBUINT8 entryFormat; /* A packed field that describes the compressed
3826 * representation of delta-set indices. */
3827 MapCountT mapCount; /* The number of mapping entries. */
3828 UnsizedArrayOf<HBUINT8>
3829 mapDataZ; /* The delta-set index mapping data. */
3830
3831 public:
3832 DEFINE_SIZE_ARRAY (2+MapCountT::static_size, mapDataZ)void _compiles_assertion_on_line_3832 () const { (void) (mapDataZ
)[0].static_size; } void _instance_assertion_on_line_3832 () const
{ static_assert ((sizeof (*this) == (2+MapCountT::static_size
) + (1 +0) * sizeof ((mapDataZ)[0])), ""); } static constexpr
unsigned null_size = (2+MapCountT::static_size); static constexpr
unsigned min_size = (2+MapCountT::static_size)
;
3833};
3834
3835struct DeltaSetIndexMap
3836{
3837 template <typename T>
3838 bool serialize (hb_serialize_context_t *c, const T &plan)
3839 {
3840 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
3841 unsigned length = plan.get_output_map ().length;
3842 u.format.v = length <= 0xFFFF ? 0 : 1;
3843 switch (u.format.v) {
3844 case 0: hb_barrier (); return_trace (u.format0.serialize (c, plan))return trace.ret (u.format0.serialize (c, plan), __PRETTY_FUNCTION__
, 3844)
;
3845 case 1: hb_barrier (); return_trace (u.format1.serialize (c, plan))return trace.ret (u.format1.serialize (c, plan), __PRETTY_FUNCTION__
, 3845)
;
3846 default:return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3846);
3847 }
3848 }
3849
3850 uint32_t map (unsigned v) const
3851 {
3852 switch (u.format.v) {
3853 case 0: hb_barrier (); return (u.format0.map (v));
3854 case 1: hb_barrier (); return (u.format1.map (v));
3855 default:return v;
3856 }
3857 }
3858
3859 unsigned get_map_count () const
3860 {
3861 switch (u.format.v) {
3862 case 0: hb_barrier (); return u.format0.get_map_count ();
3863 case 1: hb_barrier (); return u.format1.get_map_count ();
3864 default:return 0;
3865 }
3866 }
3867
3868 unsigned get_width () const
3869 {
3870 switch (u.format.v) {
3871 case 0: hb_barrier (); return u.format0.get_width ();
3872 case 1: hb_barrier (); return u.format1.get_width ();
3873 default:return 0;
3874 }
3875 }
3876
3877 unsigned get_inner_bit_count () const
3878 {
3879 switch (u.format.v) {
3880 case 0: hb_barrier (); return u.format0.get_inner_bit_count ();
3881 case 1: hb_barrier (); return u.format1.get_inner_bit_count ();
3882 default:return 0;
3883 }
3884 }
3885
3886 bool sanitize (hb_sanitize_context_t *c) const
3887 {
3888 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
3889 if (!u.format.v.sanitize (c)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3889);
3890 hb_barrier ();
3891 switch (u.format.v) {
3892 case 0: hb_barrier (); return_trace (u.format0.sanitize (c))return trace.ret (u.format0.sanitize (c), __PRETTY_FUNCTION__
, 3892)
;
3893 case 1: hb_barrier (); return_trace (u.format1.sanitize (c))return trace.ret (u.format1.sanitize (c), __PRETTY_FUNCTION__
, 3893)
;
3894 default:return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 3894);
3895 }
3896 }
3897
3898 DeltaSetIndexMap* copy (hb_serialize_context_t *c) const
3899 {
3900 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
3901 switch (u.format.v) {
3902 case 0: hb_barrier (); return_trace (reinterpret_cast<DeltaSetIndexMap *> (u.format0.copy (c)))return trace.ret (reinterpret_cast<DeltaSetIndexMap *> (
u.format0.copy (c)), __PRETTY_FUNCTION__, 3902)
;
3903 case 1: hb_barrier (); return_trace (reinterpret_cast<DeltaSetIndexMap *> (u.format1.copy (c)))return trace.ret (reinterpret_cast<DeltaSetIndexMap *> (
u.format1.copy (c)), __PRETTY_FUNCTION__, 3903)
;
3904 default:return_trace (nullptr)return trace.ret (nullptr, __PRETTY_FUNCTION__, 3904);
3905 }
3906 }
3907
3908 protected:
3909 union {
3910 struct { HBUINT8 v; } format; /* Format identifier */
3911 DeltaSetIndexMapFormat01<HBUINT16> format0;
3912 DeltaSetIndexMapFormat01<HBUINT32> format1;
3913 } u;
3914 public:
3915 DEFINE_SIZE_UNION (1, format.v)void _compiles_assertion_on_line_3915 () const { (void) this->
u.format.v.static_size; } void _instance_assertion_on_line_3915
() const { static_assert ((sizeof(this->u.format.v) == (1
)), ""); } static constexpr unsigned null_size = (1); static constexpr
unsigned min_size = (1)
;
3916};
3917
3918
3919struct ItemVarStoreInstancer
3920{
3921 ItemVarStoreInstancer (const ItemVariationStore *varStore_,
3922 const DeltaSetIndexMap *varIdxMap,
3923 hb_array_t<const int> coords,
3924 hb_scalar_cache_t *cache = nullptr) :
3925 varStore (varStore_), varIdxMap (varIdxMap), coords (coords), cache (cache)
3926 {
3927 if (!varStore)
3928 varStore = &Null(ItemVariationStore)NullHelper<ItemVariationStore>::get_null ();
3929 }
3930
3931 operator bool () const { return varStore && bool (coords); }
3932
3933 float operator[] (uint32_t varIdx) const
3934 { return (*this) (varIdx); }
3935
3936 float operator() (uint32_t varIdx, unsigned short offset = 0) const
3937 {
3938 if (!coords || varIdx == VarIdx::NO_VARIATION)
3939 return 0.f;
3940
3941 varIdx += offset;
3942 if (varIdxMap)
3943 varIdx = varIdxMap->map (varIdx);
3944 return varStore->get_delta (varIdx, coords, cache);
3945 }
3946
3947 const ItemVariationStore *varStore;
3948 const DeltaSetIndexMap *varIdxMap;
3949 hb_array_t<const int> coords;
3950 hb_scalar_cache_t *cache;
3951};
3952
3953struct MultiItemVarStoreInstancer
3954{
3955 MultiItemVarStoreInstancer (const MultiItemVariationStore *varStore,
3956 const DeltaSetIndexMap *varIdxMap,
3957 hb_array_t<const int> coords,
3958 hb_scalar_cache_t *cache = nullptr) :
3959 varStore (varStore), varIdxMap (varIdxMap), coords (coords), cache (cache)
3960 {
3961 if (!varStore)
3962 varStore = &Null(MultiItemVariationStore)NullHelper<MultiItemVariationStore>::get_null ();
Value stored to 'varStore' is never read
3963 }
3964
3965 operator bool () const { return varStore && bool (coords); }
3966
3967 float operator[] (uint32_t varIdx) const
3968 {
3969 float v = 0;
3970 (*this) (hb_array (&v, 1), varIdx);
3971 return v;
3972 }
3973
3974 void operator() (hb_array_t<float> out, uint32_t varIdx, unsigned short offset = 0) const
3975 {
3976 if (coords && varIdx != VarIdx::NO_VARIATION)
3977 {
3978 varIdx += offset;
3979 if (varIdxMap)
3980 varIdx = varIdxMap->map (varIdx);
3981 varStore->get_delta (varIdx, coords, out, cache);
3982 }
3983 else
3984 for (unsigned i = 0; i < out.length; i++)
3985 out.arrayZ[i] = 0.f;
3986 }
3987
3988 const MultiItemVariationStore *varStore;
3989 const DeltaSetIndexMap *varIdxMap;
3990 hb_array_t<const int> coords;
3991 hb_scalar_cache_t *cache;
3992};
3993
3994
3995/*
3996 * Feature Variations
3997 */
3998enum Cond_with_Var_flag_t
3999{
4000 KEEP_COND_WITH_VAR = 0,
4001 KEEP_RECORD_WITH_VAR = 1,
4002 DROP_COND_WITH_VAR = 2,
4003 DROP_RECORD_WITH_VAR = 3,
4004};
4005
4006struct Condition;
4007
4008template <typename Instancer>
4009static bool
4010_hb_recurse_condition_evaluate (const struct Condition &condition,
4011 const int *coords,
4012 unsigned int coord_len,
4013 Instancer *instancer);
4014
4015struct ConditionAxisRange
4016{
4017 friend struct Condition;
4018
4019 bool subset (hb_subset_context_t *c) const
4020 {
4021 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
4022 auto *out = c->serializer->embed (this);
4023 if (unlikely (!out)__builtin_expect (bool(!out), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4023);
4024
4025 const hb_map_t *index_map = &c->plan->axes_index_map;
4026 if (index_map->is_empty ()) return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 4026);
4027
4028 const hb_map_t& axes_old_index_tag_map = c->plan->axes_old_index_tag_map;
4029 hb_codepoint_t *axis_tag;
4030 if (!axes_old_index_tag_map.has (axisIndex, &axis_tag) ||
4031 !index_map->has (axisIndex))
4032 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4032);
4033
4034 const hb_hashmap_t<hb_tag_t, Triple>& normalized_axes_location = c->plan->axes_location;
4035 Triple axis_limit{-1.0, 0.0, 1.0};
4036 Triple *normalized_limit;
4037 if (normalized_axes_location.has (*axis_tag, &normalized_limit))
4038 axis_limit = *normalized_limit;
4039
4040 const hb_hashmap_t<hb_tag_t, TripleDistances>& axes_triple_distances = c->plan->axes_triple_distances;
4041 TripleDistances axis_triple_distances{1.0, 1.0};
4042 TripleDistances *triple_dists;
4043 if (axes_triple_distances.has (*axis_tag, &triple_dists))
4044 axis_triple_distances = *triple_dists;
4045
4046 float normalized_min = renormalizeValue ((double) filterRangeMinValue.to_float (), axis_limit, axis_triple_distances, false);
4047 float normalized_max = renormalizeValue ((double) filterRangeMaxValue.to_float (), axis_limit, axis_triple_distances, false);
4048 out->filterRangeMinValue.set_float (normalized_min);
4049 out->filterRangeMaxValue.set_float (normalized_max);
4050
4051 return_trace (c->serializer->check_assign (out->axisIndex, index_map->get (axisIndex),return trace.ret (c->serializer->check_assign (out->
axisIndex, index_map->get (axisIndex), HB_SERIALIZE_ERROR_INT_OVERFLOW
), __PRETTY_FUNCTION__, 4052)
4052 HB_SERIALIZE_ERROR_INT_OVERFLOW))return trace.ret (c->serializer->check_assign (out->
axisIndex, index_map->get (axisIndex), HB_SERIALIZE_ERROR_INT_OVERFLOW
), __PRETTY_FUNCTION__, 4052)
;
4053 }
4054
4055 private:
4056 Cond_with_Var_flag_t keep_with_variations (hb_collect_feature_substitutes_with_var_context_t *c,
4057 hb_map_t *condition_map /* OUT */) const
4058 {
4059 //invalid axis index, drop the entire record
4060 if (!c->axes_index_tag_map->has (axisIndex))
4061 return DROP_RECORD_WITH_VAR;
4062
4063 hb_tag_t axis_tag = c->axes_index_tag_map->get (axisIndex);
4064
4065 Triple axis_range (-1.0, 0.0, 1.0);
4066 Triple *axis_limit;
4067 bool axis_set_by_user = false;
4068 if (c->axes_location->has (axis_tag, &axis_limit))
4069 {
4070 axis_range = *axis_limit;
4071 axis_set_by_user = true;
4072 }
4073
4074 float axis_min_val = axis_range.minimum;
4075 float axis_default_val = axis_range.middle;
4076 float axis_max_val = axis_range.maximum;
4077
4078 float filter_min_val = filterRangeMinValue.to_float ();
4079 float filter_max_val = filterRangeMaxValue.to_float ();
4080
4081 if (axis_default_val < filter_min_val ||
4082 axis_default_val > filter_max_val)
4083 c->apply = false;
4084
4085 //condition not met, drop the entire record
4086 if (axis_min_val > filter_max_val || axis_max_val < filter_min_val ||
4087 filter_min_val > filter_max_val)
4088 return DROP_RECORD_WITH_VAR;
4089
4090 //condition met and axis pinned, drop the condition
4091 if (axis_set_by_user && axis_range.is_point ())
4092 return DROP_COND_WITH_VAR;
4093
4094 if (filter_max_val != axis_max_val || filter_min_val != axis_min_val)
4095 {
4096 // add axisIndex->value into the hashmap so we can check if the record is
4097 // unique with variations
4098 uint16_t int_filter_max_val = (uint16_t) filterRangeMaxValue.to_int ();
4099 uint16_t int_filter_min_val = (uint16_t) filterRangeMinValue.to_int ();
4100 hb_codepoint_t val = (int_filter_max_val << 16) + int_filter_min_val;
4101
4102 condition_map->set (axisIndex, val);
4103 return KEEP_COND_WITH_VAR;
4104 }
4105 return KEEP_RECORD_WITH_VAR;
4106 }
4107
4108 template <typename Instancer>
4109 bool evaluate (const int *coords, unsigned int coord_len,
4110 Instancer *instancer HB_UNUSED__attribute__((unused))) const
4111 {
4112 int coord = axisIndex < coord_len ? coords[axisIndex] : 0;
4113 return filterRangeMinValue.to_int () <= coord && coord <= filterRangeMaxValue.to_int ();
4114 }
4115
4116 public:
4117 bool sanitize (hb_sanitize_context_t *c) const
4118 {
4119 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
4120 return_trace (c->check_struct (this))return trace.ret (c->check_struct (this), __PRETTY_FUNCTION__
, 4120)
;
4121 }
4122
4123 protected:
4124 HBUINT16 format; /* Format identifier--format = 1 */
4125 HBUINT16 axisIndex;
4126 F2DOT14 filterRangeMinValue;
4127 F2DOT14 filterRangeMaxValue;
4128 public:
4129 DEFINE_SIZE_STATIC (8)void _instance_assertion_on_line_4129 () const { static_assert
((sizeof (*this) == (8)), ""); } size_t get_size () const { return
(8); } static constexpr unsigned null_size = (8); static constexpr
unsigned min_size = (8); static constexpr unsigned static_size
= (8)
;
4130};
4131
4132struct ConditionValue
4133{
4134 friend struct Condition;
4135
4136 bool subset (hb_subset_context_t *c) const
4137 {
4138 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
4139 // TODO(subset)
4140 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4140);
4141 }
4142
4143 private:
4144 template <typename Instancer>
4145 bool evaluate (const int *coords, unsigned int coord_len,
4146 Instancer *instancer) const
4147 {
4148 float value = defaultValue;
4149 value += (*instancer)[varIdx];
4150 return value > 0;
4151 }
4152
4153 bool subset (hb_subset_context_t *c,
4154 hb_subset_layout_context_t *l,
4155 bool insert_catch_all) const
4156 {
4157 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
4158 // TODO(subset)
4159 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4159);
4160 }
4161
4162 public:
4163 bool sanitize (hb_sanitize_context_t *c) const
4164 {
4165 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
4166 return_trace (c->check_struct (this))return trace.ret (c->check_struct (this), __PRETTY_FUNCTION__
, 4166)
;
4167 }
4168
4169 protected:
4170 HBUINT16 format; /* Format identifier--format = 2 */
4171 HBINT16 defaultValue; /* Value at default instance. */
4172 VarIdx varIdx; /* Variation index */
4173 public:
4174 DEFINE_SIZE_STATIC (8)void _instance_assertion_on_line_4174 () const { static_assert
((sizeof (*this) == (8)), ""); } size_t get_size () const { return
(8); } static constexpr unsigned null_size = (8); static constexpr
unsigned min_size = (8); static constexpr unsigned static_size
= (8)
;
4175};
4176
4177struct ConditionAnd
4178{
4179 friend struct Condition;
4180
4181 bool subset (hb_subset_context_t *c) const
4182 {
4183 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
4184 // TODO(subset)
4185 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4185);
4186 }
4187
4188 private:
4189 template <typename Instancer>
4190 bool evaluate (const int *coords, unsigned int coord_len,
4191 Instancer *instancer) const
4192 {
4193 unsigned int count = conditions.len;
4194 for (unsigned int i = 0; i < count; i++)
4195 if (!_hb_recurse_condition_evaluate (this+conditions.arrayZ[i],
4196 coords, coord_len,
4197 instancer))
4198 return false;
4199 return true;
4200 }
4201
4202 bool subset (hb_subset_context_t *c,
4203 hb_subset_layout_context_t *l,
4204 bool insert_catch_all) const
4205 {
4206 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
4207 // TODO(subset)
4208 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4208);
4209 }
4210
4211 public:
4212 bool sanitize (hb_sanitize_context_t *c) const
4213 {
4214 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
4215 return_trace (conditions.sanitize (c, this))return trace.ret (conditions.sanitize (c, this), __PRETTY_FUNCTION__
, 4215)
;
4216 }
4217
4218 protected:
4219 HBUINT16 format; /* Format identifier--format = 3 */
4220 Array8OfOffset24To<struct Condition> conditions;
4221 public:
4222 DEFINE_SIZE_ARRAY (3, conditions)void _compiles_assertion_on_line_4222 () const { (void) (conditions
)[0].static_size; } void _instance_assertion_on_line_4222 () const
{ static_assert ((sizeof (*this) == (3) + (1 +0) * sizeof ((
conditions)[0])), ""); } static constexpr unsigned null_size =
(3); static constexpr unsigned min_size = (3)
;
4223};
4224
4225struct ConditionOr
4226{
4227 friend struct Condition;
4228
4229 bool subset (hb_subset_context_t *c) const
4230 {
4231 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
4232 // TODO(subset)
4233 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4233);
4234 }
4235
4236 private:
4237 template <typename Instancer>
4238 bool evaluate (const int *coords, unsigned int coord_len,
4239 Instancer *instancer) const
4240 {
4241 unsigned int count = conditions.len;
4242 for (unsigned int i = 0; i < count; i++)
4243 if (_hb_recurse_condition_evaluate (this+conditions.arrayZ[i],
4244 coords, coord_len,
4245 instancer))
4246 return true;
4247 return false;
4248 }
4249
4250 bool subset (hb_subset_context_t *c,
4251 hb_subset_layout_context_t *l,
4252 bool insert_catch_all) const
4253 {
4254 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
4255 // TODO(subset)
4256 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4256);
4257 }
4258
4259 public:
4260 bool sanitize (hb_sanitize_context_t *c) const
4261 {
4262 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
4263 return_trace (conditions.sanitize (c, this))return trace.ret (conditions.sanitize (c, this), __PRETTY_FUNCTION__
, 4263)
;
4264 }
4265
4266 protected:
4267 HBUINT16 format; /* Format identifier--format = 4 */
4268 Array8OfOffset24To<struct Condition> conditions;
4269 public:
4270 DEFINE_SIZE_ARRAY (3, conditions)void _compiles_assertion_on_line_4270 () const { (void) (conditions
)[0].static_size; } void _instance_assertion_on_line_4270 () const
{ static_assert ((sizeof (*this) == (3) + (1 +0) * sizeof ((
conditions)[0])), ""); } static constexpr unsigned null_size =
(3); static constexpr unsigned min_size = (3)
;
4271};
4272
4273struct ConditionNegate
4274{
4275 friend struct Condition;
4276
4277 bool subset (hb_subset_context_t *c) const
4278 {
4279 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
4280 // TODO(subset)
4281 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4281);
4282 }
4283
4284 private:
4285 template <typename Instancer>
4286 bool evaluate (const int *coords, unsigned int coord_len,
4287 Instancer *instancer) const
4288 {
4289 return !_hb_recurse_condition_evaluate (this+condition,
4290 coords, coord_len,
4291 instancer);
4292 }
4293
4294 bool subset (hb_subset_context_t *c,
4295 hb_subset_layout_context_t *l,
4296 bool insert_catch_all) const
4297 {
4298 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
4299 // TODO(subset)
4300 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4300);
4301 }
4302
4303 public:
4304 bool sanitize (hb_sanitize_context_t *c) const
4305 {
4306 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
4307 return_trace (condition.sanitize (c, this))return trace.ret (condition.sanitize (c, this), __PRETTY_FUNCTION__
, 4307)
;
4308 }
4309
4310 protected:
4311 HBUINT16 format; /* Format identifier--format = 5 */
4312 Offset24To<struct Condition> condition;
4313 public:
4314 DEFINE_SIZE_STATIC (5)void _instance_assertion_on_line_4314 () const { static_assert
((sizeof (*this) == (5)), ""); } size_t get_size () const { return
(5); } static constexpr unsigned null_size = (5); static constexpr
unsigned min_size = (5); static constexpr unsigned static_size
= (5)
;
4315};
4316
4317struct Condition
4318{
4319 template <typename Instancer>
4320 bool evaluate (const int *coords, unsigned int coord_len,
4321 Instancer *instancer) const
4322 {
4323 switch (u.format.v) {
4324 case 1: hb_barrier (); return u.format1.evaluate (coords, coord_len, instancer);
4325 case 2: hb_barrier (); return u.format2.evaluate (coords, coord_len, instancer);
4326 case 3: hb_barrier (); return u.format3.evaluate (coords, coord_len, instancer);
4327 case 4: hb_barrier (); return u.format4.evaluate (coords, coord_len, instancer);
4328 case 5: hb_barrier (); return u.format5.evaluate (coords, coord_len, instancer);
4329 default:return false;
4330 }
4331 }
4332
4333 Cond_with_Var_flag_t keep_with_variations (hb_collect_feature_substitutes_with_var_context_t *c,
4334 hb_map_t *condition_map /* OUT */) const
4335 {
4336 switch (u.format.v) {
4337 case 1: hb_barrier (); return u.format1.keep_with_variations (c, condition_map);
4338 // TODO(subset)
4339 default: c->apply = false; return KEEP_COND_WITH_VAR;
4340 }
4341 }
4342
4343 template <typename context_t, typename ...Ts>
4344 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
4345 {
4346 if (unlikely (!c->may_dispatch (this, &u.format.v))__builtin_expect (bool(!c->may_dispatch (this, &u.format
.v)), 0)
) return c->no_dispatch_return_value ();
4347 TRACE_DISPATCH (this, u.format.v)hb_no_trace_t<typename context_t::return_t> trace;
4348 switch (u.format.v) {
4349 case 1: hb_barrier (); return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...))return trace.ret (c->dispatch (u.format1, std::forward<
Ts> (ds)...), __PRETTY_FUNCTION__, 4349)
;
4350 case 2: hb_barrier (); return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...))return trace.ret (c->dispatch (u.format2, std::forward<
Ts> (ds)...), __PRETTY_FUNCTION__, 4350)
;
4351 case 3: hb_barrier (); return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...))return trace.ret (c->dispatch (u.format3, std::forward<
Ts> (ds)...), __PRETTY_FUNCTION__, 4351)
;
4352 case 4: hb_barrier (); return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...))return trace.ret (c->dispatch (u.format4, std::forward<
Ts> (ds)...), __PRETTY_FUNCTION__, 4352)
;
4353 case 5: hb_barrier (); return_trace (c->dispatch (u.format5, std::forward<Ts> (ds)...))return trace.ret (c->dispatch (u.format5, std::forward<
Ts> (ds)...), __PRETTY_FUNCTION__, 4353)
;
4354 default:return_trace (c->default_return_value ())return trace.ret (c->default_return_value (), __PRETTY_FUNCTION__
, 4354)
;
4355 }
4356 }
4357
4358 bool sanitize (hb_sanitize_context_t *c) const
4359 {
4360 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
4361
4362 if (unlikely (!c->check_start_recursion (HB_MAX_NESTING_LEVEL))__builtin_expect (bool(!c->check_start_recursion (64)), 0))
4363 return_trace (c->no_dispatch_return_value ())return trace.ret (c->no_dispatch_return_value (), __PRETTY_FUNCTION__
, 4363)
;
4364
4365 return_trace (c->end_recursion (this->dispatch (c)))return trace.ret (c->end_recursion (this->dispatch (c))
, __PRETTY_FUNCTION__, 4365)
;
4366 }
4367
4368 protected:
4369 union {
4370 struct { HBUINT16 v; } format; /* Format identifier */
4371 ConditionAxisRange format1;
4372 ConditionValue format2;
4373 ConditionAnd format3;
4374 ConditionOr format4;
4375 ConditionNegate format5;
4376 } u;
4377 public:
4378 DEFINE_SIZE_UNION (2, format.v)void _compiles_assertion_on_line_4378 () const { (void) this->
u.format.v.static_size; } void _instance_assertion_on_line_4378
() const { static_assert ((sizeof(this->u.format.v) == (2
)), ""); } static constexpr unsigned null_size = (2); static constexpr
unsigned min_size = (2)
;
4379};
4380
4381template <typename Instancer>
4382bool
4383_hb_recurse_condition_evaluate (const struct Condition &condition,
4384 const int *coords,
4385 unsigned int coord_len,
4386 Instancer *instancer)
4387{
4388 return condition.evaluate (coords, coord_len, instancer);
4389}
4390
4391struct ConditionList
4392{
4393 const Condition& operator[] (unsigned i) const
4394 { return this+conditions[i]; }
4395
4396 bool sanitize (hb_sanitize_context_t *c) const
4397 {
4398 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
4399 return_trace (conditions.sanitize (c, this))return trace.ret (conditions.sanitize (c, this), __PRETTY_FUNCTION__
, 4399)
;
4400 }
4401
4402 protected:
4403 Array32OfOffset32To<Condition> conditions;
4404 public:
4405 DEFINE_SIZE_ARRAY (4, conditions)void _compiles_assertion_on_line_4405 () const { (void) (conditions
)[0].static_size; } void _instance_assertion_on_line_4405 () const
{ static_assert ((sizeof (*this) == (4) + (1 +0) * sizeof ((
conditions)[0])), ""); } static constexpr unsigned null_size =
(4); static constexpr unsigned min_size = (4)
;
4406};
4407
4408struct ConditionSet
4409{
4410 bool evaluate (const int *coords, unsigned int coord_len,
4411 ItemVarStoreInstancer *instancer) const
4412 {
4413 unsigned int count = conditions.len;
4414 for (unsigned int i = 0; i < count; i++)
4415 if (!(this+conditions.arrayZ[i]).evaluate (coords, coord_len, instancer))
4416 return false;
4417 return true;
4418 }
4419
4420 void keep_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const
4421 {
4422 hb_map_t *condition_map = hb_map_create ();
4423 if (unlikely (!condition_map)__builtin_expect (bool(!condition_map), 0)) return;
4424 hb::shared_ptr<hb_map_t> p {condition_map};
4425
4426 hb_set_t *cond_set = hb_set_create ();
4427 if (unlikely (!cond_set)__builtin_expect (bool(!cond_set), 0)) return;
4428 hb::shared_ptr<hb_set_t> s {cond_set};
4429
4430 c->apply = true;
4431 bool should_keep = false;
4432 unsigned num_kept_cond = 0, cond_idx = 0;
4433 for (const auto& offset : conditions)
4434 {
4435 Cond_with_Var_flag_t ret = (this+offset).keep_with_variations (c, condition_map);
4436 // condition is not met or condition out of range, drop the entire record
4437 if (ret == DROP_RECORD_WITH_VAR)
4438 return;
4439
4440 if (ret == KEEP_COND_WITH_VAR)
4441 {
4442 should_keep = true;
4443 cond_set->add (cond_idx);
4444 num_kept_cond++;
4445 }
4446
4447 if (ret == KEEP_RECORD_WITH_VAR)
4448 should_keep = true;
4449
4450 cond_idx++;
4451 }
4452
4453 if (!should_keep) return;
4454
4455 //check if condition_set is unique with variations
4456 if (c->conditionset_map->has (p))
4457 //duplicate found, drop the entire record
4458 return;
4459
4460 c->conditionset_map->set (p, 1);
4461 c->record_cond_idx_map->set (c->cur_record_idx, s);
4462 if (should_keep && num_kept_cond == 0)
4463 c->universal = true;
4464 }
4465
4466 bool subset (hb_subset_context_t *c,
4467 hb_subset_layout_context_t *l,
4468 bool insert_catch_all) const
4469 {
4470 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
4471 auto *out = c->serializer->start_embed (this);
4472 if (unlikely (!out || !c->serializer->extend_min (out))__builtin_expect (bool(!out || !c->serializer->extend_min
(out)), 0)
) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4472);
4473
4474 if (insert_catch_all) return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 4474);
4475
4476 hb_set_t *retained_cond_set = nullptr;
4477 if (l->feature_record_cond_idx_map != nullptr)
4478 retained_cond_set = l->feature_record_cond_idx_map->get (l->cur_feature_var_record_idx);
4479
4480 unsigned int count = conditions.len;
4481 for (unsigned int i = 0; i < count; i++)
4482 {
4483 if (retained_cond_set != nullptr && !retained_cond_set->has (i))
4484 continue;
4485 subset_offset_array (c, out->conditions, this) (conditions[i]);
4486 }
4487
4488 return_trace (bool (out->conditions))return trace.ret (bool (out->conditions), __PRETTY_FUNCTION__
, 4488)
;
4489 }
4490
4491 bool sanitize (hb_sanitize_context_t *c) const
4492 {
4493 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
4494 return_trace (conditions.sanitize (c, this))return trace.ret (conditions.sanitize (c, this), __PRETTY_FUNCTION__
, 4494)
;
4495 }
4496
4497 protected:
4498 Array16OfOffset32To<Condition> conditions;
4499 public:
4500 DEFINE_SIZE_ARRAY (2, conditions)void _compiles_assertion_on_line_4500 () const { (void) (conditions
)[0].static_size; } void _instance_assertion_on_line_4500 () const
{ static_assert ((sizeof (*this) == (2) + (1 +0) * sizeof ((
conditions)[0])), ""); } static constexpr unsigned null_size =
(2); static constexpr unsigned min_size = (2)
;
4501};
4502
4503struct FeatureTableSubstitutionRecord
4504{
4505 friend struct FeatureTableSubstitution;
4506
4507 void collect_lookups (const void *base, hb_set_t *lookup_indexes /* OUT */) const
4508 {
4509 return (base+feature).add_lookup_indexes_to (lookup_indexes);
4510 }
4511
4512 void closure_features (const void *base,
4513 const hb_map_t *lookup_indexes,
4514 hb_set_t *feature_indexes /* OUT */) const
4515 {
4516 if ((base+feature).intersects_lookup_indexes (lookup_indexes))
4517 feature_indexes->add (featureIndex);
4518 }
4519
4520 void collect_feature_substitutes_with_variations (hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
4521 hb_set_t& catch_all_record_feature_idxes,
4522 const hb_set_t *feature_indices,
4523 const void *base) const
4524 {
4525 if (feature_indices->has (featureIndex))
4526 {
4527 feature_substitutes_map->set (featureIndex, &(base+feature));
4528 catch_all_record_feature_idxes.add (featureIndex);
4529 }
4530 }
4531
4532 bool serialize (hb_subset_layout_context_t *c,
4533 unsigned feature_index,
4534 const Feature *f, const Tag *tag)
4535 {
4536 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
4537 hb_serialize_context_t *s = c->subset_context->serializer;
4538 if (unlikely (!s->extend_min (this))__builtin_expect (bool(!s->extend_min (this)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4538);
4539
4540 uint32_t *new_feature_idx;
4541 if (!c->feature_map_w_duplicates->has (feature_index, &new_feature_idx))
4542 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4542);
4543
4544 if (!s->check_assign (featureIndex, *new_feature_idx, HB_SERIALIZE_ERROR_INT_OVERFLOW))
4545 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4545);
4546
4547 s->push ();
4548 bool ret = f->subset (c->subset_context, c, tag);
4549 if (ret) s->add_link (feature, s->pop_pack ());
4550 else s->pop_discard ();
4551
4552 return_trace (ret)return trace.ret (ret, __PRETTY_FUNCTION__, 4552);
4553 }
4554
4555 bool subset (hb_subset_layout_context_t *c, const void *base) const
4556 {
4557 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
4558 uint32_t *new_feature_index;
4559 if (!c->feature_map_w_duplicates->has (featureIndex, &new_feature_index))
4560 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4560);
4561
4562 auto *out = c->subset_context->serializer->embed (this);
4563 if (unlikely (!out)__builtin_expect (bool(!out), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4563);
4564
4565 out->featureIndex = *new_feature_index;
4566 return_trace (out->feature.serialize_subset (c->subset_context, feature, base, c))return trace.ret (out->feature.serialize_subset (c->subset_context
, feature, base, c), __PRETTY_FUNCTION__, 4566)
;
4567 }
4568
4569 bool sanitize (hb_sanitize_context_t *c, const void *base) const
4570 {
4571 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
4572 return_trace (c->check_struct (this) && feature.sanitize (c, base))return trace.ret (c->check_struct (this) && feature
.sanitize (c, base), __PRETTY_FUNCTION__, 4572)
;
4573 }
4574
4575 protected:
4576 HBUINT16 featureIndex;
4577 Offset32To<Feature> feature;
4578 public:
4579 DEFINE_SIZE_STATIC (6)void _instance_assertion_on_line_4579 () const { static_assert
((sizeof (*this) == (6)), ""); } size_t get_size () const { return
(6); } static constexpr unsigned null_size = (6); static constexpr
unsigned min_size = (6); static constexpr unsigned static_size
= (6)
;
4580};
4581
4582struct FeatureTableSubstitution
4583{
4584 const Feature *find_substitute (unsigned int feature_index) const
4585 {
4586 unsigned int count = substitutions.len;
4587 for (unsigned int i = 0; i < count; i++)
4588 {
4589 const FeatureTableSubstitutionRecord &record = substitutions.arrayZ[i];
4590 if (record.featureIndex == feature_index)
4591 return &(this+record.feature);
4592 }
4593 return nullptr;
4594 }
4595
4596 void collect_lookups (const hb_set_t *feature_indexes,
4597 hb_set_t *lookup_indexes /* OUT */) const
4598 {
4599 + hb_iter (substitutions)
4600 | hb_filter (feature_indexes, &FeatureTableSubstitutionRecord::featureIndex)
4601 | hb_apply ([this, lookup_indexes] (const FeatureTableSubstitutionRecord& r)
4602 { r.collect_lookups (this, lookup_indexes); })
4603 ;
4604 }
4605
4606 void closure_features (const hb_map_t *lookup_indexes,
4607 hb_set_t *feature_indexes /* OUT */) const
4608 {
4609 for (const FeatureTableSubstitutionRecord& record : substitutions)
4610 record.closure_features (this, lookup_indexes, feature_indexes);
4611 }
4612
4613 bool intersects_features (const hb_map_t *feature_index_map) const
4614 {
4615 for (const FeatureTableSubstitutionRecord& record : substitutions)
4616 {
4617 if (feature_index_map->has (record.featureIndex)) return true;
4618 }
4619 return false;
4620 }
4621
4622 void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const
4623 {
4624 for (const FeatureTableSubstitutionRecord& record : substitutions)
4625 record.collect_feature_substitutes_with_variations (c->feature_substitutes_map,
4626 c->catch_all_record_feature_idxes,
4627 c->feature_indices, this);
4628 }
4629
4630 bool subset (hb_subset_context_t *c,
4631 hb_subset_layout_context_t *l,
4632 bool insert_catch_all) const
4633 {
4634 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
4635 auto *out = c->serializer->start_embed (*this);
4636 if (unlikely (!out || !c->serializer->extend_min (out))__builtin_expect (bool(!out || !c->serializer->extend_min
(out)), 0)
) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4636);
4637
4638 out->version.major = version.major;
4639 out->version.minor = version.minor;
4640
4641 if (insert_catch_all)
4642 {
4643 for (unsigned feature_index : *(l->catch_all_record_feature_idxes))
4644 {
4645 hb_pair_t<const void*, const void*> *p;
4646 if (!l->feature_idx_tag_map->has (feature_index, &p))
4647 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4647);
4648 auto *o = out->substitutions.serialize_append (c->serializer);
4649 if (!o->serialize (l, feature_index,
4650 reinterpret_cast<const Feature*> (p->first),
4651 reinterpret_cast<const Tag*> (p->second)))
4652 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4652);
4653 }
4654 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 4654);
4655 }
4656
4657 + substitutions.iter ()
4658 | hb_apply (subset_record_array (l, &(out->substitutions), this))
4659 ;
4660
4661 return_trace (bool (out->substitutions))return trace.ret (bool (out->substitutions), __PRETTY_FUNCTION__
, 4661)
;
4662 }
4663
4664 bool sanitize (hb_sanitize_context_t *c) const
4665 {
4666 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
4667 return_trace (version.sanitize (c) &&return trace.ret (version.sanitize (c) && hb_barrier (
) && __builtin_expect (bool(version.major == 1), 1) &&
substitutions.sanitize (c, this), __PRETTY_FUNCTION__, 4670)
4668 hb_barrier () &&return trace.ret (version.sanitize (c) && hb_barrier (
) && __builtin_expect (bool(version.major == 1), 1) &&
substitutions.sanitize (c, this), __PRETTY_FUNCTION__, 4670)
4669 likely (version.major == 1) &&return trace.ret (version.sanitize (c) && hb_barrier (
) && __builtin_expect (bool(version.major == 1), 1) &&
substitutions.sanitize (c, this), __PRETTY_FUNCTION__, 4670)
4670 substitutions.sanitize (c, this))return trace.ret (version.sanitize (c) && hb_barrier (
) && __builtin_expect (bool(version.major == 1), 1) &&
substitutions.sanitize (c, this), __PRETTY_FUNCTION__, 4670)
;
4671 }
4672
4673 protected:
4674 FixedVersion<> version; /* Version--0x00010000u */
4675 Array16Of<FeatureTableSubstitutionRecord>
4676 substitutions;
4677 public:
4678 DEFINE_SIZE_ARRAY (6, substitutions)void _compiles_assertion_on_line_4678 () const { (void) (substitutions
)[0].static_size; } void _instance_assertion_on_line_4678 () const
{ static_assert ((sizeof (*this) == (6) + (1 +0) * sizeof ((
substitutions)[0])), ""); } static constexpr unsigned null_size
= (6); static constexpr unsigned min_size = (6)
;
4679};
4680
4681struct FeatureVariationRecord
4682{
4683 friend struct FeatureVariations;
4684
4685 void collect_lookups (const void *base,
4686 const hb_set_t *feature_indexes,
4687 hb_set_t *lookup_indexes /* OUT */) const
4688 {
4689 return (base+substitutions).collect_lookups (feature_indexes, lookup_indexes);
4690 }
4691
4692 void closure_features (const void *base,
4693 const hb_map_t *lookup_indexes,
4694 hb_set_t *feature_indexes /* OUT */) const
4695 {
4696 (base+substitutions).closure_features (lookup_indexes, feature_indexes);
4697 }
4698
4699 bool intersects_features (const void *base, const hb_map_t *feature_index_map) const
4700 {
4701 return (base+substitutions).intersects_features (feature_index_map);
4702 }
4703
4704 void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c,
4705 const void *base) const
4706 {
4707 (base+conditions).keep_with_variations (c);
4708 if (c->apply && !c->variation_applied)
4709 {
4710 (base+substitutions).collect_feature_substitutes_with_variations (c);
4711 c->variation_applied = true; // set variations only once
4712 }
4713 }
4714
4715 bool subset (hb_subset_layout_context_t *c, const void *base,
4716 bool insert_catch_all = false) const
4717 {
4718 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
4719 auto *out = c->subset_context->serializer->embed (this);
4720 if (unlikely (!out)__builtin_expect (bool(!out), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4720);
4721
4722 out->conditions.serialize_subset (c->subset_context, conditions, base, c, insert_catch_all);
4723 out->substitutions.serialize_subset (c->subset_context, substitutions, base, c, insert_catch_all);
4724
4725 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 4725);
4726 }
4727
4728 bool sanitize (hb_sanitize_context_t *c, const void *base) const
4729 {
4730 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
4731 return_trace (conditions.sanitize (c, base) &&return trace.ret (conditions.sanitize (c, base) && substitutions
.sanitize (c, base), __PRETTY_FUNCTION__, 4732)
4732 substitutions.sanitize (c, base))return trace.ret (conditions.sanitize (c, base) && substitutions
.sanitize (c, base), __PRETTY_FUNCTION__, 4732)
;
4733 }
4734
4735 protected:
4736 Offset32To<ConditionSet>
4737 conditions;
4738 Offset32To<FeatureTableSubstitution>
4739 substitutions;
4740 public:
4741 DEFINE_SIZE_STATIC (8)void _instance_assertion_on_line_4741 () const { static_assert
((sizeof (*this) == (8)), ""); } size_t get_size () const { return
(8); } static constexpr unsigned null_size = (8); static constexpr
unsigned min_size = (8); static constexpr unsigned static_size
= (8)
;
4742};
4743
4744struct FeatureVariations
4745{
4746 static constexpr unsigned NOT_FOUND_INDEX = 0xFFFFFFFFu;
4747
4748 unsigned record_count () const
4749 {
4750 return varRecords.len;
4751 }
4752
4753 bool find_index (const int *coords, unsigned int coord_len,
4754 unsigned int *index,
4755 ItemVarStoreInstancer *instancer) const
4756 {
4757 unsigned int count = varRecords.len;
4758 for (unsigned int i = 0; i < count; i++)
4759 {
4760 const FeatureVariationRecord &record = varRecords.arrayZ[i];
4761 if ((this+record.conditions).evaluate (coords, coord_len, instancer))
4762 {
4763 *index = i;
4764 return true;
4765 }
4766 }
4767 *index = NOT_FOUND_INDEX;
4768 return false;
4769 }
4770
4771 const Feature *find_substitute (unsigned int variations_index,
4772 unsigned int feature_index) const
4773 {
4774 const FeatureVariationRecord &record = varRecords[variations_index];
4775 return (this+record.substitutions).find_substitute (feature_index);
4776 }
4777
4778 void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const
4779 {
4780 unsigned int count = varRecords.len;
4781 for (unsigned int i = 0; i < count; i++)
4782 {
4783 c->cur_record_idx = i;
4784 varRecords[i].collect_feature_substitutes_with_variations (c, this);
4785 if (c->universal)
4786 break;
4787 }
4788 if (c->universal || c->record_cond_idx_map->is_empty ())
4789 c->catch_all_record_feature_idxes.reset ();
4790 }
4791
4792 FeatureVariations* copy (hb_serialize_context_t *c) const
4793 {
4794 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
4795 return_trace (c->embed (*this))return trace.ret (c->embed (*this), __PRETTY_FUNCTION__, 4795
)
;
4796 }
4797
4798 void collect_lookups (const hb_set_t *feature_indexes,
4799 const hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map,
4800 hb_set_t *lookup_indexes /* OUT */) const
4801 {
4802 unsigned count = varRecords.len;
4803 for (unsigned int i = 0; i < count; i++)
4804 {
4805 if (feature_record_cond_idx_map &&
4806 !feature_record_cond_idx_map->has (i))
4807 continue;
4808 varRecords[i].collect_lookups (this, feature_indexes, lookup_indexes);
4809 }
4810 }
4811
4812 void closure_features (const hb_map_t *lookup_indexes,
4813 const hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map,
4814 hb_set_t *feature_indexes /* OUT */) const
4815 {
4816 unsigned int count = varRecords.len;
4817 for (unsigned int i = 0; i < count; i++)
4818 {
4819 if (feature_record_cond_idx_map != nullptr &&
4820 !feature_record_cond_idx_map->has (i))
4821 continue;
4822 varRecords[i].closure_features (this, lookup_indexes, feature_indexes);
4823 }
4824 }
4825
4826 bool subset (hb_subset_context_t *c,
4827 hb_subset_layout_context_t *l) const
4828 {
4829 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
4830 auto *out = c->serializer->start_embed (*this);
4831 if (unlikely (!out || !c->serializer->extend_min (out))__builtin_expect (bool(!out || !c->serializer->extend_min
(out)), 0)
) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4831);
4832
4833 out->version.major = version.major;
4834 out->version.minor = version.minor;
4835
4836 int keep_up_to = -1;
4837 for (int i = varRecords.len - 1; i >= 0; i--) {
4838 if (varRecords[i].intersects_features (this, l->feature_map_w_duplicates)) {
4839 keep_up_to = i;
4840 break;
4841 }
4842 }
4843
4844 unsigned count = (unsigned) (keep_up_to + 1);
4845 for (unsigned i = 0; i < count; i++)
4846 {
4847 if (l->feature_record_cond_idx_map != nullptr &&
4848 !l->feature_record_cond_idx_map->has (i))
4849 continue;
4850
4851 l->cur_feature_var_record_idx = i;
4852 subset_record_array (l, &(out->varRecords), this) (varRecords[i]);
4853 }
4854
4855 if (out->varRecords.len && !l->catch_all_record_feature_idxes->is_empty ())
4856 {
4857 bool insert_catch_all_record = true;
4858 subset_record_array (l, &(out->varRecords), this, insert_catch_all_record) (varRecords[0]);
4859 }
4860
4861 return_trace (bool (out->varRecords))return trace.ret (bool (out->varRecords), __PRETTY_FUNCTION__
, 4861)
;
4862 }
4863
4864 bool sanitize (hb_sanitize_context_t *c) const
4865 {
4866 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
4867 return_trace (version.sanitize (c) &&return trace.ret (version.sanitize (c) && hb_barrier (
) && __builtin_expect (bool(version.major == 1), 1) &&
varRecords.sanitize (c, this), __PRETTY_FUNCTION__, 4870)
4868 hb_barrier () &&return trace.ret (version.sanitize (c) && hb_barrier (
) && __builtin_expect (bool(version.major == 1), 1) &&
varRecords.sanitize (c, this), __PRETTY_FUNCTION__, 4870)
4869 likely (version.major == 1) &&return trace.ret (version.sanitize (c) && hb_barrier (
) && __builtin_expect (bool(version.major == 1), 1) &&
varRecords.sanitize (c, this), __PRETTY_FUNCTION__, 4870)
4870 varRecords.sanitize (c, this))return trace.ret (version.sanitize (c) && hb_barrier (
) && __builtin_expect (bool(version.major == 1), 1) &&
varRecords.sanitize (c, this), __PRETTY_FUNCTION__, 4870)
;
4871 }
4872
4873 protected:
4874 FixedVersion<> version; /* Version--0x00010000u */
4875 Array32Of<FeatureVariationRecord>
4876 varRecords;
4877 public:
4878 DEFINE_SIZE_ARRAY_SIZED (8, varRecords)size_t get_size () const { return (8 - (varRecords).min_size +
(varRecords).get_size ()); } void _compiles_assertion_on_line_4878
() const { (void) (varRecords)[0].static_size; } void _instance_assertion_on_line_4878
() const { static_assert ((sizeof (*this) == (8) + (1 +0) * sizeof
((varRecords)[0])), ""); } static constexpr unsigned null_size
= (8); static constexpr unsigned min_size = (8)
;
4879};
4880
4881
4882/*
4883 * Device Tables
4884 */
4885
4886struct HintingDevice
4887{
4888 friend struct Device;
4889
4890 private:
4891
4892 hb_position_t get_x_delta (hb_font_t *font) const
4893 { return get_delta (font->x_ppem, font->x_scale); }
4894
4895 hb_position_t get_y_delta (hb_font_t *font) const
4896 { return get_delta (font->y_ppem, font->y_scale); }
4897
4898 public:
4899
4900 size_t get_size () const
4901 {
4902 unsigned int f = deltaFormat;
4903 if (unlikely (f < 1 || f > 3 || startSize > endSize)__builtin_expect (bool(f < 1 || f > 3 || startSize >
endSize), 0)
) return 3 * HBUINT16::static_size;
4904 return HBUINT16::static_size * (4 + ((endSize - startSize) >> (4 - f)));
4905 }
4906
4907 bool sanitize (hb_sanitize_context_t *c) const
4908 {
4909 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
4910 return_trace (c->check_struct (this) && c->check_range (this, this->get_size ()))return trace.ret (c->check_struct (this) && c->
check_range (this, this->get_size ()), __PRETTY_FUNCTION__
, 4910)
;
4911 }
4912
4913 HintingDevice* copy (hb_serialize_context_t *c) const
4914 {
4915 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
4916 return_trace (c->embed<HintingDevice> (this))return trace.ret (c->embed<HintingDevice> (this), __PRETTY_FUNCTION__
, 4916)
;
4917 }
4918
4919 private:
4920
4921 int get_delta (unsigned int ppem, int scale) const
4922 {
4923 if (!ppem) return 0;
4924
4925 int pixels = get_delta_pixels (ppem);
4926
4927 if (!pixels) return 0;
4928
4929 return (int) (pixels * (int64_t) scale / ppem);
4930 }
4931 int get_delta_pixels (unsigned int ppem_size) const
4932 {
4933 unsigned int f = deltaFormat;
4934 if (unlikely (f < 1 || f > 3)__builtin_expect (bool(f < 1 || f > 3), 0))
4935 return 0;
4936
4937 if (ppem_size < startSize || ppem_size > endSize)
4938 return 0;
4939
4940 unsigned int s = ppem_size - startSize;
4941
4942 unsigned int byte = deltaValueZ[s >> (4 - f)];
4943 unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f)));
4944 unsigned int mask = (0xFFFFu >> (16 - (1 << f)));
4945
4946 int delta = bits & mask;
4947
4948 if ((unsigned int) delta >= ((mask + 1) >> 1))
4949 delta -= mask + 1;
4950
4951 return delta;
4952 }
4953
4954 protected:
4955 HBUINT16 startSize; /* Smallest size to correct--in ppem */
4956 HBUINT16 endSize; /* Largest size to correct--in ppem */
4957 HBUINT16 deltaFormat; /* Format of DeltaValue array data: 1, 2, or 3
4958 * 1 Signed 2-bit value, 8 values per uint16
4959 * 2 Signed 4-bit value, 4 values per uint16
4960 * 3 Signed 8-bit value, 2 values per uint16
4961 */
4962 UnsizedArrayOf<HBUINT16>
4963 deltaValueZ; /* Array of compressed data */
4964 public:
4965 DEFINE_SIZE_ARRAY (6, deltaValueZ)void _compiles_assertion_on_line_4965 () const { (void) (deltaValueZ
)[0].static_size; } void _instance_assertion_on_line_4965 () const
{ static_assert ((sizeof (*this) == (6) + (1 +0) * sizeof ((
deltaValueZ)[0])), ""); } static constexpr unsigned null_size
= (6); static constexpr unsigned min_size = (6)
;
4966};
4967
4968struct VariationDevice
4969{
4970 friend struct Device;
4971
4972 private:
4973
4974 hb_position_t get_x_delta (hb_font_t *font,
4975 const ItemVariationStore &store,
4976 hb_scalar_cache_t *store_cache = nullptr) const
4977 { return !font->has_nonzero_coords ? 0 : font->em_scalef_x (get_delta (font, store, store_cache)); }
4978
4979 hb_position_t get_y_delta (hb_font_t *font,
4980 const ItemVariationStore &store,
4981 hb_scalar_cache_t *store_cache = nullptr) const
4982 { return !font->has_nonzero_coords ? 0 : font->em_scalef_y (get_delta (font, store, store_cache)); }
4983
4984 VariationDevice* copy (hb_serialize_context_t *c,
4985 const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const
4986 {
4987 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
4988 if (!layout_variation_idx_delta_map) return_trace (nullptr)return trace.ret (nullptr, __PRETTY_FUNCTION__, 4988);
4989
4990 hb_pair_t<unsigned, int> *v;
4991 if (!layout_variation_idx_delta_map->has (varIdx, &v))
4992 return_trace (nullptr)return trace.ret (nullptr, __PRETTY_FUNCTION__, 4992);
4993
4994 c->start_zerocopy (this->static_size);
4995 auto *out = c->embed (this);
4996 if (unlikely (!out)__builtin_expect (bool(!out), 0)) return_trace (nullptr)return trace.ret (nullptr, __PRETTY_FUNCTION__, 4996);
4997
4998 if (!c->check_assign (out->varIdx, hb_first (*v), HB_SERIALIZE_ERROR_INT_OVERFLOW))
4999 return_trace (nullptr)return trace.ret (nullptr, __PRETTY_FUNCTION__, 4999);
5000 return_trace (out)return trace.ret (out, __PRETTY_FUNCTION__, 5000);
5001 }
5002
5003 void collect_variation_index (hb_collect_variation_indices_context_t *c) const
5004 { c->layout_variation_indices->add (varIdx); }
5005
5006 bool sanitize (hb_sanitize_context_t *c) const
5007 {
5008 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
5009 return_trace (c->check_struct (this))return trace.ret (c->check_struct (this), __PRETTY_FUNCTION__
, 5009)
;
5010 }
5011
5012 private:
5013
5014 float get_delta (hb_font_t *font,
5015 const ItemVariationStore &store,
5016 hb_scalar_cache_t *store_cache = nullptr) const
5017 {
5018 return store.get_delta (varIdx, font->coords, font->num_coords, store_cache);
5019 }
5020
5021 protected:
5022 VarIdx varIdx; /* Variation index */
5023 HBUINT16 deltaFormat; /* Format identifier for this table: 0x0x8000 */
5024 public:
5025 DEFINE_SIZE_STATIC (6)void _instance_assertion_on_line_5025 () const { static_assert
((sizeof (*this) == (6)), ""); } size_t get_size () const { return
(6); } static constexpr unsigned null_size = (6); static constexpr
unsigned min_size = (6); static constexpr unsigned static_size
= (6)
;
5026};
5027
5028struct DeviceHeader
5029{
5030 protected:
5031 HBUINT16 reserved1;
5032 HBUINT16 reserved2;
5033 public:
5034 HBUINT16 format; /* Format identifier */
5035 public:
5036 DEFINE_SIZE_STATIC (6)void _instance_assertion_on_line_5036 () const { static_assert
((sizeof (*this) == (6)), ""); } size_t get_size () const { return
(6); } static constexpr unsigned null_size = (6); static constexpr
unsigned min_size = (6); static constexpr unsigned static_size
= (6)
;
5037};
5038
5039struct Device
5040{
5041 hb_position_t get_x_delta (hb_font_t *font,
5042 const ItemVariationStore &store=Null (ItemVariationStore)NullHelper<ItemVariationStore>::get_null (),
5043 hb_scalar_cache_t *store_cache = nullptr) const
5044 {
5045 switch (u.b.format)
5046 {
5047#ifndef HB_NO_HINTING
5048 case 1: case 2: case 3:
5049 hb_barrier ();
5050 return u.hinting.get_x_delta (font);
5051#endif
5052#ifndef HB_NO_VAR
5053 case 0x8000:
5054 hb_barrier ();
5055 return u.variation.get_x_delta (font, store, store_cache);
5056#endif
5057 default:
5058 return 0;
5059 }
5060 }
5061 hb_position_t get_y_delta (hb_font_t *font,
5062 const ItemVariationStore &store=Null (ItemVariationStore)NullHelper<ItemVariationStore>::get_null (),
5063 hb_scalar_cache_t *store_cache = nullptr) const
5064 {
5065 switch (u.b.format)
5066 {
5067 case 1: case 2: case 3:
5068#ifndef HB_NO_HINTING
5069 hb_barrier ();
5070 return u.hinting.get_y_delta (font);
5071#endif
5072#ifndef HB_NO_VAR
5073 case 0x8000:
5074 hb_barrier ();
5075 return u.variation.get_y_delta (font, store, store_cache);
5076#endif
5077 default:
5078 return 0;
5079 }
5080 }
5081
5082 bool sanitize (hb_sanitize_context_t *c) const
5083 {
5084 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
5085 if (!u.b.format.sanitize (c)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 5085);
5086 switch (u.b.format) {
5087#ifndef HB_NO_HINTING
5088 case 1: case 2: case 3:
5089 hb_barrier ();
5090 return_trace (u.hinting.sanitize (c))return trace.ret (u.hinting.sanitize (c), __PRETTY_FUNCTION__
, 5090)
;
5091#endif
5092#ifndef HB_NO_VAR
5093 case 0x8000:
5094 hb_barrier ();
5095 return_trace (u.variation.sanitize (c))return trace.ret (u.variation.sanitize (c), __PRETTY_FUNCTION__
, 5095)
;
5096#endif
5097 default:
5098 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 5098);
5099 }
5100 }
5101
5102 Device* copy (hb_serialize_context_t *c,
5103 const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map=nullptr) const
5104 {
5105 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
5106 switch (u.b.format) {
5107#ifndef HB_NO_HINTING
5108 case 1:
5109 case 2:
5110 case 3:
5111 hb_barrier ();
5112 return_trace (reinterpret_cast<Device *> (u.hinting.copy (c)))return trace.ret (reinterpret_cast<Device *> (u.hinting
.copy (c)), __PRETTY_FUNCTION__, 5112)
;
5113#endif
5114#ifndef HB_NO_VAR
5115 case 0x8000:
5116 hb_barrier ();
5117 return_trace (reinterpret_cast<Device *> (u.variation.copy (c, layout_variation_idx_delta_map)))return trace.ret (reinterpret_cast<Device *> (u.variation
.copy (c, layout_variation_idx_delta_map)), __PRETTY_FUNCTION__
, 5117)
;
5118#endif
5119 default:
5120 return_trace (nullptr)return trace.ret (nullptr, __PRETTY_FUNCTION__, 5120);
5121 }
5122 }
5123
5124 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
5125 {
5126 switch (u.b.format) {
5127#ifndef HB_NO_HINTING
5128 case 1:
5129 case 2:
5130 case 3:
5131 return;
5132#endif
5133#ifndef HB_NO_VAR
5134 case 0x8000:
5135 hb_barrier ();
5136 u.variation.collect_variation_index (c);
5137 return;
5138#endif
5139 default:
5140 return;
5141 }
5142 }
5143
5144 unsigned get_variation_index () const
5145 {
5146 switch (u.b.format) {
5147#ifndef HB_NO_VAR
5148 case 0x8000:
5149 hb_barrier ();
5150 return u.variation.varIdx;
5151#endif
5152 default:
5153 return HB_OT_LAYOUT_NO_VARIATIONS_INDEX0xFFFFFFFFu;
5154 }
5155 }
5156
5157 bool is_variation_device () const
5158 {
5159 switch (u.b.format) {
5160#ifndef HB_NO_VAR
5161 case 0x8000:
5162 return true;
5163#endif
5164 default:
5165 return false;
5166 }
5167 }
5168
5169 protected:
5170 union {
5171 DeviceHeader b;
5172 HintingDevice hinting;
5173#ifndef HB_NO_VAR
5174 VariationDevice variation;
5175#endif
5176 } u;
5177 public:
5178 DEFINE_SIZE_UNION (6, b)void _compiles_assertion_on_line_5178 () const { (void) this->
u.b.static_size; } void _instance_assertion_on_line_5178 () const
{ static_assert ((sizeof(this->u.b) == (6)), ""); } static
constexpr unsigned null_size = (6); static constexpr unsigned
min_size = (6)
;
5179};
5180
5181
5182} /* namespace OT */
5183
5184
5185#endif /* HB_OT_LAYOUT_COMMON_HH */