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 4138, 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-10-17-231001-351276-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
1699 /* An empty ClassDef assigns class zero to every glyph, so every glyph in
1700 * `glyphs` intersects class zero. Handle it up front: `end_glyph` below
1701 * underflows when startGlyph is zero, and neither comparison can then be
1702 * true. */
1703 if (!classValue.len)
1704 {
1705 intersect_classes->add (0);
1706 return;
1707 }
1708
1709 hb_codepoint_t end_glyph = startGlyph + classValue.len - 1;
1710 if (glyphs->get_min () < startGlyph ||
1711 glyphs->get_max () > end_glyph)
1712 intersect_classes->add (0);
1713
1714 for (const auto& _ : + hb_enumerate (classValue))
1715 {
1716 hb_codepoint_t g = startGlyph + _.first;
1717 if (glyphs->has (g))
1718 intersect_classes->add (_.second);
1719 }
1720 }
1721
1722 protected:
1723 HBUINT16 classFormat; /* Format identifier--format = 1 */
1724 typename Types::HBGlyphID
1725 startGlyph; /* First GlyphID of the classValueArray */
1726 typename Types::template ArrayOf<HBUINT16>
1727 classValue; /* Array of Class Values--one per GlyphID */
1728 public:
1729 DEFINE_SIZE_ARRAY (2 + 2 * Types::size, classValue)void _compiles_assertion_on_line_1729 () const { (void) (classValue
)[0].static_size; } void _instance_assertion_on_line_1729 () 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)
;
1730};
1731
1732template <typename Types>
1733struct ClassDefFormat2_4
1734{
1735 friend struct ClassDef;
1736
1737 private:
1738 unsigned int get_class (hb_codepoint_t glyph_id) const
1739 {
1740 return rangeRecord.bsearch (glyph_id).value;
1741 }
1742
1743 unsigned get_population () const
1744 {
1745 typename Types::large_int ret = 0;
1746 for (const auto &r : rangeRecord)
1747 ret += r.get_population ();
1748 return ret > UINT_MAX(2147483647 *2U +1U) ? UINT_MAX(2147483647 *2U +1U) : (unsigned) ret;
1749 }
1750
1751 template<typename Iterator,
1752 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
>
1753 bool serialize (hb_serialize_context_t *c,
1754 Iterator it)
1755 {
1756 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
1757 if (unlikely (!c->extend_min (this))__builtin_expect (bool(!c->extend_min (this)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 1757);
1758
1759 if (unlikely (!it)__builtin_expect (bool(!it), 0))
1760 {
1761 classFormat = 2;
1762 rangeRecord.len = 0;
1763 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 1763);
1764 }
1765
1766 unsigned unsorted = false;
1767 unsigned num_ranges = 1;
1768 hb_codepoint_t prev_gid = (*it).first;
1769 unsigned prev_klass = (*it).second;
1770
1771 RangeRecord<Types> range_rec;
1772 range_rec.first = prev_gid;
1773 range_rec.last = prev_gid;
1774 range_rec.value = prev_klass;
1775
1776 auto *record = c->copy (range_rec);
1777 if (unlikely (!record)__builtin_expect (bool(!record), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 1777);
1778
1779 for (const auto gid_klass_pair : + (++it))
1780 {
1781 hb_codepoint_t cur_gid = gid_klass_pair.first;
1782 unsigned cur_klass = gid_klass_pair.second;
1783
1784 if (cur_gid != prev_gid + 1 ||
1785 cur_klass != prev_klass)
1786 {
1787
1788 if (unlikely (cur_gid < prev_gid)__builtin_expect (bool(cur_gid < prev_gid), 0))
1789 unsorted = true;
1790
1791 if (unlikely (!record)__builtin_expect (bool(!record), 0)) break;
1792 record->last = prev_gid;
1793 num_ranges++;
1794
1795 range_rec.first = cur_gid;
1796 range_rec.last = cur_gid;
1797 range_rec.value = cur_klass;
1798
1799 record = c->copy (range_rec);
1800 }
1801
1802 prev_klass = cur_klass;
1803 prev_gid = cur_gid;
1804 }
1805
1806 if (unlikely (c->in_error ())__builtin_expect (bool(c->in_error ()), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 1806);
1807
1808 if (likely (record)__builtin_expect (bool(record), 1)) record->last = prev_gid;
1809 rangeRecord.len = num_ranges;
1810
1811 if (unlikely (unsorted)__builtin_expect (bool(unsorted), 0))
1812 rangeRecord.as_array ().qsort (RangeRecord<Types>::cmp_range);
1813
1814 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 1814);
1815 }
1816
1817 bool subset (hb_subset_context_t *c,
1818 hb_map_t *klass_map = nullptr /*OUT*/,
1819 bool keep_empty_table = true,
1820 bool use_class_zero = true,
1821 const Coverage* glyph_filter = nullptr) const
1822 {
1823 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
1824 const hb_set_t &glyph_set = *c->plan->glyphset_gsub ();
1825
1826 hb_sorted_vector_t<hb_codepoint_pair_t> glyph_and_klass;
1827 hb_set_t orig_klasses;
1828
1829 if (glyph_set.get_population () * hb_bit_storage ((unsigned) rangeRecord.len)
1830 < get_population ())
1831 {
1832 for (hb_codepoint_t g : glyph_set)
1833 {
1834 unsigned klass = get_class (g);
1835 if (!klass) continue;
1836 hb_codepoint_t new_gid = c->plan->map_gsub_glyph (g);
1837 if (new_gid == HB_MAP_VALUE_INVALID((hb_codepoint_t) -1)) continue;
1838 if (glyph_filter && !glyph_filter->has (g)) continue;
1839 glyph_and_klass.push (hb_pair (new_gid, klass));
1840 orig_klasses.add (klass);
1841 }
1842 }
1843 else
1844 {
1845 unsigned num_source_glyphs = c->plan->source->get_num_glyphs ();
1846 for (auto &range : rangeRecord)
1847 {
1848 unsigned klass = range.value;
1849 if (!klass) continue;
1850 hb_codepoint_t start = range.first;
1851 hb_codepoint_t end = hb_min (range.last + 1, num_source_glyphs);
1852 for (hb_codepoint_t g = start; g < end; g++)
1853 {
1854 hb_codepoint_t new_gid = c->plan->map_gsub_glyph (g);
1855 if (new_gid == HB_MAP_VALUE_INVALID((hb_codepoint_t) -1)) continue;
1856 if (glyph_filter && !glyph_filter->has (g)) continue;
1857
1858 glyph_and_klass.push (hb_pair (new_gid, klass));
1859 orig_klasses.add (klass);
1860 }
1861 }
1862 }
1863
1864 const hb_set_t& glyphset = *c->plan->glyphset_gsub ();
1865 unsigned glyph_count = glyph_filter
1866 ? hb_len (hb_iter (glyphset) | hb_filter (glyph_filter))
1867 : glyphset.get_population ();
1868 use_class_zero = use_class_zero && glyph_count <= glyph_and_klass.length;
1869 if (!ClassDef_remap_and_serialize (c->serializer,
1870 orig_klasses,
1871 use_class_zero,
1872 glyph_and_klass,
1873 klass_map))
1874 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 1874);
1875 return_trace (keep_empty_table || (bool) glyph_and_klass)return trace.ret (keep_empty_table || (bool) glyph_and_klass,
__PRETTY_FUNCTION__, 1875)
;
1876 }
1877
1878 bool sanitize (hb_sanitize_context_t *c) const
1879 {
1880 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
1881 return_trace (rangeRecord.sanitize (c))return trace.ret (rangeRecord.sanitize (c), __PRETTY_FUNCTION__
, 1881)
;
1882 }
1883
1884 unsigned cost () const { return hb_bit_storage ((unsigned) rangeRecord.len); /* bsearch cost */ }
1885
1886 template <typename set_t>
1887 bool collect_coverage (set_t *glyphs) const
1888 {
1889 for (auto &range : rangeRecord)
1890 if (range.value)
1891 if (unlikely (!range.collect_coverage (glyphs))__builtin_expect (bool(!range.collect_coverage (glyphs)), 0))
1892 return false;
1893 return true;
1894 }
1895
1896 template <typename set_t>
1897 bool collect_class (set_t *glyphs, unsigned int klass) const
1898 {
1899 for (auto &range : rangeRecord)
1900 {
1901 if (range.value == klass)
1902 if (unlikely (!range.collect_coverage (glyphs))__builtin_expect (bool(!range.collect_coverage (glyphs)), 0))
1903 return false;
1904 }
1905 return true;
1906 }
1907
1908 bool intersects (const hb_set_t *glyphs) const
1909 {
1910 if (rangeRecord.len > glyphs->get_population () * hb_bit_storage ((unsigned) rangeRecord.len))
1911 {
1912 for (auto g : *glyphs)
1913 if (get_class (g))
1914 return true;
1915 return false;
1916 }
1917
1918 return hb_any (+ hb_iter (rangeRecord)
1919 | hb_map ([glyphs] (const RangeRecord<Types> &range) { return range.intersects (*glyphs) && range.value; }));
1920 }
1921 bool intersects_class (const hb_set_t *glyphs, uint16_t klass) const
1922 {
1923 if (klass == 0)
1924 {
1925 /* An empty ClassDef assigns class zero to every glyph, so it intersects
1926 * class zero as long as there is any glyph at all. The loop below is a
1927 * no-op when there are no ranges, and the `g != HB_SET_VALUE_INVALID`
1928 * guard after it would then wrongly report no intersection. */
1929 if (!rangeRecord.len)
1930 return !glyphs->is_empty ();
1931
1932 /* Match if there's any glyph that is not listed! */
1933 hb_codepoint_t g = HB_SET_VALUE_INVALID((hb_codepoint_t) -1);
1934 hb_codepoint_t last = HB_SET_VALUE_INVALID((hb_codepoint_t) -1);
1935 auto it = hb_iter (rangeRecord);
1936 for (auto &range : it)
1937 {
1938 if (it->first == last + 1)
1939 {
1940 it++;
1941 continue;
1942 }
1943
1944 if (!glyphs->next (&g))
1945 break;
1946 if (g < range.first)
1947 return true;
1948 g = range.last;
1949 last = g;
1950 }
1951 if (g != HB_SET_VALUE_INVALID((hb_codepoint_t) -1) && glyphs->next (&g))
1952 return true;
1953 /* Fall through. */
1954 }
1955 for (const auto &range : rangeRecord)
1956 if (range.value == klass && range.intersects (*glyphs))
1957 return true;
1958 return false;
1959 }
1960
1961 void intersected_class_glyphs (const hb_set_t *glyphs, unsigned klass, hb_set_t *intersect_glyphs) const
1962 {
1963 if (klass == 0)
1964 {
1965 hb_codepoint_t g = HB_SET_VALUE_INVALID((hb_codepoint_t) -1);
1966 for (auto &range : rangeRecord)
1967 {
1968 if (!glyphs->next (&g))
1969 goto done;
1970 while (g < range.first)
1971 {
1972 intersect_glyphs->add (g);
1973 if (!glyphs->next (&g))
1974 goto done;
1975 }
1976 g = range.last;
1977 }
1978 while (glyphs->next (&g))
1979 intersect_glyphs->add (g);
1980 done:
1981
1982 return;
1983 }
1984
1985 unsigned count = rangeRecord.len;
1986 if (count > glyphs->get_population () * hb_bit_storage (count))
1987 {
1988 for (auto g : *glyphs)
1989 {
1990 unsigned i;
1991 if (rangeRecord.as_array ().bfind (g, &i) &&
1992 rangeRecord.arrayZ[i].value == klass)
1993 intersect_glyphs->add (g);
1994 }
1995 return;
1996 }
1997
1998 for (auto &range : rangeRecord)
1999 {
2000 if (range.value != klass) continue;
2001
2002 unsigned end = range.last + 1;
2003 for (hb_codepoint_t g = range.first - 1;
2004 glyphs->next (&g) && g < end;)
2005 intersect_glyphs->add (g);
2006 }
2007 }
2008
2009 void intersected_classes (const hb_set_t *glyphs, hb_set_t *intersect_classes) const
2010 {
2011 if (glyphs->is_empty ()) return;
2012
2013 /* An empty ClassDef assigns class zero to every glyph, so every glyph in
2014 * `glyphs` intersects class zero. Handle it up front: the loops below are
2015 * no-ops when there are no ranges, and the `g != HB_SET_VALUE_INVALID`
2016 * guard would then wrongly skip adding class zero. */
2017 if (!rangeRecord.len)
2018 {
2019 intersect_classes->add (0);
2020 return;
2021 }
2022
2023 hb_codepoint_t g = HB_SET_VALUE_INVALID((hb_codepoint_t) -1);
2024 for (auto &range : rangeRecord)
2025 {
2026 if (!glyphs->next (&g))
2027 break;
2028 if (g < range.first)
2029 {
2030 intersect_classes->add (0);
2031 break;
2032 }
2033 g = range.last;
2034 }
2035 if (g != HB_SET_VALUE_INVALID((hb_codepoint_t) -1) && glyphs->next (&g))
2036 intersect_classes->add (0);
2037
2038 for (const auto& range : rangeRecord)
2039 if (range.intersects (*glyphs))
2040 intersect_classes->add (range.value);
2041 }
2042
2043 protected:
2044 HBUINT16 classFormat; /* Format identifier--format = 2 */
2045 typename Types::template SortedArrayOf<RangeRecord<Types>>
2046 rangeRecord; /* Array of glyph ranges--ordered by
2047 * Start GlyphID */
2048 public:
2049 DEFINE_SIZE_ARRAY (2 + Types::size, rangeRecord)void _compiles_assertion_on_line_2049 () const { (void) (rangeRecord
)[0].static_size; } void _instance_assertion_on_line_2049 () 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)
;
2050};
2051
2052struct ClassDef
2053{
2054 /* Has interface. */
2055 unsigned operator [] (hb_codepoint_t k) const { return get (k); }
2056 bool has (hb_codepoint_t k) const { return (*this)[k]; }
2057 /* Projection. */
2058 hb_codepoint_t operator () (hb_codepoint_t k) const { return get (k); }
2059
2060 unsigned int get (hb_codepoint_t k) const { return get_class (k); }
2061 unsigned int get_class (hb_codepoint_t glyph_id) const
2062 {
2063 switch (u.format.v) {
2064 case 1: hb_barrier (); return u.format1.get_class (glyph_id);
2065 case 2: hb_barrier (); return u.format2.get_class (glyph_id);
2066#ifndef HB_NO_BEYOND_64K
2067 case 3: hb_barrier (); return u.format3.get_class (glyph_id);
2068 case 4: hb_barrier (); return u.format4.get_class (glyph_id);
2069#endif
2070 default:return 0;
2071 }
2072 }
2073 unsigned int get_class (hb_codepoint_t glyph_id,
2074 hb_ot_layout_mapping_cache_t *cache) const
2075 {
2076 unsigned klass;
2077 if (cache && cache->get (glyph_id, &klass)) return klass;
2078 klass = get_class (glyph_id);
2079 if (cache) cache->set (glyph_id, klass);
2080 return klass;
2081 }
2082
2083 unsigned get_population () const
2084 {
2085 switch (u.format.v) {
2086 case 1: hb_barrier (); return u.format1.get_population ();
2087 case 2: hb_barrier (); return u.format2.get_population ();
2088#ifndef HB_NO_BEYOND_64K
2089 case 3: hb_barrier (); return u.format3.get_population ();
2090 case 4: hb_barrier (); return u.format4.get_population ();
2091#endif
2092 default:return NOT_COVERED((unsigned int) -1);
2093 }
2094 }
2095
2096 template<typename Iterator,
2097 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
>
2098 bool serialize (hb_serialize_context_t *c, Iterator it_with_class_zero)
2099 {
2100 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
2101 if (unlikely (!c->extend_min (this))__builtin_expect (bool(!c->extend_min (this)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 2101);
2102
2103 auto it = + it_with_class_zero | hb_filter (hb_second);
2104
2105 unsigned format = 2;
2106 hb_codepoint_t glyph_max = 0;
2107 if (likely (it)__builtin_expect (bool(it), 1))
2108 {
2109 hb_codepoint_t glyph_min = (*it).first;
2110 glyph_max = glyph_min;
2111
2112 unsigned num_glyphs = 0;
2113 unsigned num_ranges = 1;
2114 hb_codepoint_t prev_gid = glyph_min;
2115 unsigned prev_klass = (*it).second;
2116
2117 for (const auto gid_klass_pair : it)
2118 {
2119 hb_codepoint_t cur_gid = gid_klass_pair.first;
2120 unsigned cur_klass = gid_klass_pair.second;
2121 num_glyphs++;
2122 if (cur_gid == glyph_min) continue;
2123 if (cur_gid > glyph_max) glyph_max = cur_gid;
2124 if (cur_gid != prev_gid + 1 ||
2125 cur_klass != prev_klass)
2126 num_ranges++;
2127
2128 prev_gid = cur_gid;
2129 prev_klass = cur_klass;
2130 }
2131
2132 if (num_glyphs && 1 + (glyph_max - glyph_min + 1) <= num_ranges * 3)
2133 format = 1;
2134 }
2135
2136#ifndef HB_NO_BEYOND_64K
2137 if (glyph_max > 0xFFFFu)
2138 u.format.v += 2;
2139 if (unlikely (glyph_max > 0xFFFFFFu)__builtin_expect (bool(glyph_max > 0xFFFFFFu), 0))
2140#else
2141 if (unlikely (glyph_max > 0xFFFFu)__builtin_expect (bool(glyph_max > 0xFFFFu), 0))
2142#endif
2143 {
2144 c->check_success (false, HB_SERIALIZE_ERROR_INT_OVERFLOW);
2145 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 2145);
2146 }
2147
2148 u.format.v = format;
2149
2150 switch (u.format.v)
2151 {
2152 case 1: hb_barrier (); return_trace (u.format1.serialize (c, it))return trace.ret (u.format1.serialize (c, it), __PRETTY_FUNCTION__
, 2152)
;
2153 case 2: hb_barrier (); return_trace (u.format2.serialize (c, it))return trace.ret (u.format2.serialize (c, it), __PRETTY_FUNCTION__
, 2153)
;
2154#ifndef HB_NO_BEYOND_64K
2155 case 3: hb_barrier (); return_trace (u.format3.serialize (c, it))return trace.ret (u.format3.serialize (c, it), __PRETTY_FUNCTION__
, 2155)
;
2156 case 4: hb_barrier (); return_trace (u.format4.serialize (c, it))return trace.ret (u.format4.serialize (c, it), __PRETTY_FUNCTION__
, 2156)
;
2157#endif
2158 default:return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 2158);
2159 }
2160 }
2161
2162 bool subset (hb_subset_context_t *c,
2163 hb_map_t *klass_map = nullptr /*OUT*/,
2164 bool keep_empty_table = true,
2165 bool use_class_zero = true,
2166 const Coverage* glyph_filter = nullptr) const
2167 {
2168 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
2169 switch (u.format.v) {
2170 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__, 2170)
;
2171 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__, 2171)
;
2172#ifndef HB_NO_BEYOND_64K
2173 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__, 2173)
;
2174 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__, 2174)
;
2175#endif
2176 default:return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 2176);
2177 }
2178 }
2179
2180 bool sanitize (hb_sanitize_context_t *c) const
2181 {
2182 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
2183 if (!u.format.v.sanitize (c)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 2183);
2184 hb_barrier ();
2185 switch (u.format.v) {
2186 case 1: hb_barrier (); return_trace (u.format1.sanitize (c))return trace.ret (u.format1.sanitize (c), __PRETTY_FUNCTION__
, 2186)
;
2187 case 2: hb_barrier (); return_trace (u.format2.sanitize (c))return trace.ret (u.format2.sanitize (c), __PRETTY_FUNCTION__
, 2187)
;
2188#ifndef HB_NO_BEYOND_64K
2189 case 3: hb_barrier (); return_trace (u.format3.sanitize (c))return trace.ret (u.format3.sanitize (c), __PRETTY_FUNCTION__
, 2189)
;
2190 case 4: hb_barrier (); return_trace (u.format4.sanitize (c))return trace.ret (u.format4.sanitize (c), __PRETTY_FUNCTION__
, 2190)
;
2191#endif
2192 default:return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 2192);
2193 }
2194 }
2195
2196 unsigned cost () const
2197 {
2198 switch (u.format.v) {
2199 case 1: hb_barrier (); return u.format1.cost ();
2200 case 2: hb_barrier (); return u.format2.cost ();
2201#ifndef HB_NO_BEYOND_64K
2202 case 3: hb_barrier (); return u.format3.cost ();
2203 case 4: hb_barrier (); return u.format4.cost ();
2204#endif
2205 default:return 0u;
2206 }
2207 }
2208
2209 /* Might return false if array looks unsorted.
2210 * Used for faster rejection of corrupt data. */
2211 template <typename set_t>
2212 bool collect_coverage (set_t *glyphs) const
2213 {
2214 switch (u.format.v) {
2215 case 1: hb_barrier (); return u.format1.collect_coverage (glyphs);
2216 case 2: hb_barrier (); return u.format2.collect_coverage (glyphs);
2217#ifndef HB_NO_BEYOND_64K
2218 case 3: hb_barrier (); return u.format3.collect_coverage (glyphs);
2219 case 4: hb_barrier (); return u.format4.collect_coverage (glyphs);
2220#endif
2221 default:return false;
2222 }
2223 }
2224
2225 /* Might return false if array looks unsorted.
2226 * Used for faster rejection of corrupt data. */
2227 template <typename set_t>
2228 bool collect_class (set_t *glyphs, unsigned int klass) const
2229 {
2230 switch (u.format.v) {
2231 case 1: hb_barrier (); return u.format1.collect_class (glyphs, klass);
2232 case 2: hb_barrier (); return u.format2.collect_class (glyphs, klass);
2233#ifndef HB_NO_BEYOND_64K
2234 case 3: hb_barrier (); return u.format3.collect_class (glyphs, klass);
2235 case 4: hb_barrier (); return u.format4.collect_class (glyphs, klass);
2236#endif
2237 default:return false;
2238 }
2239 }
2240
2241 bool intersects (const hb_set_t *glyphs) const
2242 {
2243 switch (u.format.v) {
2244 case 1: hb_barrier (); return u.format1.intersects (glyphs);
2245 case 2: hb_barrier (); return u.format2.intersects (glyphs);
2246#ifndef HB_NO_BEYOND_64K
2247 case 3: hb_barrier (); return u.format3.intersects (glyphs);
2248 case 4: hb_barrier (); return u.format4.intersects (glyphs);
2249#endif
2250 default:return false;
2251 }
2252 }
2253 bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const
2254 {
2255 switch (u.format.v) {
2256 case 1: hb_barrier (); return u.format1.intersects_class (glyphs, klass);
2257 case 2: hb_barrier (); return u.format2.intersects_class (glyphs, klass);
2258#ifndef HB_NO_BEYOND_64K
2259 case 3: hb_barrier (); return u.format3.intersects_class (glyphs, klass);
2260 case 4: hb_barrier (); return u.format4.intersects_class (glyphs, klass);
2261#endif
2262 default:return false;
2263 }
2264 }
2265
2266 void intersected_class_glyphs (const hb_set_t *glyphs, unsigned klass, hb_set_t *intersect_glyphs) const
2267 {
2268 switch (u.format.v) {
2269 case 1: hb_barrier (); return u.format1.intersected_class_glyphs (glyphs, klass, intersect_glyphs);
2270 case 2: hb_barrier (); return u.format2.intersected_class_glyphs (glyphs, klass, intersect_glyphs);
2271#ifndef HB_NO_BEYOND_64K
2272 case 3: hb_barrier (); return u.format3.intersected_class_glyphs (glyphs, klass, intersect_glyphs);
2273 case 4: hb_barrier (); return u.format4.intersected_class_glyphs (glyphs, klass, intersect_glyphs);
2274#endif
2275 default:return;
2276 }
2277 }
2278
2279 void intersected_classes (const hb_set_t *glyphs, hb_set_t *intersect_classes) const
2280 {
2281 switch (u.format.v) {
2282 case 1: hb_barrier (); return u.format1.intersected_classes (glyphs, intersect_classes);
2283 case 2: hb_barrier (); return u.format2.intersected_classes (glyphs, intersect_classes);
2284#ifndef HB_NO_BEYOND_64K
2285 case 3: hb_barrier (); return u.format3.intersected_classes (glyphs, intersect_classes);
2286 case 4: hb_barrier (); return u.format4.intersected_classes (glyphs, intersect_classes);
2287#endif
2288 default:return;
2289 }
2290 }
2291
2292
2293 protected:
2294 union {
2295 struct { HBUINT16 v; } format; /* Format identifier */
2296 ClassDefFormat1_3<SmallTypes> format1;
2297 ClassDefFormat2_4<SmallTypes> format2;
2298#ifndef HB_NO_BEYOND_64K
2299 ClassDefFormat1_3<MediumTypes>format3;
2300 ClassDefFormat2_4<MediumTypes>format4;
2301#endif
2302 } u;
2303 public:
2304 DEFINE_SIZE_UNION (2, format.v)void _compiles_assertion_on_line_2304 () const { (void) this->
u.format.v.static_size; } void _instance_assertion_on_line_2304
() const { static_assert ((sizeof(this->u.format.v) == (2
)), ""); } static constexpr unsigned null_size = (2); static constexpr
unsigned min_size = (2)
;
2305};
2306
2307template<typename Iterator>
2308static inline bool ClassDef_serialize (hb_serialize_context_t *c,
2309 Iterator it)
2310{ return (c->start_embed<ClassDef> ()->serialize (c, it)); }
2311
2312
2313/*
2314 * Item Variation Store
2315 */
2316
2317/* ported from fonttools (class _Encoding) */
2318struct delta_row_encoding_t
2319{
2320 /* each byte represents a region, value is one of 0/1/2/4, which means bytes
2321 * needed for this region */
2322 struct chars_t : hb_vector_t<uint8_t>
2323 {
2324 int cmp (const chars_t& other) const
2325 {
2326 return as_array ().cmp (other.as_array ());
2327 }
2328
2329 hb_pair_t<unsigned, unsigned> get_width ()
2330 {
2331 unsigned width = 0;
2332 unsigned columns = 0;
2333 for (unsigned i = 0; i < length; i++)
2334 {
2335 unsigned v = arrayZ[i];
2336 width += v;
2337 columns += (v != 0);
2338 }
2339 return hb_pair (width, columns);
2340 }
2341
2342 HB_HOT__attribute__((hot))
2343 hb_pair_t<unsigned, unsigned> combine_width (const chars_t& other) const
2344 {
2345 unsigned combined_width = 0;
2346 unsigned combined_columns = 0;
2347 for (unsigned i = 0; i < length; i++)
2348 {
2349 unsigned v = hb_max (arrayZ[i], other.arrayZ[i]);
2350 combined_width += v;
2351 combined_columns += (v != 0);
2352 }
2353 return hb_pair (combined_width, combined_columns);
2354 }
2355 };
2356
2357 hb_pair_t<unsigned, unsigned> combine_width (const delta_row_encoding_t& other_encoding) const { return chars.combine_width (other_encoding.chars); }
2358
2359 // Actual data
2360
2361 chars_t chars;
2362 unsigned width = 0;
2363 unsigned overhead = 0;
2364 hb_vector_t<const hb_vector_t<int>*> items;
2365
2366 delta_row_encoding_t () = default;
2367 delta_row_encoding_t (hb_vector_t<const hb_vector_t<int>*> &&rows, unsigned num_cols)
2368 {
2369 assert (rows)(static_cast <bool> (rows) ? void (0) : __assert_fail (
"rows", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2370
2371 items = std::move (rows);
2372
2373 if (unlikely (!chars.resize (num_cols))__builtin_expect (bool(!chars.resize (num_cols)), 0))
2374 return;
2375
2376 calculate_chars ();
2377 }
2378
2379 void merge (const delta_row_encoding_t& other)
2380 {
2381 items.alloc (items.length + other.items.length);
2382 for (auto &row : other.items)
2383 add_row (row);
2384
2385 // Merge chars
2386 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__
))
;
2387 for (unsigned i = 0; i < chars.length; i++)
2388 chars.arrayZ[i] = hb_max (chars.arrayZ[i], other.chars.arrayZ[i]);
2389 chars_changed ();
2390 }
2391
2392 void chars_changed ()
2393 {
2394 auto _ = chars.get_width ();
2395 width = _.first;
2396 overhead = get_chars_overhead (_.second);
2397 }
2398
2399 void calculate_chars ()
2400 {
2401 assert (items)(static_cast <bool> (items) ? void (0) : __assert_fail (
"items", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2402
2403 bool long_words = false;
2404
2405 for (auto &row : items)
2406 {
2407 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__))
;
2408
2409 /* 0/1/2 byte encoding */
2410 for (unsigned i = 0; i < row->length; i++)
2411 {
2412 int v = row->arrayZ[i];
2413 if (v == 0)
2414 continue;
2415 else if (v > 32767 || v < -32768)
2416 {
2417 long_words = true;
2418 chars.arrayZ[i] = hb_max (chars.arrayZ[i], 4);
2419 }
2420 else if (v > 127 || v < -128)
2421 chars.arrayZ[i] = hb_max (chars.arrayZ[i], 2);
2422 else
2423 chars.arrayZ[i] = hb_max (chars.arrayZ[i], 1);
2424 }
2425 }
2426
2427 if (long_words)
2428 {
2429 // Convert 1s to 2s
2430 for (auto &v : chars)
2431 if (v == 1)
2432 v = 2;
2433 }
2434
2435 chars_changed ();
2436 }
2437
2438 bool is_empty () const
2439 { return !items; }
2440
2441 static inline unsigned get_chars_overhead (unsigned num_columns)
2442 {
2443 unsigned c = 4 + 6; // 4 bytes for LOffset, 6 bytes for VarData header
2444 return c + num_columns * 2;
2445 }
2446
2447 unsigned get_gain (unsigned additional_bytes_per_rows = 1) const
2448 {
2449 int count = items.length;
2450 return hb_max (0, (int) overhead - count * (int) additional_bytes_per_rows);
2451 }
2452
2453 int gain_from_merging (const delta_row_encoding_t& other_encoding) const
2454 {
2455 // Back of the envelope calculations to reject early.
2456 signed additional_bytes_per_rows = other_encoding.width - width;
2457 if (additional_bytes_per_rows > 0)
2458 {
2459 if (get_gain (additional_bytes_per_rows) == 0)
2460 return 0;
2461 }
2462 else
2463 {
2464 if (other_encoding.get_gain (-additional_bytes_per_rows) == 0)
2465 return 0;
2466 }
2467
2468 auto pair = combine_width (other_encoding);
2469 unsigned combined_width = pair.first;
2470 unsigned combined_columns = pair.second;
2471
2472 int combined_gain = (int) overhead + (int) other_encoding.overhead;
2473 combined_gain -= (combined_width - (int) width) * items.length;
2474 combined_gain -= (combined_width - (int) other_encoding.width) * other_encoding.items.length;
2475 combined_gain -= get_chars_overhead (combined_columns);
2476
2477 return combined_gain;
2478 }
2479
2480 bool add_row (const hb_vector_t<int>* row)
2481 { return items.push (row); }
2482
2483 static int cmp (const void *pa, const void *pb)
2484 {
2485 const delta_row_encoding_t *a = (const delta_row_encoding_t *)pa;
2486 const delta_row_encoding_t *b = (const delta_row_encoding_t *)pb;
2487
2488 if (a->width != b->width)
2489 return (int) a->width - (int) b->width;
2490
2491 return b->chars.cmp (a->chars);
2492 }
2493};
2494
2495struct VarRegionAxis
2496{
2497 float evaluate (int coord) const
2498 {
2499 int peak = peakCoord.to_int ();
2500 if (peak == 0 || coord == peak)
2501 return 1.f;
2502 else if (coord == 0) // Faster
2503 return 0.f;
2504
2505 int start = startCoord.to_int (), end = endCoord.to_int ();
2506
2507 /* TODO Move these to sanitize(). */
2508 if (unlikely (start > peak || peak > end)__builtin_expect (bool(start > peak || peak > end), 0))
2509 return 1.f;
2510 if (unlikely (start < 0 && end > 0)__builtin_expect (bool(start < 0 && end > 0), 0
)
)
2511 return 1.f;
2512
2513 if (coord <= start || end <= coord)
2514 return 0.f;
2515
2516 /* Interpolate */
2517 if (coord < peak)
2518 return float (coord - start) / (peak - start);
2519 else
2520 return float (end - coord) / (end - peak);
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 F2DOT14 startCoord;
2537 F2DOT14 peakCoord;
2538 F2DOT14 endCoord;
2539 public:
2540 DEFINE_SIZE_STATIC (6)void _instance_assertion_on_line_2540 () 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)
;
2541};
2542struct SparseVarRegionAxis
2543{
2544 float evaluate (const int *coords, unsigned int coord_len) const
2545 {
2546 unsigned i = axisIndex;
2547 int coord = i < coord_len ? coords[i] : 0;
2548 return axis.evaluate (coord);
2549 }
2550
2551 bool sanitize (hb_sanitize_context_t *c) const
2552 {
2553 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
2554 return_trace (c->check_struct (this))return trace.ret (c->check_struct (this), __PRETTY_FUNCTION__
, 2554)
;
2555 }
2556
2557 bool serialize (hb_serialize_context_t *c) const
2558 {
2559 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
2560 return_trace (c->embed (this))return trace.ret (c->embed (this), __PRETTY_FUNCTION__, 2560
)
;
2561 }
2562
2563 public:
2564 HBUINT16 axisIndex;
2565 VarRegionAxis axis;
2566 public:
2567 DEFINE_SIZE_STATIC (8)void _instance_assertion_on_line_2567 () 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)
;
2568};
2569
2570struct hb_scalar_cache_t
2571{
2572 private:
2573 static constexpr unsigned STATIC_LENGTH = 128;
2574 static constexpr int INVALID = INT_MIN(-2147483647 -1);
2575 static constexpr float MULTIPLIER = 1 << ((sizeof (int) * 8) - 2);
2576 static constexpr float DIVISOR = 1.f / MULTIPLIER;
2577
2578 public:
2579 hb_scalar_cache_t () {}
2580
2581 hb_scalar_cache_t (const hb_scalar_cache_t&) = delete;
2582 hb_scalar_cache_t (hb_scalar_cache_t&&) = delete;
2583 hb_scalar_cache_t& operator= (const hb_scalar_cache_t&) = delete;
2584 hb_scalar_cache_t& operator= (hb_scalar_cache_t&&) = delete;
2585
2586 static hb_scalar_cache_t *create (unsigned int count,
2587 hb_scalar_cache_t *scratch_cache = nullptr)
2588 {
2589 if (!count) return (hb_scalar_cache_t *) &Null(hb_scalar_cache_t)NullHelper<hb_scalar_cache_t>::get_null ();
2590
2591 if (scratch_cache && count <= STATIC_LENGTH)
2592 {
2593 scratch_cache->length = count;
2594 scratch_cache->clear ();
2595 return scratch_cache;
2596 }
2597
2598 auto *cache = (hb_scalar_cache_t *) hb_malloc (sizeof (hb_scalar_cache_t) - sizeof (static_values) + sizeof (static_values[0]) * count);
2599 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 ();
2600
2601 cache->length = count;
2602 cache->clear ();
2603
2604 return cache;
2605 }
2606
2607 static void destroy (hb_scalar_cache_t *cache,
2608 hb_scalar_cache_t *scratch_cache = nullptr)
2609 {
2610 if (cache != &Null(hb_scalar_cache_t)NullHelper<hb_scalar_cache_t>::get_null () && cache != scratch_cache)
2611 hb_free (cache);
2612 }
2613
2614 void clear ()
2615 {
2616 auto *values = &static_values[0];
2617 unsigned i = 0;
2618#ifndef HB_OPTIMIZE_SIZE
2619 for (; i + 3 < length; i += 4)
2620 {
2621 values[i + 0] = INVALID;
2622 values[i + 1] = INVALID;
2623 values[i + 2] = INVALID;
2624 values[i + 3] = INVALID;
2625 }
2626#endif
2627 for (; i < length; i++)
2628 values[i] = INVALID;
2629 }
2630
2631 HB_ALWAYS_INLINE__attribute__((always_inline)) inline
2632 bool get (unsigned i, float *value) const
2633 {
2634 if (unlikely (i >= length)__builtin_expect (bool(i >= length), 0))
2635 {
2636 *value = 0.f;
2637 return true;
2638 }
2639 auto *values = &static_values[0];
2640 auto *cached_value = &values[i];
2641 // Super hot. Most common path is that we have a cached value of 0.
2642 int v = *cached_value;
2643 if (likely (!v)__builtin_expect (bool(!v), 1))
2644 {
2645 *value = 0.f;
2646 return true;
2647 }
2648 if (v == INVALID)
2649 return false;
2650 *value = v * DIVISOR;
2651 return true;
2652 }
2653
2654 HB_ALWAYS_INLINE__attribute__((always_inline)) inline
2655 void set (unsigned i, float value)
2656 {
2657 if (unlikely (i >= length)__builtin_expect (bool(i >= length), 0)) return;
2658 auto *values = &static_values[0];
2659 auto *cached_value = &values[i];
2660 *cached_value = roundf(value * MULTIPLIER)_hb_roundf(value * MULTIPLIER);
2661 }
2662
2663 public:
2664 unsigned length;
2665 private:
2666 mutable hb_atomic_t<int> static_values[STATIC_LENGTH];
2667};
2668
2669struct VarRegionList
2670{
2671 private:
2672 float evaluate_impl (unsigned int region_index,
2673 const int *coords, unsigned int coord_len) const
2674 {
2675 const VarRegionAxis *axes = axesZ.arrayZ + (region_index * axisCount);
2676 float v = 1.f;
2677
2678 unsigned int count = axisCount;
2679 for (unsigned int i = 0; i < count; i++)
2680 {
2681 int coord = i < coord_len ? coords[i] : 0;
2682 float factor = axes[i].evaluate (coord);
2683 if (factor == 0.f)
2684 {
2685 v = 0.f;
2686 break;
2687 }
2688 v *= factor;
2689 }
2690
2691 return v;
2692 }
2693
2694 public:
2695 HB_ALWAYS_INLINE__attribute__((always_inline)) inline
2696 float evaluate (unsigned int region_index,
2697 const int *coords, unsigned int coord_len,
2698 hb_scalar_cache_t *cache = nullptr) const
2699 {
2700 if (unlikely (region_index >= regionCount)__builtin_expect (bool(region_index >= regionCount), 0))
2701 return 0.;
2702
2703 float v;
2704 if (cache && cache->get (region_index, &v))
2705 return v;
2706
2707 v = evaluate_impl (region_index, coords, coord_len);
2708
2709 if (cache)
2710 cache->set (region_index, v);
2711 return v;
2712 }
2713
2714 bool sanitize (hb_sanitize_context_t *c) const
2715 {
2716 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
2717 return_trace (c->check_struct (this) &&return trace.ret (c->check_struct (this) && hb_barrier
() && axesZ.sanitize (c, axisCount * regionCount), __PRETTY_FUNCTION__
, 2719)
2718 hb_barrier () &&return trace.ret (c->check_struct (this) && hb_barrier
() && axesZ.sanitize (c, axisCount * regionCount), __PRETTY_FUNCTION__
, 2719)
2719 axesZ.sanitize (c, axisCount * regionCount))return trace.ret (c->check_struct (this) && hb_barrier
() && axesZ.sanitize (c, axisCount * regionCount), __PRETTY_FUNCTION__
, 2719)
;
2720 }
2721
2722 bool serialize (hb_serialize_context_t *c,
2723 const hb_vector_t<hb_tag_t>& axis_tags,
2724 const hb_vector_t<const hb_hashmap_t<hb_tag_t, Triple>*>& regions)
2725 {
2726 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
2727 unsigned axis_count = axis_tags.length;
2728 unsigned region_count = regions.length;
2729 if (!axis_count || !region_count) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 2729);
2730 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)
2731 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__, 2731);
2732 if (unlikely (!c->extend_min (this))__builtin_expect (bool(!c->extend_min (this)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 2732);
2733 axisCount = axis_count;
2734 regionCount = region_count;
2735
2736 for (unsigned r = 0; r < region_count; r++)
2737 {
2738 const auto& region = regions[r];
2739 for (unsigned i = 0; i < axis_count; i++)
2740 {
2741 hb_tag_t tag = axis_tags.arrayZ[i];
2742 VarRegionAxis var_region_rec;
2743 Triple *coords;
2744 if (region->has (tag, &coords))
2745 {
2746 var_region_rec.startCoord.set_float (coords->minimum);
2747 var_region_rec.peakCoord.set_float (coords->middle);
2748 var_region_rec.endCoord.set_float (coords->maximum);
2749 }
2750 else
2751 {
2752 var_region_rec.startCoord.set_int (0);
2753 var_region_rec.peakCoord.set_int (0);
2754 var_region_rec.endCoord.set_int (0);
2755 }
2756 if (!var_region_rec.serialize (c))
2757 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 2757);
2758 }
2759 }
2760 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 2760);
2761 }
2762
2763 bool serialize (hb_serialize_context_t *c, const VarRegionList *src, const hb_inc_bimap_t &region_map)
2764 {
2765 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
2766 if (unlikely (!c->extend_min (this))__builtin_expect (bool(!c->extend_min (this)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 2766);
2767 axisCount = src->axisCount;
2768 regionCount = region_map.get_population ();
2769 if (unlikely (hb_unsigned_mul_overflows (axisCount * regionCount,__builtin_expect (bool(hb_unsigned_mul_overflows (axisCount *
regionCount, VarRegionAxis::static_size)), 0)
2770 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__, 2770);
2771 if (unlikely (!c->extend (this))__builtin_expect (bool(!c->extend (this)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 2771);
2772 unsigned int region_count = src->regionCount;
2773 for (unsigned int r = 0; r < regionCount; r++)
2774 {
2775 unsigned int backward = region_map.backward (r);
2776 if (backward >= region_count) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 2776);
2777 hb_memcpy (&axesZ[axisCount * r], &src->axesZ[axisCount * backward], VarRegionAxis::static_size * axisCount);
2778 }
2779
2780 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 2780);
2781 }
2782
2783 bool get_var_region (unsigned region_index,
2784 const hb_map_t& axes_old_index_tag_map,
2785 hb_hashmap_t<hb_tag_t, Triple>& axis_tuples /* OUT */) const
2786 {
2787 if (region_index >= regionCount) return false;
2788 const VarRegionAxis* axis_region = axesZ.arrayZ + (region_index * axisCount);
2789 for (unsigned i = 0; i < axisCount; i++)
2790 {
2791 hb_tag_t *axis_tag;
2792 if (!axes_old_index_tag_map.has (i, &axis_tag))
2793 return false;
2794
2795 float min_val = axis_region->startCoord.to_float ();
2796 float def_val = axis_region->peakCoord.to_float ();
2797 float max_val = axis_region->endCoord.to_float ();
2798
2799 if (def_val != 0.f)
2800 axis_tuples.set (*axis_tag, Triple ((double) min_val, (double) def_val, (double) max_val));
2801 axis_region++;
2802 }
2803 return !axis_tuples.in_error ();
2804 }
2805
2806 bool get_var_regions (const hb_map_t& axes_old_index_tag_map,
2807 hb_vector_t<hb_hashmap_t<hb_tag_t, Triple>>& regions /* OUT */) const
2808 {
2809 if (!regions.alloc (regionCount))
2810 return false;
2811
2812 for (unsigned i = 0; i < regionCount; i++)
2813 {
2814 hb_hashmap_t<hb_tag_t, Triple> axis_tuples;
2815 if (!get_var_region (i, axes_old_index_tag_map, axis_tuples))
2816 return false;
2817 regions.push (std::move (axis_tuples));
2818 }
2819 return !regions.in_error ();
2820 }
2821
2822 size_t get_size () const
2823 { return hb_unsigned_add_saturate (min_size,
2824 hb_unsigned_mul_saturate (VarRegionAxis::static_size,
2825 axisCount, regionCount)); }
2826
2827 public:
2828 HBUINT16 axisCount;
2829 HBUINT15 regionCount;
2830 protected:
2831 UnsizedArrayOf<VarRegionAxis>
2832 axesZ;
2833 public:
2834 DEFINE_SIZE_ARRAY (4, axesZ)void _compiles_assertion_on_line_2834 () const { (void) (axesZ
)[0].static_size; } void _instance_assertion_on_line_2834 () const
{ static_assert ((sizeof (*this) == (4) + (1 +0) * sizeof ((
axesZ)[0])), ""); } static constexpr unsigned null_size = (4)
; static constexpr unsigned min_size = (4)
;
2835};
2836
2837/* Whether a variation region is unreachable given per-axis reachable
2838 * final-coordinate ranges, in F2Dot14 units (avar2 partial-instancing
2839 * culling; see hb_subset_plan_t::avar2_reachable_ranges). A region is dead
2840 * if some axis's tent evaluates to zero over the axis's entire reachable
2841 * range. Mirrors the runtime evaluation: invalid tents evaluate as
2842 * constant 1 and never kill a region. */
2843static inline bool
2844_hb_avar2_region_is_dead (const hb_hashmap_t<hb_tag_t, Triple> &axis_tuples,
2845 const hb_hashmap_t<hb_tag_t, Triple> &reachable_ranges)
2846{
2847 for (auto _ : axis_tuples)
2848 {
2849 Triple *range;
2850 if (!reachable_ranges.has (_.first, &range)) continue;
2851 const Triple &tent = _.second;
2852 int start = (int) roundf ((float) tent.minimum * 16384.f)_hb_roundf((float) tent.minimum * 16384.f);
2853 int peak = (int) roundf ((float) tent.middle * 16384.f)_hb_roundf((float) tent.middle * 16384.f);
2854 int end = (int) roundf ((float) tent.maximum * 16384.f)_hb_roundf((float) tent.maximum * 16384.f);
2855 if (!peak) continue;
2856 if (start > peak || peak > end) continue;
2857 if (start < 0 && end > 0) continue;
2858 int lo = (int) roundf ((float) range->minimum * 16384.f)_hb_roundf((float) range->minimum * 16384.f);
2859 int hi = (int) roundf ((float) range->maximum * 16384.f)_hb_roundf((float) range->maximum * 16384.f);
2860 /* Strict comparisons: the scalar is 1 (not 0) at v == peak, so a tent
2861 * whose peak sits exactly on the range boundary is still live there.
2862 * (Reachable ranges are padded by one F2Dot14 unit at their producer,
2863 * which already covers this; strictness keeps the predicate correct on
2864 * its own terms.) */
2865 if (hi < start || lo > end)
2866 return true;
2867 }
2868 return false;
2869}
2870
2871struct SparseVariationRegion : Array16Of<SparseVarRegionAxis>
2872{
2873 float evaluate (const int *coords, unsigned int coord_len) const
2874 {
2875 float v = 1.f;
2876 unsigned int count = len;
2877 for (unsigned int i = 0; i < count; i++)
2878 {
2879 float factor = arrayZ[i].evaluate (coords, coord_len);
2880 if (factor == 0.f)
2881 return 0.;
2882 v *= factor;
2883 }
2884 return v;
2885 }
2886
2887 bool serialize (hb_serialize_context_t *c,
2888 const SparseVariationRegion *src)
2889 { return bool (src->copy (c)); }
2890};
2891
2892struct SparseVarRegionList
2893{
2894 HB_ALWAYS_INLINE__attribute__((always_inline)) inline
2895 float evaluate (unsigned int region_index,
2896 const int *coords, unsigned int coord_len,
2897 hb_scalar_cache_t *cache = nullptr) const
2898 {
2899 if (unlikely (region_index >= regions.len)__builtin_expect (bool(region_index >= regions.len), 0))
2900 return 0.;
2901
2902 float v;
2903 if (cache && cache->get (region_index, &v))
2904 return v;
2905
2906 const SparseVariationRegion &region = this+regions[region_index];
2907
2908 v = region.evaluate (coords, coord_len);
2909 if (cache)
2910 cache->set (region_index, v);
2911
2912 return v;
2913 }
2914
2915 bool sanitize (hb_sanitize_context_t *c) const
2916 {
2917 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
2918 return_trace (regions.sanitize (c, this))return trace.ret (regions.sanitize (c, this), __PRETTY_FUNCTION__
, 2918)
;
2919 }
2920
2921 bool serialize (hb_serialize_context_t *c,
2922 const SparseVarRegionList *src,
2923 const hb_inc_bimap_t &region_map)
2924 {
2925 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
2926 if (unlikely (!c->extend_min (this))__builtin_expect (bool(!c->extend_min (this)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 2926);
2927 regions.len = region_map.get_population ();
2928 if (unlikely (!c->extend (regions))__builtin_expect (bool(!c->extend (regions)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 2928);
2929
2930 for (unsigned i = 0; i < regions.len; i++)
2931 {
2932 unsigned old_index = region_map.backward (i);
2933 if (unlikely (old_index >= src->regions.len ||__builtin_expect (bool(old_index >= src->regions.len ||
!regions[i].serialize_serialize (c, &(src+src->regions
[old_index]))), 0)
2934 !regions[i].serialize_serialize (c,__builtin_expect (bool(old_index >= src->regions.len ||
!regions[i].serialize_serialize (c, &(src+src->regions
[old_index]))), 0)
2935 &(src+src->regions[old_index])))__builtin_expect (bool(old_index >= src->regions.len ||
!regions[i].serialize_serialize (c, &(src+src->regions
[old_index]))), 0)
)
2936 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 2936);
2937 }
2938 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 2938);
2939 }
2940
2941 public:
2942 Array16Of<Offset32To<SparseVariationRegion>>
2943 regions;
2944 public:
2945 DEFINE_SIZE_ARRAY (2, regions)void _compiles_assertion_on_line_2945 () const { (void) (regions
)[0].static_size; } void _instance_assertion_on_line_2945 () const
{ static_assert ((sizeof (*this) == (2) + (1 +0) * sizeof ((
regions)[0])), ""); } static constexpr unsigned null_size = (
2); static constexpr unsigned min_size = (2)
;
2946};
2947
2948
2949struct VarData
2950{
2951 unsigned int get_item_count () const
2952 { return itemCount; }
2953
2954 unsigned int get_region_index_count () const
2955 { return regionIndices.len; }
2956
2957 unsigned get_region_index (unsigned i) const
2958 { return i >= regionIndices.len ? -1 : regionIndices[i]; }
2959
2960 size_t get_row_size () const
2961 { return (wordCount () + regionIndices.len) * (longWords () ? 2 : 1); }
2962
2963 size_t get_size () const
2964 { return hb_unsigned_add_saturate (min_size - regionIndices.min_size,
2965 regionIndices.get_size (),
2966 hb_unsigned_mul_saturate (itemCount, get_row_size ())); }
2967
2968 float _get_delta (unsigned int inner,
2969 const int *coords, unsigned int coord_count,
2970 const VarRegionList &regions,
2971 hb_scalar_cache_t *cache = nullptr) const
2972 {
2973 if (unlikely (inner >= itemCount)__builtin_expect (bool(inner >= itemCount), 0))
2974 return 0.;
2975 bool is_long = longWords ();
2976 unsigned int count = regionIndices.len;
2977 unsigned word_count = wordCount ();
2978 unsigned int scount = is_long ? count : word_count;
2979 unsigned int lcount = is_long ? word_count : 0;
2980
2981 const HBUINT8 *bytes = get_delta_bytes ();
2982 const HBUINT8 *row = bytes + inner * get_row_size ();
2983
2984 float delta = 0.;
2985 unsigned int i = 0;
2986
2987 const HBINT32 *lcursor = reinterpret_cast<const HBINT32 *> (row);
2988 for (; i < lcount; i++)
2989 {
2990 float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count, cache);
2991 if (scalar)
2992 delta += scalar * *lcursor;
2993 lcursor++;
2994 }
2995 const HBINT16 *scursor = reinterpret_cast<const HBINT16 *> (lcursor);
2996 for (; i < scount; i++)
2997 {
2998 float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count, cache);
2999 if (scalar)
3000 delta += scalar * *scursor;
3001 scursor++;
3002 }
3003 const HBINT8 *bcursor = reinterpret_cast<const HBINT8 *> (scursor);
3004 for (; i < count; i++)
3005 {
3006 float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count, cache);
3007 if (scalar)
3008 delta += scalar * *bcursor;
3009 bcursor++;
3010 }
3011
3012 return delta;
3013 }
3014
3015 HB_ALWAYS_INLINE__attribute__((always_inline)) inline
3016 float get_delta (unsigned int inner,
3017 const int *coords, unsigned int coord_count,
3018 const VarRegionList &regions,
3019 hb_scalar_cache_t *cache = nullptr) const
3020 {
3021 unsigned int count = regionIndices.len;
3022 if (!count) return 0.f; // This is quite common, so optimize it.
3023 return _get_delta (inner, coords, coord_count, regions, cache);
3024 }
3025
3026 void get_region_scalars (const int *coords, unsigned int coord_count,
3027 const VarRegionList &regions,
3028 float *scalars /*OUT */,
3029 unsigned int num_scalars) const
3030 {
3031 unsigned count = hb_min (num_scalars, regionIndices.len);
3032 for (unsigned int i = 0; i < count; i++)
3033 scalars[i] = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count);
3034 for (unsigned int i = count; i < num_scalars; i++)
3035 scalars[i] = 0.f;
3036 }
3037
3038 bool sanitize (hb_sanitize_context_t *c) const
3039 {
3040 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
3041 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__, 3047)
3042 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__, 3047)
3043 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__, 3047)
3044 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__, 3047)
3045 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__, 3047)
3046 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__, 3047)
3047 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__, 3047)
;
3048 }
3049
3050 bool serialize (hb_serialize_context_t *c,
3051 bool has_long,
3052 const hb_vector_t<const hb_vector_t<int>*>& rows)
3053 {
3054 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
3055 unsigned row_count = rows.length;
3056 if (!row_count) {
3057 // Nothing to serialize, will be empty.
3058 return false;
3059 }
3060
3061 if (unlikely (!c->extend_min (this))__builtin_expect (bool(!c->extend_min (this)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3061);
3062 if (unlikely (!c->check_assign (itemCount, row_count,__builtin_expect (bool(!c->check_assign (itemCount, row_count
, HB_SERIALIZE_ERROR_INT_OVERFLOW)), 0)
3063 HB_SERIALIZE_ERROR_INT_OVERFLOW))__builtin_expect (bool(!c->check_assign (itemCount, row_count
, HB_SERIALIZE_ERROR_INT_OVERFLOW)), 0)
)
3064 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3064);
3065
3066 int min_threshold = has_long ? -65536 : -128;
3067 int max_threshold = has_long ? +65535 : +127;
3068 enum delta_size_t { kZero=0, kNonWord, kWord };
3069 hb_vector_t<delta_size_t> delta_sz;
3070 unsigned num_regions = rows[0]->length;
3071 if (!delta_sz.resize (num_regions))
3072 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3072);
3073
3074 unsigned word_count = 0;
3075 for (unsigned r = 0; r < num_regions; r++)
3076 {
3077 for (unsigned i = 0; i < row_count; i++)
3078 {
3079 int delta = rows[i]->arrayZ[r];
3080 if (delta < min_threshold || delta > max_threshold)
3081 {
3082 delta_sz[r] = kWord;
3083 word_count++;
3084 break;
3085 }
3086 else if (delta != 0)
3087 {
3088 delta_sz[r] = kNonWord;
3089 }
3090 }
3091 }
3092
3093 /* reorder regions: words and then non-words*/
3094 unsigned word_index = 0;
3095 unsigned non_word_index = word_count;
3096 hb_map_t ri_map;
3097 for (unsigned r = 0; r < num_regions; r++)
3098 {
3099 if (!delta_sz[r]) continue;
3100 unsigned new_r = (delta_sz[r] == kWord)? word_index++ : non_word_index++;
3101 if (!ri_map.set (new_r, r))
3102 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3102);
3103 }
3104
3105 wordSizeCount = word_count | (has_long ? 0x8000u /* LONG_WORDS */ : 0);
3106
3107 unsigned ri_count = ri_map.get_population ();
3108 regionIndices.len = ri_count;
3109 if (unlikely (!c->extend (this))__builtin_expect (bool(!c->extend (this)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3109);
3110
3111 for (unsigned r = 0; r < ri_count; r++)
3112 {
3113 hb_codepoint_t *idx;
3114 if (!ri_map.has (r, &idx))
3115 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3115);
3116 regionIndices[r] = *idx;
3117 }
3118
3119 HBUINT8 *delta_bytes = get_delta_bytes ();
3120 unsigned row_size = get_row_size ();
3121 for (unsigned int i = 0; i < row_count; i++)
3122 {
3123 for (unsigned int r = 0; r < ri_count; r++)
3124 {
3125 int delta = rows[i]->arrayZ[ri_map[r]];
3126 set_item_delta_fast (i, r, delta, delta_bytes, row_size);
3127 }
3128 }
3129 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 3129);
3130 }
3131
3132 bool serialize (hb_serialize_context_t *c,
3133 const VarData *src,
3134 const hb_inc_bimap_t &inner_map,
3135 const hb_inc_bimap_t &region_map,
3136 const hb_set_t *culled_regions = nullptr)
3137 {
3138 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
3139 if (unlikely (!c->extend_min (this))__builtin_expect (bool(!c->extend_min (this)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3139);
3140 itemCount = inner_map.get_next_value ();
3141
3142 /* Optimize word count */
3143 unsigned ri_count = src->regionIndices.len;
3144 enum delta_size_t { kZero=0, kNonWord, kWord };
3145 hb_vector_t<delta_size_t> delta_sz;
3146 hb_vector_t<unsigned int> ri_map; /* maps new index to old index */
3147 delta_sz.resize (ri_count);
3148 ri_map.resize (ri_count);
3149 unsigned int new_word_count = 0;
3150 unsigned int r;
3151
3152 const HBUINT8 *src_delta_bytes = src->get_delta_bytes ();
3153 unsigned src_row_size = src->get_row_size ();
3154 unsigned src_word_count = src->wordCount ();
3155 bool src_long_words = src->longWords ();
3156
3157 bool has_long = false;
3158 if (src_long_words)
3159 {
3160 for (r = 0; r < src_word_count; r++)
3161 {
3162 for (unsigned old_gid : inner_map.keys())
3163 {
3164 int32_t delta = src->get_item_delta_fast (old_gid, r, src_delta_bytes, src_row_size);
3165 if (delta < -65536 || 65535 < delta)
3166 {
3167 has_long = true;
3168 break;
3169 }
3170 }
3171 }
3172 }
3173
3174 signed min_threshold = has_long ? -65536 : -128;
3175 signed max_threshold = has_long ? +65535 : +127;
3176 for (r = 0; r < ri_count; r++)
3177 {
3178 bool short_circuit = src_long_words == has_long && src_word_count <= r;
3179
3180 delta_sz[r] = kZero;
3181 if (culled_regions && culled_regions->has (src->regionIndices[r]))
3182 continue; /* unreachable region: drop its column */
3183 for (unsigned old_gid : inner_map.keys())
3184 {
3185 int32_t delta = src->get_item_delta_fast (old_gid, r, src_delta_bytes, src_row_size);
3186 if (delta < min_threshold || max_threshold < delta)
3187 {
3188 delta_sz[r] = kWord;
3189 new_word_count++;
3190 break;
3191 }
3192 else if (delta != 0)
3193 {
3194 delta_sz[r] = kNonWord;
3195 if (short_circuit)
3196 break;
3197 }
3198 }
3199 }
3200
3201 unsigned int word_index = 0;
3202 unsigned int non_word_index = new_word_count;
3203 unsigned int new_ri_count = 0;
3204 for (r = 0; r < ri_count; r++)
3205 if (delta_sz[r])
3206 {
3207 unsigned new_r = (delta_sz[r] == kWord)? word_index++ : non_word_index++;
3208 ri_map[new_r] = r;
3209 new_ri_count++;
3210 }
3211
3212 wordSizeCount = new_word_count | (has_long ? 0x8000u /* LONG_WORDS */ : 0);
3213
3214 regionIndices.len = new_ri_count;
3215
3216 if (unlikely (!c->extend (this))__builtin_expect (bool(!c->extend (this)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3216);
3217
3218 for (r = 0; r < new_ri_count; r++)
3219 regionIndices[r] = region_map[src->regionIndices[ri_map[r]]];
3220
3221 HBUINT8 *delta_bytes = get_delta_bytes ();
3222 unsigned row_size = get_row_size ();
3223 unsigned count = itemCount;
3224 for (unsigned int i = 0; i < count; i++)
3225 {
3226 unsigned int old = inner_map.backward (i);
3227 for (unsigned int r = 0; r < new_ri_count; r++)
3228 set_item_delta_fast (i, r,
3229 src->get_item_delta_fast (old, ri_map[r],
3230 src_delta_bytes, src_row_size),
3231 delta_bytes, row_size);
3232 }
3233
3234 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 3234);
3235 }
3236
3237 void collect_region_refs (hb_set_t &region_indices, const hb_inc_bimap_t &inner_map) const
3238 {
3239 const HBUINT8 *delta_bytes = get_delta_bytes ();
3240 unsigned row_size = get_row_size ();
3241
3242 for (unsigned int r = 0; r < regionIndices.len; r++)
3243 {
3244 unsigned int region = regionIndices.arrayZ[r];
3245 if (region_indices.has (region)) continue;
3246 for (hb_codepoint_t old_gid : inner_map.keys())
3247 if (get_item_delta_fast (old_gid, r, delta_bytes, row_size) != 0)
3248 {
3249 region_indices.add (region);
3250 break;
3251 }
3252 }
3253 }
3254
3255 public:
3256 const HBUINT8 *get_delta_bytes () const
3257 { return &StructAfter<HBUINT8> (regionIndices); }
3258
3259 protected:
3260 HBUINT8 *get_delta_bytes ()
3261 { return &StructAfter<HBUINT8> (regionIndices); }
3262
3263 public:
3264 int32_t get_item_delta_fast (unsigned int item, unsigned int region,
3265 const HBUINT8 *delta_bytes, unsigned row_size) const
3266 {
3267 if (unlikely (item >= itemCount || region >= regionIndices.len)__builtin_expect (bool(item >= itemCount || region >= regionIndices
.len), 0)
) return 0;
3268
3269 const HBINT8 *p = (const HBINT8 *) delta_bytes + item * row_size;
3270 unsigned word_count = wordCount ();
3271 bool is_long = longWords ();
3272 if (is_long)
3273 {
3274 if (region < word_count)
3275 return ((const HBINT32 *) p)[region];
3276 else
3277 return ((const HBINT16 *)(p + HBINT32::static_size * word_count))[region - word_count];
3278 }
3279 else
3280 {
3281 if (region < word_count)
3282 return ((const HBINT16 *) p)[region];
3283 else
3284 return (p + HBINT16::static_size * word_count)[region - word_count];
3285 }
3286 }
3287 int32_t get_item_delta (unsigned int item, unsigned int region) const
3288 {
3289 return get_item_delta_fast (item, region,
3290 get_delta_bytes (),
3291 get_row_size ());
3292 }
3293
3294 protected:
3295 void set_item_delta_fast (unsigned int item, unsigned int region, int32_t delta,
3296 HBUINT8 *delta_bytes, unsigned row_size)
3297 {
3298 HBINT8 *p = (HBINT8 *) delta_bytes + item * row_size;
3299 unsigned word_count = wordCount ();
3300 bool is_long = longWords ();
3301 if (is_long)
3302 {
3303 if (region < word_count)
3304 ((HBINT32 *) p)[region] = delta;
3305 else
3306 ((HBINT16 *)(p + HBINT32::static_size * word_count))[region - word_count] = delta;
3307 }
3308 else
3309 {
3310 if (region < word_count)
3311 ((HBINT16 *) p)[region] = delta;
3312 else
3313 (p + HBINT16::static_size * word_count)[region - word_count] = delta;
3314 }
3315 }
3316 void set_item_delta (unsigned int item, unsigned int region, int32_t delta)
3317 {
3318 set_item_delta_fast (item, region, delta,
3319 get_delta_bytes (),
3320 get_row_size ());
3321 }
3322
3323 bool longWords () const { return wordSizeCount & 0x8000u /* LONG_WORDS */; }
3324 unsigned wordCount () const { return wordSizeCount & 0x7FFFu /* WORD_DELTA_COUNT_MASK */; }
3325
3326 protected:
3327 HBUINT16 itemCount;
3328 HBUINT16 wordSizeCount;
3329 Array16Of<HBUINT16> regionIndices;
3330/*UnsizedArrayOf<HBUINT8>bytesX;*/
3331 public:
3332 DEFINE_SIZE_ARRAY (6, regionIndices)void _compiles_assertion_on_line_3332 () const { (void) (regionIndices
)[0].static_size; } void _instance_assertion_on_line_3332 () const
{ static_assert ((sizeof (*this) == (6) + (1 +0) * sizeof ((
regionIndices)[0])), ""); } static constexpr unsigned null_size
= (6); static constexpr unsigned min_size = (6)
;
3333};
3334
3335struct MultiVarData
3336{
3337 size_t get_size () const
3338 { return hb_unsigned_add_saturate (min_size - regionIndices.min_size,
3339 regionIndices.get_size (),
3340 StructAfter<CFF2Index> (regionIndices).get_size ()); }
3341
3342 void get_delta (unsigned int inner,
3343 const int *coords, unsigned int coord_count,
3344 const SparseVarRegionList &regions,
3345 hb_array_t<float> out,
3346 hb_scalar_cache_t *cache = nullptr) const
3347 {
3348 auto &deltaSets = StructAfter<decltype (deltaSetsX)> (regionIndices);
3349
3350 auto values_iter = deltaSets.fetcher (inner);
3351 unsigned regionCount = regionIndices.len;
3352 unsigned skip = 0;
3353 for (unsigned regionIndex = 0; regionIndex < regionCount; regionIndex++)
3354 {
3355 float scalar = regions.evaluate (regionIndices.arrayZ[regionIndex],
3356 coords, coord_count,
3357 cache);
3358 // We skip lazily. Helps with the tail end.
3359 if (scalar == 0.0f)
3360 skip += out.length;
3361 else
3362 {
3363 if (skip)
3364 {
3365 values_iter.skip (skip);
3366 skip = 0;
3367 }
3368 values_iter.add_to (out, scalar);
3369 }
3370 }
3371 }
3372
3373 bool sanitize (hb_sanitize_context_t *c) const
3374 {
3375 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
3376 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__
, 3381)
3377 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__
, 3381)
3378 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__
, 3381)
3379 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__
, 3381)
3380 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__
, 3381)
3381 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__
, 3381)
;
3382 }
3383
3384 unsigned get_item_count () const
3385 { return StructAfter<decltype (deltaSetsX)> (regionIndices).count; }
3386
3387 void collect_region_refs (hb_set_t &region_indices) const
3388 {
3389 for (unsigned region : regionIndices)
3390 region_indices.add (region);
3391 }
3392
3393 bool serialize (hb_serialize_context_t *c,
3394 const MultiVarData *src,
3395 const hb_inc_bimap_t &inner_map,
3396 const hb_inc_bimap_t &region_map)
3397 {
3398 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
3399 unsigned region_count = src->regionIndices.len;
3400 unsigned header_size = HBUINT8::static_size +
3401 Array16Of<HBUINT16>::min_size +
3402 region_count * HBUINT16::static_size;
3403 if (unlikely (!c->extend_size (this, header_size, false))__builtin_expect (bool(!c->extend_size (this, header_size,
false)), 0)
)
3404 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3404);
3405 format = 1;
3406 regionIndices.len = region_count;
3407 for (unsigned i = 0; i < regionIndices.len; i++)
3408 {
3409 unsigned old_region = src->regionIndices[i];
3410 if (unlikely (!region_map.has (old_region))__builtin_expect (bool(!region_map.has (old_region)), 0))
3411 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3411);
3412 regionIndices[i] = region_map.get (old_region);
3413 }
3414
3415 const auto &src_delta_sets = StructAfter<decltype (deltaSetsX)> (src->regionIndices);
3416 hb_vector_t<hb_ubytes_t> delta_sets;
3417 unsigned data_size = 0;
3418 if (unlikely (!delta_sets.alloc_exact (inner_map.get_population ()))__builtin_expect (bool(!delta_sets.alloc_exact (inner_map.get_population
())), 0)
)
3419 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3419);
3420 for (unsigned i = 0; i < inner_map.get_population (); i++)
3421 {
3422 unsigned old_inner = inner_map.backward (i);
3423 if (unlikely (old_inner >= src_delta_sets.count)__builtin_expect (bool(old_inner >= src_delta_sets.count),
0)
) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3423);
3424 hb_ubytes_t bytes = static_cast<const CFF2Index &> (src_delta_sets)[old_inner];
3425 data_size = hb_unsigned_add_saturate (data_size, bytes.length);
3426 delta_sets.push (bytes);
3427 }
3428 if (unlikely (data_size == UINT_MAX || delta_sets.in_error ())__builtin_expect (bool(data_size == (2147483647 *2U +1U) || delta_sets
.in_error ()), 0)
)
3429 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3429);
3430
3431 auto &out_delta_sets = StructAfter<decltype (deltaSetsX)> (regionIndices);
3432 return_trace (out_delta_sets.serialize (c, delta_sets.iter (), &data_size))return trace.ret (out_delta_sets.serialize (c, delta_sets.iter
(), &data_size), __PRETTY_FUNCTION__, 3432)
;
3433 }
3434
3435 protected:
3436 HBUINT8 format; // 1
3437 Array16Of<HBUINT16> regionIndices;
3438 TupleList deltaSetsX;
3439 public:
3440 DEFINE_SIZE_MIN (8)void _instance_assertion_on_line_3440 () const { static_assert
((sizeof (*this) >= (8)), ""); } static constexpr unsigned
null_size = (8); static constexpr unsigned min_size = (8)
;
3441};
3442
3443struct ItemVariationStore
3444{
3445 friend struct item_variations_t;
3446
3447 hb_scalar_cache_t *create_cache () const
3448 {
3449#ifdef HB_NO_VAR
3450 return hb_scalar_cache_t::create (0);
3451#endif
3452 return hb_scalar_cache_t::create ((this+regions).regionCount);
3453 }
3454
3455 static void destroy_cache (hb_scalar_cache_t *cache)
3456 {
3457 hb_scalar_cache_t::destroy (cache);
3458 }
3459
3460 private:
3461 float get_delta (unsigned int outer, unsigned int inner,
3462 const int *coords, unsigned int coord_count,
3463 hb_scalar_cache_t *cache = nullptr) const
3464 {
3465#ifdef HB_NO_VAR
3466 return 0.f;
3467#endif
3468
3469 if (unlikely (outer >= dataSets.len)__builtin_expect (bool(outer >= dataSets.len), 0))
3470 return 0.f;
3471
3472 return (this+dataSets[outer]).get_delta (inner,
3473 coords, coord_count,
3474 this+regions,
3475 cache);
3476 }
3477
3478 public:
3479 bool has_delta_set (unsigned int index) const
3480 {
3481#ifdef HB_NO_VAR
3482 return false;
3483#endif
3484
3485 unsigned int outer = index >> 16;
3486 unsigned int inner = index & 0xFFFF;
3487 return outer < dataSets.len &&
3488 inner < (this+dataSets[outer]).get_item_count ();
3489 }
3490
3491 float get_delta (unsigned int index,
3492 const int *coords, unsigned int coord_count,
3493 hb_scalar_cache_t *cache = nullptr) const
3494 {
3495 unsigned int outer = index >> 16;
3496 unsigned int inner = index & 0xFFFF;
3497 return get_delta (outer, inner, coords, coord_count, cache);
3498 }
3499 float get_delta (unsigned int index,
3500 hb_array_t<const int> coords,
3501 hb_scalar_cache_t *cache = nullptr) const
3502 {
3503 return get_delta (index,
3504 coords.arrayZ, coords.length,
3505 cache);
3506 }
3507
3508 bool sanitize (hb_sanitize_context_t *c) const
3509 {
3510#ifdef HB_NO_VAR
3511 return true;
3512#endif
3513
3514 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
3515 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__
, 3519)
3516 hb_barrier () &&return trace.ret (c->check_struct (this) && hb_barrier
() && format == 1 && regions.sanitize (c, this
) && dataSets.sanitize (c, this), __PRETTY_FUNCTION__
, 3519)
3517 format == 1 &&return trace.ret (c->check_struct (this) && hb_barrier
() && format == 1 && regions.sanitize (c, this
) && dataSets.sanitize (c, this), __PRETTY_FUNCTION__
, 3519)
3518 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__
, 3519)
3519 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__
, 3519)
;
3520 }
3521
3522 bool serialize (hb_serialize_context_t *c,
3523 bool has_long,
3524 const hb_vector_t<hb_tag_t>& axis_tags,
3525 const hb_vector_t<const hb_hashmap_t<hb_tag_t, Triple>*>& region_list,
3526 const hb_vector_t<delta_row_encoding_t>& vardata_encodings)
3527 {
3528 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
3529#ifdef HB_NO_VAR
3530 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3530);
3531#endif
3532 if (unlikely (!c->extend_min (this))__builtin_expect (bool(!c->extend_min (this)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3532);
3533
3534 format = 1;
3535 if (!regions.serialize_serialize (c, axis_tags, region_list))
3536 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3536);
3537
3538 unsigned num_var_data = vardata_encodings.length;
3539 if (!num_var_data) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3539);
3540 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)
3541 HB_SERIALIZE_ERROR_INT_OVERFLOW))__builtin_expect (bool(!c->check_assign (dataSets.len, num_var_data
, HB_SERIALIZE_ERROR_INT_OVERFLOW)), 0)
)
3542 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3542);
3543
3544 if (unlikely (!c->extend (dataSets))__builtin_expect (bool(!c->extend (dataSets)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3544);
3545 for (unsigned i = 0; i < num_var_data; i++)
3546 if (!dataSets[i].serialize_serialize (c, has_long, vardata_encodings[i].items))
3547 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3547);
3548
3549 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 3549);
3550 }
3551
3552 bool serialize (hb_serialize_context_t *c,
3553 const ItemVariationStore *src,
3554 const hb_array_t <const hb_inc_bimap_t> &inner_maps,
3555 const hb_set_t *culled_regions = nullptr)
3556 {
3557 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
3558#ifdef HB_NO_VAR
3559 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3559);
3560#endif
3561
3562 if (unlikely (!c->extend_min (this))__builtin_expect (bool(!c->extend_min (this)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3562);
3563
3564 unsigned int set_count = 0;
3565 for (unsigned int i = 0; i < inner_maps.length; i++)
3566 if (inner_maps[i].get_population ())
3567 set_count++;
3568
3569 format = 1;
3570
3571 const auto &src_regions = src+src->regions;
3572
3573 hb_set_t region_indices;
3574 for (unsigned int i = 0; i < inner_maps.length; i++)
3575 (src+src->dataSets[i]).collect_region_refs (region_indices, inner_maps[i]);
3576
3577 if (region_indices.in_error ())
3578 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3578);
3579
3580 region_indices.del_range ((src_regions).regionCount, hb_set_t::INVALID);
3581
3582 if (culled_regions)
3583 region_indices.subtract (*culled_regions);
3584
3585 /* TODO use constructor when our data-structures support that. */
3586 hb_inc_bimap_t region_map;
3587 + hb_iter (region_indices)
3588 | hb_apply ([&region_map] (unsigned _) { region_map.add(_); })
3589 ;
3590 if (region_map.in_error())
3591 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3591);
3592
3593 if (unlikely (!regions.serialize_serialize (c, &src_regions, region_map))__builtin_expect (bool(!regions.serialize_serialize (c, &
src_regions, region_map)), 0)
)
3594 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3594);
3595
3596 dataSets.len = set_count;
3597 if (unlikely (!c->extend (dataSets))__builtin_expect (bool(!c->extend (dataSets)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3597);
3598
3599 /* TODO: The following code could be simplified when
3600 * List16OfOffset16To::subset () can take a custom param to be passed to VarData::serialize () */
3601 unsigned int set_index = 0;
3602 for (unsigned int i = 0; i < inner_maps.length; i++)
3603 {
3604 if (!inner_maps[i].get_population ()) continue;
3605 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)
3606 .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)
3607 culled_regions))__builtin_expect (bool(!dataSets[set_index++] .serialize_serialize
(c, &(src+src->dataSets[i]), inner_maps[i], region_map
, culled_regions)), 0)
)
3608 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3608);
3609 }
3610
3611 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 3611);
3612 }
3613
3614 ItemVariationStore *copy (hb_serialize_context_t *c) const
3615 {
3616 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
3617 auto *out = c->start_embed (this);
3618 if (unlikely (!out)__builtin_expect (bool(!out), 0)) return_trace (nullptr)return trace.ret (nullptr, __PRETTY_FUNCTION__, 3618);
3619
3620 hb_vector_t <hb_inc_bimap_t> inner_maps;
3621 unsigned count = dataSets.len;
3622 for (unsigned i = 0; i < count; i++)
3623 {
3624 hb_inc_bimap_t *map = inner_maps.push ();
3625 if (unlikely (!c->propagate_error(inner_maps))__builtin_expect (bool(!c->propagate_error(inner_maps)), 0
)
)
3626 return_trace(nullptr)return trace.ret (nullptr, __PRETTY_FUNCTION__, 3626);
3627 auto &data = this+dataSets[i];
3628
3629 unsigned itemCount = data.get_item_count ();
3630 for (unsigned j = 0; j < itemCount; j++)
3631 map->add (j);
3632 }
3633
3634 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__, 3634);
3635
3636 return_trace (out)return trace.ret (out, __PRETTY_FUNCTION__, 3636);
3637 }
3638
3639 /* Collect regions that a partial avar2 instance can never reach, per the
3640 * plan's reachable final-coordinate ranges. */
3641 bool collect_dead_regions (const hb_map_t &axes_old_index_tag_map,
3642 const hb_hashmap_t<hb_tag_t, Triple> &reachable_ranges,
3643 hb_set_t &dead_regions /* OUT */) const
3644 {
3645#ifndef HB_NO_VAR
3646 if (!reachable_ranges.get_population ()) return true;
3647 const VarRegionList &region_list = this+regions;
3648 unsigned count = region_list.regionCount;
3649 for (unsigned i = 0; i < count; i++)
3650 {
3651 hb_hashmap_t<hb_tag_t, Triple> axis_tuples;
3652 if (!region_list.get_var_region (i, axes_old_index_tag_map, axis_tuples))
3653 return false;
3654 if (_hb_avar2_region_is_dead (axis_tuples, reachable_ranges))
3655 dead_regions.add (i);
3656 }
3657 return !dead_regions.in_error ();
3658#else
3659 return true;
3660#endif
3661 }
3662
3663 bool subset (hb_subset_context_t *c, const hb_array_t<const hb_inc_bimap_t> &inner_maps) const
3664 {
3665 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
3666#ifdef HB_NO_VAR
3667 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3667);
3668#endif
3669
3670 ItemVariationStore *varstore_prime = c->serializer->start_embed<ItemVariationStore> ();
3671 if (unlikely (!varstore_prime)__builtin_expect (bool(!varstore_prime), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3671);
3672
3673 /* avar2 partial instancing: cull unreachable regions. */
3674 hb_set_t dead_regions;
3675 if (c->plan->has_avar2)
3676 if (!collect_dead_regions (c->plan->axes_old_index_tag_map,
3677 c->plan->avar2_reachable_ranges,
3678 dead_regions))
3679 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3679);
3680
3681 varstore_prime->serialize (c->serializer, this, inner_maps,
3682 dead_regions.get_population () ? &dead_regions : nullptr);
3683
3684 return_trace (return trace.ret (!c->serializer->in_error() &&
varstore_prime->dataSets, __PRETTY_FUNCTION__, 3686)
3685 !c->serializer->in_error()return trace.ret (!c->serializer->in_error() &&
varstore_prime->dataSets, __PRETTY_FUNCTION__, 3686)
3686 && varstore_prime->dataSets)return trace.ret (!c->serializer->in_error() &&
varstore_prime->dataSets, __PRETTY_FUNCTION__, 3686)
;
3687 }
3688
3689 unsigned int get_region_index_count (unsigned int major) const
3690 {
3691#ifdef HB_NO_VAR
3692 return 0;
3693#endif
3694 return (this+dataSets[major]).get_region_index_count ();
3695 }
3696
3697 void get_region_scalars (unsigned int major,
3698 const int *coords, unsigned int coord_count,
3699 float *scalars /*OUT*/,
3700 unsigned int num_scalars) const
3701 {
3702#ifdef HB_NO_VAR
3703 for (unsigned i = 0; i < num_scalars; i++)
3704 scalars[i] = 0.f;
3705 return;
3706#endif
3707
3708 (this+dataSets[major]).get_region_scalars (coords, coord_count,
3709 this+regions,
3710 &scalars[0], num_scalars);
3711 }
3712
3713 unsigned int get_sub_table_count () const
3714 {
3715#ifdef HB_NO_VAR
3716 return 0;
3717#endif
3718 return dataSets.len;
3719 }
3720
3721 const VarData& get_sub_table (unsigned i) const
3722 {
3723#ifdef HB_NO_VAR
3724 return Null (VarData)NullHelper<VarData>::get_null ();
3725#endif
3726 return this+dataSets[i];
3727 }
3728
3729 const VarRegionList& get_region_list () const
3730 {
3731#ifdef HB_NO_VAR
3732 return Null (VarRegionList)NullHelper<VarRegionList>::get_null ();
3733#endif
3734 return this+regions;
3735 }
3736
3737 protected:
3738 HBUINT16 format;
3739 Offset32To<VarRegionList> regions;
3740 Array16OfOffset32To<VarData> dataSets;
3741 public:
3742 DEFINE_SIZE_ARRAY_SIZED (8, dataSets)size_t get_size () const { return (8 - (dataSets).min_size + (
dataSets).get_size ()); } void _compiles_assertion_on_line_3742
() const { (void) (dataSets)[0].static_size; } void _instance_assertion_on_line_3742
() const { static_assert ((sizeof (*this) == (8) + (1 +0) * sizeof
((dataSets)[0])), ""); } static constexpr unsigned null_size
= (8); static constexpr unsigned min_size = (8)
;
3743};
3744
3745struct MultiItemVariationStore
3746{
3747 hb_scalar_cache_t *create_cache (hb_scalar_cache_t *static_cache = nullptr) const
3748 {
3749#ifdef HB_NO_VAR
3750 return hb_scalar_cache_t::create (0);
3751#endif
3752 auto &r = this+regions;
3753 unsigned count = r.regions.len;
3754
3755 return hb_scalar_cache_t::create (count, static_cache);
3756 }
3757
3758 static void destroy_cache (hb_scalar_cache_t *cache,
3759 hb_scalar_cache_t *static_cache = nullptr)
3760 {
3761 hb_scalar_cache_t::destroy (cache, static_cache);
3762 }
3763
3764 private:
3765 void get_delta (unsigned int outer, unsigned int inner,
3766 const int *coords, unsigned int coord_count,
3767 hb_array_t<float> out,
3768 hb_scalar_cache_t *cache = nullptr) const
3769 {
3770#ifdef HB_NO_VAR
3771 return;
3772#endif
3773
3774 if (unlikely (outer >= dataSets.len)__builtin_expect (bool(outer >= dataSets.len), 0))
3775 return;
3776
3777 return (this+dataSets[outer]).get_delta (inner,
3778 coords, coord_count,
3779 this+regions,
3780 out,
3781 cache);
3782 }
3783
3784 public:
3785 void get_delta (unsigned int index,
3786 const int *coords, unsigned int coord_count,
3787 hb_array_t<float> out,
3788 hb_scalar_cache_t *cache = nullptr) const
3789 {
3790 unsigned int outer = index >> 16;
3791 unsigned int inner = index & 0xFFFF;
3792 get_delta (outer, inner, coords, coord_count, out, cache);
3793 }
3794 void get_delta (unsigned int index,
3795 hb_array_t<const int> coords,
3796 hb_array_t<float> out,
3797 hb_scalar_cache_t *cache = nullptr) const
3798 {
3799 return get_delta (index,
3800 coords.arrayZ, coords.length,
3801 out,
3802 cache);
3803 }
3804
3805 bool sanitize (hb_sanitize_context_t *c) const
3806 {
3807#ifdef HB_NO_VAR
3808 return true;
3809#endif
3810
3811 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
3812 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__
, 3816)
3813 hb_barrier () &&return trace.ret (c->check_struct (this) && hb_barrier
() && format == 1 && regions.sanitize (c, this
) && dataSets.sanitize (c, this), __PRETTY_FUNCTION__
, 3816)
3814 format == 1 &&return trace.ret (c->check_struct (this) && hb_barrier
() && format == 1 && regions.sanitize (c, this
) && dataSets.sanitize (c, this), __PRETTY_FUNCTION__
, 3816)
3815 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__
, 3816)
3816 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__
, 3816)
;
3817 }
3818
3819 bool create_subset_plan (const hb_set_t &var_indices,
3820 hb_vector_t<hb_inc_bimap_t> *inner_maps,
3821 hb_map_t *varidx_map) const
3822 {
3823 if (unlikely (!inner_maps->resize (dataSets.len))__builtin_expect (bool(!inner_maps->resize (dataSets.len))
, 0)
) return false;
3824 for (hb_codepoint_t var_idx : var_indices)
3825 {
3826 unsigned outer = var_idx >> 16;
3827 unsigned inner = var_idx & 0xFFFFu;
3828 if (unlikely (outer >= dataSets.len ||__builtin_expect (bool(outer >= dataSets.len || inner >=
(this+dataSets[outer]).get_item_count ()), 0)
3829 inner >= (this+dataSets[outer]).get_item_count ())__builtin_expect (bool(outer >= dataSets.len || inner >=
(this+dataSets[outer]).get_item_count ()), 0)
)
3830 return false;
3831 (*inner_maps)[outer].add (inner);
3832 }
3833
3834 unsigned new_outer = 0;
3835 for (unsigned outer = 0; outer < inner_maps->length; outer++)
3836 {
3837 const hb_inc_bimap_t &inner_map = (*inner_maps)[outer];
3838 if (!inner_map.get_population ()) continue;
3839 if (unlikely (inner_map.in_error ())__builtin_expect (bool(inner_map.in_error ()), 0)) return false;
3840 for (unsigned new_inner = 0;
3841 new_inner < inner_map.get_population ();
3842 new_inner++)
3843 {
3844 unsigned old_inner = inner_map.backward (new_inner);
3845 varidx_map->set ((outer << 16) | old_inner,
3846 (new_outer << 16) | new_inner);
3847 }
3848 new_outer++;
3849 }
3850 return !inner_maps->in_error () && !varidx_map->in_error ();
3851 }
3852
3853 bool serialize (hb_serialize_context_t *c,
3854 const MultiItemVariationStore *src,
3855 const hb_array_t<const hb_inc_bimap_t> &inner_maps)
3856 {
3857 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
3858 if (unlikely (!c->extend_min (this) ||__builtin_expect (bool(!c->extend_min (this) || inner_maps
.length < src->dataSets.len), 0)
3859 inner_maps.length < src->dataSets.len)__builtin_expect (bool(!c->extend_min (this) || inner_maps
.length < src->dataSets.len), 0)
)
3860 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3860);
3861 format = 1;
3862
3863 const auto &src_regions = src+src->regions;
3864 hb_set_t region_indices;
3865 unsigned set_count = 0;
3866 for (unsigned i = 0; i < src->dataSets.len; i++)
3867 {
3868 if (!inner_maps[i].get_population ()) continue;
3869 set_count++;
3870 (src+src->dataSets[i]).collect_region_refs (region_indices);
3871 }
3872 region_indices.del_range (src_regions.regions.len, hb_set_t::INVALID);
3873 hb_inc_bimap_t region_map;
3874 region_map.add_set (&region_indices);
3875 if (unlikely (region_indices.in_error () || region_map.in_error () ||__builtin_expect (bool(region_indices.in_error () || region_map
.in_error () || !regions.serialize_serialize (c, &src_regions
, region_map)), 0)
3876 !regions.serialize_serialize (c, &src_regions, region_map))__builtin_expect (bool(region_indices.in_error () || region_map
.in_error () || !regions.serialize_serialize (c, &src_regions
, region_map)), 0)
)
3877 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3877);
3878
3879 dataSets.len = set_count;
3880 if (unlikely (!c->extend (dataSets))__builtin_expect (bool(!c->extend (dataSets)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3880);
3881 unsigned set_index = 0;
3882 for (unsigned i = 0; i < src->dataSets.len; i++)
3883 {
3884 if (!inner_maps[i].get_population ()) continue;
3885 if (unlikely (!dataSets[set_index++].serialize_serialize (__builtin_expect (bool(!dataSets[set_index++].serialize_serialize
( c, &(src+src->dataSets[i]), inner_maps[i], region_map
)), 0)
3886 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
)), 0)
)
3887 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3887);
3888 }
3889 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 3889);
3890 }
3891
3892 protected:
3893 HBUINT16 format; // 1
3894 Offset32To<SparseVarRegionList> regions;
3895 Array16OfOffset32To<MultiVarData> dataSets;
3896 public:
3897 DEFINE_SIZE_ARRAY_SIZED (8, dataSets)size_t get_size () const { return (8 - (dataSets).min_size + (
dataSets).get_size ()); } void _compiles_assertion_on_line_3897
() const { (void) (dataSets)[0].static_size; } void _instance_assertion_on_line_3897
() const { static_assert ((sizeof (*this) == (8) + (1 +0) * sizeof
((dataSets)[0])), ""); } static constexpr unsigned null_size
= (8); static constexpr unsigned min_size = (8)
;
3898};
3899
3900template <typename MapCountT>
3901struct DeltaSetIndexMapFormat01
3902{
3903 friend struct DeltaSetIndexMap;
3904
3905 size_t get_size () const
3906 { return hb_unsigned_mul_add_saturate (mapCount, get_width (), min_size); }
3907
3908 private:
3909 DeltaSetIndexMapFormat01* copy (hb_serialize_context_t *c) const
3910 {
3911 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
3912 return_trace (c->embed (this))return trace.ret (c->embed (this), __PRETTY_FUNCTION__, 3912
)
;
3913 }
3914
3915 template <typename T>
3916 bool serialize (hb_serialize_context_t *c, const T &plan)
3917 {
3918 unsigned int width = plan.get_width ();
3919 unsigned int inner_bit_count = plan.get_inner_bit_count ();
3920 const hb_array_t<const uint32_t> output_map = plan.get_output_map ();
3921
3922 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
3923 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)
)
3924 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3924);
3925 if (unlikely (!c->extend_min (this))__builtin_expect (bool(!c->extend_min (this)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3925);
3926
3927 entryFormat = ((width-1)<<4)|(inner_bit_count-1);
3928 mapCount = output_map.length;
3929 HBUINT8 *p = c->allocate_size<HBUINT8> (width * output_map.length);
3930 if (unlikely (!p)__builtin_expect (bool(!p), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 3930);
3931 for (unsigned int i = 0; i < output_map.length; i++)
3932 {
3933 unsigned int v = output_map.arrayZ[i];
3934 if (v)
3935 {
3936 unsigned int outer = v >> 16;
3937 unsigned int inner = v & 0xFFFF;
3938 unsigned int u = (outer << inner_bit_count) | inner;
3939 for (unsigned int w = width; w > 0;)
3940 {
3941 p[--w] = u;
3942 u >>= 8;
3943 }
3944 }
3945 p += width;
3946 }
3947 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 3947);
3948 }
3949
3950 HB_ALWAYS_INLINE__attribute__((always_inline)) inline
3951 uint32_t map (unsigned int v) const /* Returns 16.16 outer.inner. */
3952 {
3953 /* If count is zero, pass value unchanged. This takes
3954 * care of direct mapping for advance map. */
3955 if (!mapCount)
3956 return v;
3957 return _map (v);
3958 }
3959
3960 HB_HOT__attribute__((hot))
3961 uint32_t _map (unsigned int v) const /* Returns 16.16 outer.inner. */
3962 {
3963 if (v >= mapCount)
3964 v = mapCount - 1;
3965
3966 unsigned int u = 0;
3967 { /* Fetch it. */
3968 unsigned int w = get_width ();
3969 const HBUINT8 *p = mapDataZ.arrayZ + w * v;
3970 for (; w; w--)
3971 u = (u << 8) + *p++;
3972 }
3973
3974 { /* Repack it. */
3975 unsigned int n = get_inner_bit_count ();
3976 unsigned int outer = u >> n;
3977 unsigned int inner = u & ((1 << n) - 1);
3978 u = (outer<<16) | inner;
3979 }
3980
3981 return u;
3982 }
3983
3984 unsigned get_map_count () const { return mapCount; }
3985 unsigned get_width () const { return ((entryFormat >> 4) & 3) + 1; }
3986 unsigned get_inner_bit_count () const { return (entryFormat & 0xF) + 1; }
3987
3988
3989 bool sanitize (hb_sanitize_context_t *c) const
3990 {
3991 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
3992 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__, 3996)
3993 hb_barrier () &&return trace.ret (c->check_struct (this) && hb_barrier
() && c->check_range (mapDataZ.arrayZ, mapCount, get_width
()), __PRETTY_FUNCTION__, 3996)
3994 c->check_range (mapDataZ.arrayZ,return trace.ret (c->check_struct (this) && hb_barrier
() && c->check_range (mapDataZ.arrayZ, mapCount, get_width
()), __PRETTY_FUNCTION__, 3996)
3995 mapCount,return trace.ret (c->check_struct (this) && hb_barrier
() && c->check_range (mapDataZ.arrayZ, mapCount, get_width
()), __PRETTY_FUNCTION__, 3996)
3996 get_width ()))return trace.ret (c->check_struct (this) && hb_barrier
() && c->check_range (mapDataZ.arrayZ, mapCount, get_width
()), __PRETTY_FUNCTION__, 3996)
;
3997 }
3998
3999 protected:
4000 HBUINT8 format; /* Format identifier--format = 0 */
4001 HBUINT8 entryFormat; /* A packed field that describes the compressed
4002 * representation of delta-set indices. */
4003 MapCountT mapCount; /* The number of mapping entries. */
4004 UnsizedArrayOf<HBUINT8>
4005 mapDataZ; /* The delta-set index mapping data. */
4006
4007 public:
4008 DEFINE_SIZE_ARRAY (2+MapCountT::static_size, mapDataZ)void _compiles_assertion_on_line_4008 () const { (void) (mapDataZ
)[0].static_size; } void _instance_assertion_on_line_4008 () 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)
;
4009};
4010
4011struct DeltaSetIndexMap
4012{
4013 template <typename T>
4014 bool serialize (hb_serialize_context_t *c, const T &plan)
4015 {
4016 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
4017 unsigned length = plan.get_output_map ().length;
4018 u.format.v = length <= 0xFFFF ? 0 : 1;
4019 switch (u.format.v) {
4020 case 0: hb_barrier (); return_trace (u.format0.serialize (c, plan))return trace.ret (u.format0.serialize (c, plan), __PRETTY_FUNCTION__
, 4020)
;
4021 case 1: hb_barrier (); return_trace (u.format1.serialize (c, plan))return trace.ret (u.format1.serialize (c, plan), __PRETTY_FUNCTION__
, 4021)
;
4022 default:return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4022);
4023 }
4024 }
4025
4026 uint32_t map (unsigned v) const
4027 {
4028 switch (u.format.v) {
4029 case 0: hb_barrier (); return (u.format0.map (v));
4030 case 1: hb_barrier (); return (u.format1.map (v));
4031 default:return v;
4032 }
4033 }
4034
4035 unsigned get_map_count () const
4036 {
4037 switch (u.format.v) {
4038 case 0: hb_barrier (); return u.format0.get_map_count ();
4039 case 1: hb_barrier (); return u.format1.get_map_count ();
4040 default:return 0;
4041 }
4042 }
4043
4044 unsigned get_width () const
4045 {
4046 switch (u.format.v) {
4047 case 0: hb_barrier (); return u.format0.get_width ();
4048 case 1: hb_barrier (); return u.format1.get_width ();
4049 default:return 0;
4050 }
4051 }
4052
4053 unsigned get_inner_bit_count () const
4054 {
4055 switch (u.format.v) {
4056 case 0: hb_barrier (); return u.format0.get_inner_bit_count ();
4057 case 1: hb_barrier (); return u.format1.get_inner_bit_count ();
4058 default:return 0;
4059 }
4060 }
4061
4062 bool sanitize (hb_sanitize_context_t *c) const
4063 {
4064 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
4065 if (!u.format.v.sanitize (c)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4065);
4066 hb_barrier ();
4067 switch (u.format.v) {
4068 case 0: hb_barrier (); return_trace (u.format0.sanitize (c))return trace.ret (u.format0.sanitize (c), __PRETTY_FUNCTION__
, 4068)
;
4069 case 1: hb_barrier (); return_trace (u.format1.sanitize (c))return trace.ret (u.format1.sanitize (c), __PRETTY_FUNCTION__
, 4069)
;
4070 default:return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 4070);
4071 }
4072 }
4073
4074 DeltaSetIndexMap* copy (hb_serialize_context_t *c) const
4075 {
4076 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
4077 switch (u.format.v) {
4078 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__, 4078)
;
4079 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__, 4079)
;
4080 default:return_trace (nullptr)return trace.ret (nullptr, __PRETTY_FUNCTION__, 4080);
4081 }
4082 }
4083
4084 protected:
4085 union {
4086 struct { HBUINT8 v; } format; /* Format identifier */
4087 DeltaSetIndexMapFormat01<HBUINT16> format0;
4088 DeltaSetIndexMapFormat01<HBUINT32> format1;
4089 } u;
4090 public:
4091 DEFINE_SIZE_UNION (1, format.v)void _compiles_assertion_on_line_4091 () const { (void) this->
u.format.v.static_size; } void _instance_assertion_on_line_4091
() const { static_assert ((sizeof(this->u.format.v) == (1
)), ""); } static constexpr unsigned null_size = (1); static constexpr
unsigned min_size = (1)
;
4092};
4093
4094
4095struct ItemVarStoreInstancer
4096{
4097 ItemVarStoreInstancer (const ItemVariationStore *varStore_,
4098 const DeltaSetIndexMap *varIdxMap,
4099 hb_array_t<const int> coords,
4100 hb_scalar_cache_t *cache = nullptr) :
4101 varStore (varStore_), varIdxMap (varIdxMap), coords (coords), cache (cache)
4102 {
4103 if (!varStore)
4104 varStore = &Null(ItemVariationStore)NullHelper<ItemVariationStore>::get_null ();
4105 }
4106
4107 operator bool () const { return varStore && bool (coords); }
4108
4109 float operator[] (uint32_t varIdx) const
4110 { return (*this) (varIdx); }
4111
4112 float operator() (uint32_t varIdx, unsigned short offset = 0) const
4113 {
4114 if (!coords || varIdx == VarIdx::NO_VARIATION)
4115 return 0.f;
4116
4117 varIdx += offset;
4118 if (varIdxMap)
4119 varIdx = varIdxMap->map (varIdx);
4120 return varStore->get_delta (varIdx, coords, cache);
4121 }
4122
4123 const ItemVariationStore *varStore;
4124 const DeltaSetIndexMap *varIdxMap;
4125 hb_array_t<const int> coords;
4126 hb_scalar_cache_t *cache;
4127};
4128
4129struct MultiItemVarStoreInstancer
4130{
4131 MultiItemVarStoreInstancer (const MultiItemVariationStore *varStore,
4132 const DeltaSetIndexMap *varIdxMap,
4133 hb_array_t<const int> coords,
4134 hb_scalar_cache_t *cache = nullptr) :
4135 varStore (varStore), varIdxMap (varIdxMap), coords (coords), cache (cache)
4136 {
4137 if (!varStore)
4138 varStore = &Null(MultiItemVariationStore)NullHelper<MultiItemVariationStore>::get_null ();
Value stored to 'varStore' is never read
4139 }
4140
4141 operator bool () const { return varStore && bool (coords); }
4142
4143 float operator[] (uint32_t varIdx) const
4144 {
4145 float v = 0;
4146 (*this) (hb_array (&v, 1), varIdx);
4147 return v;
4148 }
4149
4150 void operator() (hb_array_t<float> out, uint32_t varIdx, unsigned short offset = 0) const
4151 {
4152 if (coords && varIdx != VarIdx::NO_VARIATION)
4153 {
4154 varIdx += offset;
4155 if (varIdxMap)
4156 varIdx = varIdxMap->map (varIdx);
4157 varStore->get_delta (varIdx, coords, out, cache);
4158 }
4159 else
4160 for (unsigned i = 0; i < out.length; i++)
4161 out.arrayZ[i] = 0.f;
4162 }
4163
4164 const MultiItemVariationStore *varStore;
4165 const DeltaSetIndexMap *varIdxMap;
4166 hb_array_t<const int> coords;
4167 hb_scalar_cache_t *cache;
4168};
4169
4170
4171/*
4172 * Feature Variations
4173 */
4174enum Cond_with_Var_flag_t
4175{
4176 KEEP_COND_WITH_VAR = 0,
4177 KEEP_RECORD_WITH_VAR = 1,
4178 DROP_COND_WITH_VAR = 2,
4179 DROP_RECORD_WITH_VAR = 3,
4180};
4181
4182struct Condition;
4183
4184template <typename Instancer>
4185static bool
4186_hb_recurse_condition_evaluate (const struct Condition &condition,
4187 const int *coords,
4188 unsigned int coord_len,
4189 Instancer *instancer);
4190
4191struct ConditionAxisRange
4192{
4193 friend struct Condition;
4194
4195 bool subset (hb_subset_context_t *c) const
4196 {
4197 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
4198 auto *out = c->serializer->embed (this);
4199 if (unlikely (!out)__builtin_expect (bool(!out), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4199);
4200
4201 const hb_map_t *index_map = &c->plan->axes_index_map;
4202 if (index_map->is_empty ()) return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 4202);
4203
4204 const hb_map_t& axes_old_index_tag_map = c->plan->axes_old_index_tag_map;
4205 hb_codepoint_t *axis_tag;
4206 if (!axes_old_index_tag_map.has (axisIndex, &axis_tag) ||
4207 !index_map->has (axisIndex))
4208 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4208);
4209
4210 const hb_hashmap_t<hb_tag_t, Triple>& normalized_axes_location = c->plan->axes_location;
4211 Triple axis_limit{-1.0, 0.0, 1.0};
4212 Triple *normalized_limit;
4213 if (normalized_axes_location.has (*axis_tag, &normalized_limit))
4214 axis_limit = *normalized_limit;
4215
4216 const hb_hashmap_t<hb_tag_t, TripleDistances>& axes_triple_distances = c->plan->axes_triple_distances;
4217 TripleDistances axis_triple_distances{1.0, 1.0};
4218 TripleDistances *triple_dists;
4219 if (axes_triple_distances.has (*axis_tag, &triple_dists))
4220 axis_triple_distances = *triple_dists;
4221
4222 float normalized_min = renormalizeValue ((double) filterRangeMinValue.to_float (), axis_limit, axis_triple_distances, false);
4223 float normalized_max = renormalizeValue ((double) filterRangeMaxValue.to_float (), axis_limit, axis_triple_distances, false);
4224 out->filterRangeMinValue.set_float (normalized_min);
4225 out->filterRangeMaxValue.set_float (normalized_max);
4226
4227 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__, 4228)
4228 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__, 4228)
;
4229 }
4230
4231 private:
4232 Cond_with_Var_flag_t keep_with_variations (hb_collect_feature_substitutes_with_var_context_t *c,
4233 hb_map_t *condition_map /* OUT */) const
4234 {
4235 //invalid axis index, drop the entire record
4236 if (!c->axes_index_tag_map->has (axisIndex))
4237 return DROP_RECORD_WITH_VAR;
4238
4239 hb_tag_t axis_tag = c->axes_index_tag_map->get (axisIndex);
4240
4241 Triple axis_range (-1.0, 0.0, 1.0);
4242 Triple *axis_limit;
4243 bool axis_set_by_user = false;
4244 if (c->axes_location->has (axis_tag, &axis_limit))
4245 {
4246 axis_range = *axis_limit;
4247 axis_set_by_user = true;
4248 }
4249
4250 float axis_min_val = axis_range.minimum;
4251 float axis_default_val = axis_range.middle;
4252 float axis_max_val = axis_range.maximum;
4253
4254 float filter_min_val = filterRangeMinValue.to_float ();
4255 float filter_max_val = filterRangeMaxValue.to_float ();
4256
4257 if (axis_default_val < filter_min_val ||
4258 axis_default_val > filter_max_val)
4259 c->apply = false;
4260
4261 //condition not met, drop the entire record
4262 if (axis_min_val > filter_max_val || axis_max_val < filter_min_val ||
4263 filter_min_val > filter_max_val)
4264 return DROP_RECORD_WITH_VAR;
4265
4266 //condition met and axis pinned, drop the condition
4267 if (axis_set_by_user && axis_range.is_point ())
4268 return DROP_COND_WITH_VAR;
4269
4270 if (filter_max_val != axis_max_val || filter_min_val != axis_min_val)
4271 {
4272 // add axisIndex->value into the hashmap so we can check if the record is
4273 // unique with variations
4274 uint16_t int_filter_max_val = (uint16_t) filterRangeMaxValue.to_int ();
4275 uint16_t int_filter_min_val = (uint16_t) filterRangeMinValue.to_int ();
4276 hb_codepoint_t val = (int_filter_max_val << 16) + int_filter_min_val;
4277
4278 condition_map->set (axisIndex, val);
4279 return KEEP_COND_WITH_VAR;
4280 }
4281 return KEEP_RECORD_WITH_VAR;
4282 }
4283
4284 template <typename Instancer>
4285 bool evaluate (const int *coords, unsigned int coord_len,
4286 Instancer *instancer HB_UNUSED__attribute__((unused))) const
4287 {
4288 int coord = axisIndex < coord_len ? coords[axisIndex] : 0;
4289 return filterRangeMinValue.to_int () <= coord && coord <= filterRangeMaxValue.to_int ();
4290 }
4291
4292 public:
4293 bool sanitize (hb_sanitize_context_t *c) const
4294 {
4295 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
4296 return_trace (c->check_struct (this))return trace.ret (c->check_struct (this), __PRETTY_FUNCTION__
, 4296)
;
4297 }
4298
4299 protected:
4300 HBUINT16 format; /* Format identifier--format = 1 */
4301 HBUINT16 axisIndex;
4302 F2DOT14 filterRangeMinValue;
4303 F2DOT14 filterRangeMaxValue;
4304 public:
4305 DEFINE_SIZE_STATIC (8)void _instance_assertion_on_line_4305 () 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)
;
4306};
4307
4308struct ConditionValue
4309{
4310 friend struct Condition;
4311
4312 bool subset (hb_subset_context_t *c) const
4313 {
4314 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
4315 // TODO(subset)
4316 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4316);
4317 }
4318
4319 private:
4320 template <typename Instancer>
4321 bool evaluate (const int *coords, unsigned int coord_len,
4322 Instancer *instancer) const
4323 {
4324 float value = defaultValue;
4325 value += (*instancer)[varIdx];
4326 return value > 0;
4327 }
4328
4329 bool subset (hb_subset_context_t *c,
4330 hb_subset_layout_context_t *l,
4331 bool insert_catch_all) const
4332 {
4333 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
4334 // TODO(subset)
4335 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4335);
4336 }
4337
4338 public:
4339 bool sanitize (hb_sanitize_context_t *c) const
4340 {
4341 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
4342 return_trace (c->check_struct (this))return trace.ret (c->check_struct (this), __PRETTY_FUNCTION__
, 4342)
;
4343 }
4344
4345 protected:
4346 HBUINT16 format; /* Format identifier--format = 2 */
4347 HBINT16 defaultValue; /* Value at default instance. */
4348 VarIdx varIdx; /* Variation index */
4349 public:
4350 DEFINE_SIZE_STATIC (8)void _instance_assertion_on_line_4350 () 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)
;
4351};
4352
4353struct ConditionAnd
4354{
4355 friend struct Condition;
4356
4357 bool subset (hb_subset_context_t *c) const
4358 {
4359 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
4360 // TODO(subset)
4361 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4361);
4362 }
4363
4364 private:
4365 template <typename Instancer>
4366 bool evaluate (const int *coords, unsigned int coord_len,
4367 Instancer *instancer) const
4368 {
4369 unsigned int count = conditions.len;
4370 for (unsigned int i = 0; i < count; i++)
4371 if (!_hb_recurse_condition_evaluate (this+conditions.arrayZ[i],
4372 coords, coord_len,
4373 instancer))
4374 return false;
4375 return true;
4376 }
4377
4378 bool subset (hb_subset_context_t *c,
4379 hb_subset_layout_context_t *l,
4380 bool insert_catch_all) const
4381 {
4382 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
4383 // TODO(subset)
4384 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4384);
4385 }
4386
4387 public:
4388 bool sanitize (hb_sanitize_context_t *c) const
4389 {
4390 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
4391 return_trace (conditions.sanitize (c, this))return trace.ret (conditions.sanitize (c, this), __PRETTY_FUNCTION__
, 4391)
;
4392 }
4393
4394 protected:
4395 HBUINT16 format; /* Format identifier--format = 3 */
4396 Array8OfOffset24To<struct Condition> conditions;
4397 public:
4398 DEFINE_SIZE_ARRAY (3, conditions)void _compiles_assertion_on_line_4398 () const { (void) (conditions
)[0].static_size; } void _instance_assertion_on_line_4398 () const
{ static_assert ((sizeof (*this) == (3) + (1 +0) * sizeof ((
conditions)[0])), ""); } static constexpr unsigned null_size =
(3); static constexpr unsigned min_size = (3)
;
4399};
4400
4401struct ConditionOr
4402{
4403 friend struct Condition;
4404
4405 bool subset (hb_subset_context_t *c) const
4406 {
4407 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
4408 // TODO(subset)
4409 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4409);
4410 }
4411
4412 private:
4413 template <typename Instancer>
4414 bool evaluate (const int *coords, unsigned int coord_len,
4415 Instancer *instancer) const
4416 {
4417 unsigned int count = conditions.len;
4418 for (unsigned int i = 0; i < count; i++)
4419 if (_hb_recurse_condition_evaluate (this+conditions.arrayZ[i],
4420 coords, coord_len,
4421 instancer))
4422 return true;
4423 return false;
4424 }
4425
4426 bool subset (hb_subset_context_t *c,
4427 hb_subset_layout_context_t *l,
4428 bool insert_catch_all) const
4429 {
4430 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
4431 // TODO(subset)
4432 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4432);
4433 }
4434
4435 public:
4436 bool sanitize (hb_sanitize_context_t *c) const
4437 {
4438 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
4439 return_trace (conditions.sanitize (c, this))return trace.ret (conditions.sanitize (c, this), __PRETTY_FUNCTION__
, 4439)
;
4440 }
4441
4442 protected:
4443 HBUINT16 format; /* Format identifier--format = 4 */
4444 Array8OfOffset24To<struct Condition> conditions;
4445 public:
4446 DEFINE_SIZE_ARRAY (3, conditions)void _compiles_assertion_on_line_4446 () const { (void) (conditions
)[0].static_size; } void _instance_assertion_on_line_4446 () const
{ static_assert ((sizeof (*this) == (3) + (1 +0) * sizeof ((
conditions)[0])), ""); } static constexpr unsigned null_size =
(3); static constexpr unsigned min_size = (3)
;
4447};
4448
4449struct ConditionNegate
4450{
4451 friend struct Condition;
4452
4453 bool subset (hb_subset_context_t *c) const
4454 {
4455 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
4456 // TODO(subset)
4457 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4457);
4458 }
4459
4460 private:
4461 template <typename Instancer>
4462 bool evaluate (const int *coords, unsigned int coord_len,
4463 Instancer *instancer) const
4464 {
4465 return !_hb_recurse_condition_evaluate (this+condition,
4466 coords, coord_len,
4467 instancer);
4468 }
4469
4470 bool subset (hb_subset_context_t *c,
4471 hb_subset_layout_context_t *l,
4472 bool insert_catch_all) const
4473 {
4474 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
4475 // TODO(subset)
4476 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4476);
4477 }
4478
4479 public:
4480 bool sanitize (hb_sanitize_context_t *c) const
4481 {
4482 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
4483 return_trace (condition.sanitize (c, this))return trace.ret (condition.sanitize (c, this), __PRETTY_FUNCTION__
, 4483)
;
4484 }
4485
4486 protected:
4487 HBUINT16 format; /* Format identifier--format = 5 */
4488 Offset24To<struct Condition> condition;
4489 public:
4490 DEFINE_SIZE_STATIC (5)void _instance_assertion_on_line_4490 () 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)
;
4491};
4492
4493struct Condition
4494{
4495 template <typename Instancer>
4496 bool evaluate (const int *coords, unsigned int coord_len,
4497 Instancer *instancer) const
4498 {
4499 switch (u.format.v) {
4500 case 1: hb_barrier (); return u.format1.evaluate (coords, coord_len, instancer);
4501 case 2: hb_barrier (); return u.format2.evaluate (coords, coord_len, instancer);
4502 case 3: hb_barrier (); return u.format3.evaluate (coords, coord_len, instancer);
4503 case 4: hb_barrier (); return u.format4.evaluate (coords, coord_len, instancer);
4504 case 5: hb_barrier (); return u.format5.evaluate (coords, coord_len, instancer);
4505 default:return false;
4506 }
4507 }
4508
4509 Cond_with_Var_flag_t keep_with_variations (hb_collect_feature_substitutes_with_var_context_t *c,
4510 hb_map_t *condition_map /* OUT */) const
4511 {
4512 switch (u.format.v) {
4513 case 1: hb_barrier (); return u.format1.keep_with_variations (c, condition_map);
4514 // TODO(subset)
4515 default: c->apply = false; return KEEP_COND_WITH_VAR;
4516 }
4517 }
4518
4519 template <typename context_t, typename ...Ts>
4520 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
4521 {
4522 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 ();
4523 TRACE_DISPATCH (this, u.format.v)hb_no_trace_t<typename context_t::return_t> trace;
4524 switch (u.format.v) {
4525 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__, 4525)
;
4526 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__, 4526)
;
4527 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__, 4527)
;
4528 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__, 4528)
;
4529 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__, 4529)
;
4530 default:return_trace (c->default_return_value ())return trace.ret (c->default_return_value (), __PRETTY_FUNCTION__
, 4530)
;
4531 }
4532 }
4533
4534 bool sanitize (hb_sanitize_context_t *c) const
4535 {
4536 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
4537
4538 if (unlikely (!c->check_start_recursion (HB_MAX_NESTING_LEVEL))__builtin_expect (bool(!c->check_start_recursion (64)), 0))
4539 return_trace (c->no_dispatch_return_value ())return trace.ret (c->no_dispatch_return_value (), __PRETTY_FUNCTION__
, 4539)
;
4540
4541 return_trace (c->end_recursion (this->dispatch (c)))return trace.ret (c->end_recursion (this->dispatch (c))
, __PRETTY_FUNCTION__, 4541)
;
4542 }
4543
4544 bool collect_var_indices (hb_set_t *var_indices,
4545 unsigned depth = HB_MAX_NESTING_LEVEL64) const;
4546
4547 bool serialize (hb_serialize_context_t *c,
4548 const Condition *src,
4549 const hb_map_t &varidx_map);
4550
4551 protected:
4552 union {
4553 struct { HBUINT16 v; } format; /* Format identifier */
4554 ConditionAxisRange format1;
4555 ConditionValue format2;
4556 ConditionAnd format3;
4557 ConditionOr format4;
4558 ConditionNegate format5;
4559 } u;
4560 public:
4561 DEFINE_SIZE_UNION (2, format.v)void _compiles_assertion_on_line_4561 () const { (void) this->
u.format.v.static_size; } void _instance_assertion_on_line_4561
() const { static_assert ((sizeof(this->u.format.v) == (2
)), ""); } static constexpr unsigned null_size = (2); static constexpr
unsigned min_size = (2)
;
4562};
4563
4564template <typename Instancer>
4565bool
4566_hb_recurse_condition_evaluate (const struct Condition &condition,
4567 const int *coords,
4568 unsigned int coord_len,
4569 Instancer *instancer)
4570{
4571 return condition.evaluate (coords, coord_len, instancer);
4572}
4573
4574struct ConditionList
4575{
4576 const Condition& operator[] (unsigned i) const
4577 { return this+conditions[i]; }
4578
4579 unsigned get_count () const { return conditions.len; }
4580
4581 bool serialize (hb_serialize_context_t *c,
4582 const ConditionList *src,
4583 const hb_inc_bimap_t &condition_map,
4584 const hb_map_t &varidx_map)
4585 {
4586 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
4587 if (unlikely (!c->extend_min (this))__builtin_expect (bool(!c->extend_min (this)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4587);
4588 conditions.len = condition_map.get_population ();
4589 if (unlikely (!c->extend (conditions))__builtin_expect (bool(!c->extend (conditions)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4589);
4590 for (unsigned i = 0; i < conditions.len; i++)
4591 {
4592 unsigned old_index = condition_map.backward (i);
4593 if (unlikely (old_index >= src->conditions.len ||__builtin_expect (bool(old_index >= src->conditions.len
|| !conditions[i].serialize_serialize ( c, &(src+src->
conditions[old_index]), varidx_map)), 0)
4594 !conditions[i].serialize_serialize (__builtin_expect (bool(old_index >= src->conditions.len
|| !conditions[i].serialize_serialize ( c, &(src+src->
conditions[old_index]), varidx_map)), 0)
4595 c, &(src+src->conditions[old_index]), varidx_map))__builtin_expect (bool(old_index >= src->conditions.len
|| !conditions[i].serialize_serialize ( c, &(src+src->
conditions[old_index]), varidx_map)), 0)
)
4596 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4596);
4597 }
4598 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 4598);
4599 }
4600
4601 bool sanitize (hb_sanitize_context_t *c) const
4602 {
4603 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
4604 return_trace (conditions.sanitize (c, this))return trace.ret (conditions.sanitize (c, this), __PRETTY_FUNCTION__
, 4604)
;
4605 }
4606
4607 protected:
4608 Array32OfOffset32To<Condition> conditions;
4609 public:
4610 DEFINE_SIZE_ARRAY (4, conditions)void _compiles_assertion_on_line_4610 () const { (void) (conditions
)[0].static_size; } void _instance_assertion_on_line_4610 () const
{ static_assert ((sizeof (*this) == (4) + (1 +0) * sizeof ((
conditions)[0])), ""); } static constexpr unsigned null_size =
(4); static constexpr unsigned min_size = (4)
;
4611};
4612
4613inline bool
4614Condition::collect_var_indices (hb_set_t *var_indices, unsigned depth) const
4615{
4616 if (unlikely (!depth)__builtin_expect (bool(!depth), 0)) return false;
4617 switch (u.format.v)
4618 {
4619 case 1:
4620 return true;
4621 case 2:
4622 if (u.format2.varIdx != VarIdx::NO_VARIATION)
4623 var_indices->add (u.format2.varIdx);
4624 return !var_indices->in_error ();
4625 case 3:
4626 for (const auto &offset : u.format3.conditions)
4627 if (unlikely (!(&u.format3+offset).collect_var_indices (var_indices,__builtin_expect (bool(!(&u.format3+offset).collect_var_indices
(var_indices, depth - 1)), 0)
4628 depth - 1))__builtin_expect (bool(!(&u.format3+offset).collect_var_indices
(var_indices, depth - 1)), 0)
)
4629 return false;
4630 return true;
4631 case 4:
4632 for (const auto &offset : u.format4.conditions)
4633 if (unlikely (!(&u.format4+offset).collect_var_indices (var_indices,__builtin_expect (bool(!(&u.format4+offset).collect_var_indices
(var_indices, depth - 1)), 0)
4634 depth - 1))__builtin_expect (bool(!(&u.format4+offset).collect_var_indices
(var_indices, depth - 1)), 0)
)
4635 return false;
4636 return true;
4637 case 5:
4638 return (&u.format5+u.format5.condition).collect_var_indices (var_indices,
4639 depth - 1);
4640 default:
4641 return false;
4642 }
4643}
4644
4645inline bool
4646Condition::serialize (hb_serialize_context_t *c,
4647 const Condition *src,
4648 const hb_map_t &varidx_map)
4649{
4650 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
4651 switch (src->u.format.v)
4652 {
4653 case 1:
4654 return_trace (bool (c->embed (&src->u.format1)))return trace.ret (bool (c->embed (&src->u.format1))
, __PRETTY_FUNCTION__, 4654)
;
4655 case 2:
4656 {
4657 auto *out = c->embed (&src->u.format2);
4658 if (unlikely (!out ||__builtin_expect (bool(!out || (src->u.format2.varIdx != VarIdx
::NO_VARIATION && !varidx_map.has (src->u.format2.
varIdx))), 0)
4659 (src->u.format2.varIdx != VarIdx::NO_VARIATION &&__builtin_expect (bool(!out || (src->u.format2.varIdx != VarIdx
::NO_VARIATION && !varidx_map.has (src->u.format2.
varIdx))), 0)
4660 !varidx_map.has (src->u.format2.varIdx)))__builtin_expect (bool(!out || (src->u.format2.varIdx != VarIdx
::NO_VARIATION && !varidx_map.has (src->u.format2.
varIdx))), 0)
)
4661 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4661);
4662 out->varIdx = src->u.format2.varIdx == VarIdx::NO_VARIATION ?
4663 src->u.format2.varIdx : varidx_map.get (src->u.format2.varIdx);
4664 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 4664);
4665 }
4666 case 3:
4667 {
4668 auto *out = c->start_embed<ConditionAnd> ();
4669 if (unlikely (!c->extend_min (out))__builtin_expect (bool(!c->extend_min (out)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4669);
4670 out->format = 3;
4671 out->conditions.len = src->u.format3.conditions.len;
4672 if (unlikely (!c->extend (out->conditions))__builtin_expect (bool(!c->extend (out->conditions)), 0
)
) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4672);
4673 for (unsigned i = 0; i < out->conditions.len; i++)
4674 if (unlikely (!out->conditions[i].serialize_serialize (__builtin_expect (bool(!out->conditions[i].serialize_serialize
( c, &(&src->u.format3+src->u.format3.conditions
[i]), varidx_map)), 0)
4675 c, &(&src->u.format3+src->u.format3.conditions[i]),__builtin_expect (bool(!out->conditions[i].serialize_serialize
( c, &(&src->u.format3+src->u.format3.conditions
[i]), varidx_map)), 0)
4676 varidx_map))__builtin_expect (bool(!out->conditions[i].serialize_serialize
( c, &(&src->u.format3+src->u.format3.conditions
[i]), varidx_map)), 0)
)
4677 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4677);
4678 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 4678);
4679 }
4680 case 4:
4681 {
4682 auto *out = c->start_embed<ConditionOr> ();
4683 if (unlikely (!c->extend_min (out))__builtin_expect (bool(!c->extend_min (out)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4683);
4684 out->format = 4;
4685 out->conditions.len = src->u.format4.conditions.len;
4686 if (unlikely (!c->extend (out->conditions))__builtin_expect (bool(!c->extend (out->conditions)), 0
)
) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4686);
4687 for (unsigned i = 0; i < out->conditions.len; i++)
4688 if (unlikely (!out->conditions[i].serialize_serialize (__builtin_expect (bool(!out->conditions[i].serialize_serialize
( c, &(&src->u.format4+src->u.format4.conditions
[i]), varidx_map)), 0)
4689 c, &(&src->u.format4+src->u.format4.conditions[i]),__builtin_expect (bool(!out->conditions[i].serialize_serialize
( c, &(&src->u.format4+src->u.format4.conditions
[i]), varidx_map)), 0)
4690 varidx_map))__builtin_expect (bool(!out->conditions[i].serialize_serialize
( c, &(&src->u.format4+src->u.format4.conditions
[i]), varidx_map)), 0)
)
4691 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4691);
4692 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 4692);
4693 }
4694 case 5:
4695 {
4696 auto *out = c->embed (&src->u.format5);
4697 if (unlikely (!out ||__builtin_expect (bool(!out || !out->condition.serialize_serialize
( c, &(&src->u.format5+src->u.format5.condition
), varidx_map)), 0)
4698 !out->condition.serialize_serialize (__builtin_expect (bool(!out || !out->condition.serialize_serialize
( c, &(&src->u.format5+src->u.format5.condition
), varidx_map)), 0)
4699 c, &(&src->u.format5+src->u.format5.condition),__builtin_expect (bool(!out || !out->condition.serialize_serialize
( c, &(&src->u.format5+src->u.format5.condition
), varidx_map)), 0)
4700 varidx_map))__builtin_expect (bool(!out || !out->condition.serialize_serialize
( c, &(&src->u.format5+src->u.format5.condition
), varidx_map)), 0)
)
4701 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4701);
4702 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 4702);
4703 }
4704 default:
4705 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4705);
4706 }
4707}
4708
4709struct ConditionSet
4710{
4711 bool evaluate (const int *coords, unsigned int coord_len,
4712 ItemVarStoreInstancer *instancer) const
4713 {
4714 unsigned int count = conditions.len;
4715 for (unsigned int i = 0; i < count; i++)
4716 if (!(this+conditions.arrayZ[i]).evaluate (coords, coord_len, instancer))
4717 return false;
4718 return true;
4719 }
4720
4721 void keep_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const
4722 {
4723 hb_map_t *condition_map = hb_map_create ();
4724 if (unlikely (!condition_map)__builtin_expect (bool(!condition_map), 0)) return;
4725 hb::shared_ptr<hb_map_t> p {condition_map};
4726
4727 hb_set_t *cond_set = hb_set_create ();
4728 if (unlikely (!cond_set)__builtin_expect (bool(!cond_set), 0)) return;
4729 hb::shared_ptr<hb_set_t> s {cond_set};
4730
4731 c->apply = true;
4732 bool should_keep = false;
4733 unsigned num_kept_cond = 0, cond_idx = 0;
4734 for (const auto& offset : conditions)
4735 {
4736 Cond_with_Var_flag_t ret = (this+offset).keep_with_variations (c, condition_map);
4737 // condition is not met or condition out of range, drop the entire record
4738 if (ret == DROP_RECORD_WITH_VAR)
4739 return;
4740
4741 if (ret == KEEP_COND_WITH_VAR)
4742 {
4743 should_keep = true;
4744 cond_set->add (cond_idx);
4745 num_kept_cond++;
4746 }
4747
4748 if (ret == KEEP_RECORD_WITH_VAR)
4749 should_keep = true;
4750
4751 cond_idx++;
4752 }
4753
4754 if (!should_keep) return;
4755
4756 //check if condition_set is unique with variations
4757 if (c->conditionset_map->has (p))
4758 //duplicate found, drop the entire record
4759 return;
4760
4761 c->conditionset_map->set (p, 1);
4762 c->record_cond_idx_map->set (c->cur_record_idx, s);
4763 if (should_keep && num_kept_cond == 0)
4764 c->universal = true;
4765 }
4766
4767 bool subset (hb_subset_context_t *c,
4768 hb_subset_layout_context_t *l,
4769 bool insert_catch_all) const
4770 {
4771 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
4772 auto *out = c->serializer->start_embed (this);
4773 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__, 4773);
4774
4775 if (insert_catch_all) return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 4775);
4776
4777 hb_set_t *retained_cond_set = nullptr;
4778 if (l->feature_record_cond_idx_map != nullptr)
4779 retained_cond_set = l->feature_record_cond_idx_map->get (l->cur_feature_var_record_idx);
4780
4781 unsigned int count = conditions.len;
4782 for (unsigned int i = 0; i < count; i++)
4783 {
4784 if (retained_cond_set != nullptr && !retained_cond_set->has (i))
4785 continue;
4786 subset_offset_array (c, out->conditions, this) (conditions[i]);
4787 }
4788
4789 return_trace (bool (out->conditions))return trace.ret (bool (out->conditions), __PRETTY_FUNCTION__
, 4789)
;
4790 }
4791
4792 bool sanitize (hb_sanitize_context_t *c) const
4793 {
4794 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
4795 return_trace (conditions.sanitize (c, this))return trace.ret (conditions.sanitize (c, this), __PRETTY_FUNCTION__
, 4795)
;
4796 }
4797
4798 protected:
4799 Array16OfOffset32To<Condition> conditions;
4800 public:
4801 DEFINE_SIZE_ARRAY (2, conditions)void _compiles_assertion_on_line_4801 () const { (void) (conditions
)[0].static_size; } void _instance_assertion_on_line_4801 () const
{ static_assert ((sizeof (*this) == (2) + (1 +0) * sizeof ((
conditions)[0])), ""); } static constexpr unsigned null_size =
(2); static constexpr unsigned min_size = (2)
;
4802};
4803
4804struct FeatureTableSubstitutionRecord
4805{
4806 friend struct FeatureTableSubstitution;
4807
4808 void collect_lookups (const void *base, hb_set_t *lookup_indexes /* OUT */) const
4809 {
4810 return (base+feature).add_lookup_indexes_to (lookup_indexes);
4811 }
4812
4813 void closure_features (const void *base,
4814 const hb_map_t *lookup_indexes,
4815 hb_set_t *feature_indexes /* OUT */) const
4816 {
4817 if ((base+feature).intersects_lookup_indexes (lookup_indexes))
4818 feature_indexes->add (featureIndex);
4819 }
4820
4821 void collect_feature_substitutes_with_variations (hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
4822 hb_set_t& catch_all_record_feature_idxes,
4823 const hb_set_t *feature_indices,
4824 const void *base) const
4825 {
4826 if (feature_indices->has (featureIndex))
4827 {
4828 feature_substitutes_map->set (featureIndex, &(base+feature));
4829 catch_all_record_feature_idxes.add (featureIndex);
4830 }
4831 }
4832
4833 bool serialize (hb_subset_layout_context_t *c,
4834 unsigned feature_index,
4835 const Feature *f, const Tag *tag)
4836 {
4837 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
4838 hb_serialize_context_t *s = c->subset_context->serializer;
4839 if (unlikely (!s->extend_min (this))__builtin_expect (bool(!s->extend_min (this)), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4839);
4840
4841 uint32_t *new_feature_idx;
4842 if (!c->feature_map_w_duplicates->has (feature_index, &new_feature_idx))
4843 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4843);
4844
4845 if (!s->check_assign (featureIndex, *new_feature_idx, HB_SERIALIZE_ERROR_INT_OVERFLOW))
4846 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4846);
4847
4848 s->push ();
4849 bool ret = f->subset (c->subset_context, c, tag);
4850 if (ret) s->add_link (feature, s->pop_pack ());
4851 else s->pop_discard ();
4852
4853 return_trace (ret)return trace.ret (ret, __PRETTY_FUNCTION__, 4853);
4854 }
4855
4856 bool subset (hb_subset_layout_context_t *c, const void *base) const
4857 {
4858 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
4859 uint32_t *new_feature_index;
4860 if (!c->feature_map_w_duplicates->has (featureIndex, &new_feature_index))
4861 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4861);
4862
4863 auto *out = c->subset_context->serializer->embed (this);
4864 if (unlikely (!out)__builtin_expect (bool(!out), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4864);
4865
4866 out->featureIndex = *new_feature_index;
4867 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__, 4867)
;
4868 }
4869
4870 bool sanitize (hb_sanitize_context_t *c, const void *base) const
4871 {
4872 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
4873 return_trace (c->check_struct (this) && feature.sanitize (c, base))return trace.ret (c->check_struct (this) && feature
.sanitize (c, base), __PRETTY_FUNCTION__, 4873)
;
4874 }
4875
4876 protected:
4877 HBUINT16 featureIndex;
4878 Offset32To<Feature> feature;
4879 public:
4880 DEFINE_SIZE_STATIC (6)void _instance_assertion_on_line_4880 () 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)
;
4881};
4882
4883struct FeatureTableSubstitution
4884{
4885 const Feature *find_substitute (unsigned int feature_index) const
4886 {
4887 unsigned int count = substitutions.len;
4888 for (unsigned int i = 0; i < count; i++)
4889 {
4890 const FeatureTableSubstitutionRecord &record = substitutions.arrayZ[i];
4891 if (record.featureIndex == feature_index)
4892 return &(this+record.feature);
4893 }
4894 return nullptr;
4895 }
4896
4897 void collect_lookups (const hb_set_t *feature_indexes,
4898 hb_set_t *lookup_indexes /* OUT */) const
4899 {
4900 + hb_iter (substitutions)
4901 | hb_filter (feature_indexes, &FeatureTableSubstitutionRecord::featureIndex)
4902 | hb_apply ([this, lookup_indexes] (const FeatureTableSubstitutionRecord& r)
4903 { r.collect_lookups (this, lookup_indexes); })
4904 ;
4905 }
4906
4907 void closure_features (const hb_map_t *lookup_indexes,
4908 hb_set_t *feature_indexes /* OUT */) const
4909 {
4910 for (const FeatureTableSubstitutionRecord& record : substitutions)
4911 record.closure_features (this, lookup_indexes, feature_indexes);
4912 }
4913
4914 bool intersects_features (const hb_map_t *feature_index_map) const
4915 {
4916 for (const FeatureTableSubstitutionRecord& record : substitutions)
4917 {
4918 if (feature_index_map->has (record.featureIndex)) return true;
4919 }
4920 return false;
4921 }
4922
4923 void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const
4924 {
4925 for (const FeatureTableSubstitutionRecord& record : substitutions)
4926 record.collect_feature_substitutes_with_variations (c->feature_substitutes_map,
4927 c->catch_all_record_feature_idxes,
4928 c->feature_indices, this);
4929 }
4930
4931 bool subset (hb_subset_context_t *c,
4932 hb_subset_layout_context_t *l,
4933 bool insert_catch_all) const
4934 {
4935 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
4936 auto *out = c->serializer->start_embed (*this);
4937 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__, 4937);
4938
4939 out->version.major = version.major;
4940 out->version.minor = version.minor;
4941
4942 if (insert_catch_all)
4943 {
4944 for (unsigned feature_index : *(l->catch_all_record_feature_idxes))
4945 {
4946 hb_pair_t<const void*, const void*> *p;
4947 if (!l->feature_idx_tag_map->has (feature_index, &p))
4948 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4948);
4949 auto *o = out->substitutions.serialize_append (c->serializer);
4950 if (!o->serialize (l, feature_index,
4951 reinterpret_cast<const Feature*> (p->first),
4952 reinterpret_cast<const Tag*> (p->second)))
4953 return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 4953);
4954 }
4955 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 4955);
4956 }
4957
4958 + substitutions.iter ()
4959 | hb_apply (subset_record_array (l, &(out->substitutions), this))
4960 ;
4961
4962 return_trace (bool (out->substitutions))return trace.ret (bool (out->substitutions), __PRETTY_FUNCTION__
, 4962)
;
4963 }
4964
4965 bool sanitize (hb_sanitize_context_t *c) const
4966 {
4967 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
4968 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__, 4971)
4969 hb_barrier () &&return trace.ret (version.sanitize (c) && hb_barrier (
) && __builtin_expect (bool(version.major == 1), 1) &&
substitutions.sanitize (c, this), __PRETTY_FUNCTION__, 4971)
4970 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__, 4971)
4971 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__, 4971)
;
4972 }
4973
4974 protected:
4975 FixedVersion<> version; /* Version--0x00010000u */
4976 Array16Of<FeatureTableSubstitutionRecord>
4977 substitutions;
4978 public:
4979 DEFINE_SIZE_ARRAY (6, substitutions)void _compiles_assertion_on_line_4979 () const { (void) (substitutions
)[0].static_size; } void _instance_assertion_on_line_4979 () const
{ static_assert ((sizeof (*this) == (6) + (1 +0) * sizeof ((
substitutions)[0])), ""); } static constexpr unsigned null_size
= (6); static constexpr unsigned min_size = (6)
;
4980};
4981
4982struct FeatureVariationRecord
4983{
4984 friend struct FeatureVariations;
4985
4986 void collect_lookups (const void *base,
4987 const hb_set_t *feature_indexes,
4988 hb_set_t *lookup_indexes /* OUT */) const
4989 {
4990 return (base+substitutions).collect_lookups (feature_indexes, lookup_indexes);
4991 }
4992
4993 void closure_features (const void *base,
4994 const hb_map_t *lookup_indexes,
4995 hb_set_t *feature_indexes /* OUT */) const
4996 {
4997 (base+substitutions).closure_features (lookup_indexes, feature_indexes);
4998 }
4999
5000 bool intersects_features (const void *base, const hb_map_t *feature_index_map) const
5001 {
5002 return (base+substitutions).intersects_features (feature_index_map);
5003 }
5004
5005 void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c,
5006 const void *base) const
5007 {
5008 (base+conditions).keep_with_variations (c);
5009 if (c->apply && !c->variation_applied)
5010 {
5011 (base+substitutions).collect_feature_substitutes_with_variations (c);
5012 c->variation_applied = true; // set variations only once
5013 }
5014 }
5015
5016 bool subset (hb_subset_layout_context_t *c, const void *base,
5017 bool insert_catch_all = false) const
5018 {
5019 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
5020 auto *out = c->subset_context->serializer->embed (this);
5021 if (unlikely (!out)__builtin_expect (bool(!out), 0)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 5021);
5022
5023 out->conditions.serialize_subset (c->subset_context, conditions, base, c, insert_catch_all);
5024 out->substitutions.serialize_subset (c->subset_context, substitutions, base, c, insert_catch_all);
5025
5026 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 5026);
5027 }
5028
5029 bool sanitize (hb_sanitize_context_t *c, const void *base) const
5030 {
5031 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
5032 return_trace (conditions.sanitize (c, base) &&return trace.ret (conditions.sanitize (c, base) && substitutions
.sanitize (c, base), __PRETTY_FUNCTION__, 5033)
5033 substitutions.sanitize (c, base))return trace.ret (conditions.sanitize (c, base) && substitutions
.sanitize (c, base), __PRETTY_FUNCTION__, 5033)
;
5034 }
5035
5036 protected:
5037 Offset32To<ConditionSet>
5038 conditions;
5039 Offset32To<FeatureTableSubstitution>
5040 substitutions;
5041 public:
5042 DEFINE_SIZE_STATIC (8)void _instance_assertion_on_line_5042 () 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)
;
5043};
5044
5045struct FeatureVariations
5046{
5047 static constexpr unsigned NOT_FOUND_INDEX = 0xFFFFFFFFu;
5048
5049 unsigned record_count () const
5050 {
5051 return varRecords.len;
5052 }
5053
5054 bool find_index (const int *coords, unsigned int coord_len,
5055 unsigned int *index,
5056 ItemVarStoreInstancer *instancer) const
5057 {
5058 unsigned int count = varRecords.len;
5059 for (unsigned int i = 0; i < count; i++)
5060 {
5061 const FeatureVariationRecord &record = varRecords.arrayZ[i];
5062 if ((this+record.conditions).evaluate (coords, coord_len, instancer))
5063 {
5064 *index = i;
5065 return true;
5066 }
5067 }
5068 *index = NOT_FOUND_INDEX;
5069 return false;
5070 }
5071
5072 const Feature *find_substitute (unsigned int variations_index,
5073 unsigned int feature_index) const
5074 {
5075 const FeatureVariationRecord &record = varRecords[variations_index];
5076 return (this+record.substitutions).find_substitute (feature_index);
5077 }
5078
5079 void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const
5080 {
5081 unsigned int count = varRecords.len;
5082 for (unsigned int i = 0; i < count; i++)
5083 {
5084 c->cur_record_idx = i;
5085 varRecords[i].collect_feature_substitutes_with_variations (c, this);
5086 if (c->universal)
5087 break;
5088 }
5089 if (c->universal || c->record_cond_idx_map->is_empty ())
5090 c->catch_all_record_feature_idxes.reset ();
5091 }
5092
5093 FeatureVariations* copy (hb_serialize_context_t *c) const
5094 {
5095 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
5096 return_trace (c->embed (*this))return trace.ret (c->embed (*this), __PRETTY_FUNCTION__, 5096
)
;
5097 }
5098
5099 void collect_lookups (const hb_set_t *feature_indexes,
5100 const hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map,
5101 hb_set_t *lookup_indexes /* OUT */) const
5102 {
5103 unsigned count = varRecords.len;
5104 for (unsigned int i = 0; i < count; i++)
5105 {
5106 if (feature_record_cond_idx_map &&
5107 !feature_record_cond_idx_map->has (i))
5108 continue;
5109 varRecords[i].collect_lookups (this, feature_indexes, lookup_indexes);
5110 }
5111 }
5112
5113 void closure_features (const hb_map_t *lookup_indexes,
5114 const hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map,
5115 hb_set_t *feature_indexes /* OUT */) const
5116 {
5117 unsigned int count = varRecords.len;
5118 for (unsigned int i = 0; i < count; i++)
5119 {
5120 if (feature_record_cond_idx_map != nullptr &&
5121 !feature_record_cond_idx_map->has (i))
5122 continue;
5123 varRecords[i].closure_features (this, lookup_indexes, feature_indexes);
5124 }
5125 }
5126
5127 bool subset (hb_subset_context_t *c,
5128 hb_subset_layout_context_t *l) const
5129 {
5130 TRACE_SUBSET (this)hb_no_trace_t<bool> trace;
5131 auto *out = c->serializer->start_embed (*this);
5132 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__, 5132);
5133
5134 out->version.major = version.major;
5135 out->version.minor = version.minor;
5136
5137 int keep_up_to = -1;
5138 for (int i = varRecords.len - 1; i >= 0; i--) {
5139 if (varRecords[i].intersects_features (this, l->feature_map_w_duplicates)) {
5140 keep_up_to = i;
5141 break;
5142 }
5143 }
5144
5145 unsigned count = (unsigned) (keep_up_to + 1);
5146 for (unsigned i = 0; i < count; i++)
5147 {
5148 if (l->feature_record_cond_idx_map != nullptr &&
5149 !l->feature_record_cond_idx_map->has (i))
5150 continue;
5151
5152 l->cur_feature_var_record_idx = i;
5153 subset_record_array (l, &(out->varRecords), this) (varRecords[i]);
5154 }
5155
5156 if (out->varRecords.len && !l->catch_all_record_feature_idxes->is_empty ())
5157 {
5158 bool insert_catch_all_record = true;
5159 subset_record_array (l, &(out->varRecords), this, insert_catch_all_record) (varRecords[0]);
5160 }
5161
5162 return_trace (bool (out->varRecords))return trace.ret (bool (out->varRecords), __PRETTY_FUNCTION__
, 5162)
;
5163 }
5164
5165 bool sanitize (hb_sanitize_context_t *c) const
5166 {
5167 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
5168 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__, 5171)
5169 hb_barrier () &&return trace.ret (version.sanitize (c) && hb_barrier (
) && __builtin_expect (bool(version.major == 1), 1) &&
varRecords.sanitize (c, this), __PRETTY_FUNCTION__, 5171)
5170 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__, 5171)
5171 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__, 5171)
;
5172 }
5173
5174 protected:
5175 FixedVersion<> version; /* Version--0x00010000u */
5176 Array32Of<FeatureVariationRecord>
5177 varRecords;
5178 public:
5179 DEFINE_SIZE_ARRAY_SIZED (8, varRecords)size_t get_size () const { return (8 - (varRecords).min_size +
(varRecords).get_size ()); } void _compiles_assertion_on_line_5179
() const { (void) (varRecords)[0].static_size; } void _instance_assertion_on_line_5179
() const { static_assert ((sizeof (*this) == (8) + (1 +0) * sizeof
((varRecords)[0])), ""); } static constexpr unsigned null_size
= (8); static constexpr unsigned min_size = (8)
;
5180};
5181
5182
5183/*
5184 * Device Tables
5185 */
5186
5187struct HintingDevice
5188{
5189 friend struct Device;
5190
5191 private:
5192
5193 hb_position_t get_x_delta (hb_font_t *font) const
5194 { return get_delta (font->x_ppem, font->x_scale); }
5195
5196 hb_position_t get_y_delta (hb_font_t *font) const
5197 { return get_delta (font->y_ppem, font->y_scale); }
5198
5199 public:
5200
5201 size_t get_size () const
5202 {
5203 unsigned int f = deltaFormat;
5204 if (unlikely (f < 1 || f > 3 || startSize > endSize)__builtin_expect (bool(f < 1 || f > 3 || startSize >
endSize), 0)
) return 3 * HBUINT16::static_size;
5205 return HBUINT16::static_size * (4 + ((endSize - startSize) >> (4 - f)));
5206 }
5207
5208 bool sanitize (hb_sanitize_context_t *c) const
5209 {
5210 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
5211 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__
, 5211)
;
5212 }
5213
5214 HintingDevice* copy (hb_serialize_context_t *c) const
5215 {
5216 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
5217 return_trace (c->embed<HintingDevice> (this))return trace.ret (c->embed<HintingDevice> (this), __PRETTY_FUNCTION__
, 5217)
;
5218 }
5219
5220 private:
5221
5222 int get_delta (unsigned int ppem, int scale) const
5223 {
5224 if (!ppem) return 0;
5225
5226 int pixels = get_delta_pixels (ppem);
5227
5228 if (!pixels) return 0;
5229
5230 return (int) (pixels * (int64_t) scale / ppem);
5231 }
5232 int get_delta_pixels (unsigned int ppem_size) const
5233 {
5234 unsigned int f = deltaFormat;
5235 if (unlikely (f < 1 || f > 3)__builtin_expect (bool(f < 1 || f > 3), 0))
5236 return 0;
5237
5238 if (ppem_size < startSize || ppem_size > endSize)
5239 return 0;
5240
5241 unsigned int s = ppem_size - startSize;
5242
5243 unsigned int byte = deltaValueZ[s >> (4 - f)];
5244 unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f)));
5245 unsigned int mask = (0xFFFFu >> (16 - (1 << f)));
5246
5247 int delta = bits & mask;
5248
5249 if ((unsigned int) delta >= ((mask + 1) >> 1))
5250 delta -= mask + 1;
5251
5252 return delta;
5253 }
5254
5255 protected:
5256 HBUINT16 startSize; /* Smallest size to correct--in ppem */
5257 HBUINT16 endSize; /* Largest size to correct--in ppem */
5258 HBUINT16 deltaFormat; /* Format of DeltaValue array data: 1, 2, or 3
5259 * 1 Signed 2-bit value, 8 values per uint16
5260 * 2 Signed 4-bit value, 4 values per uint16
5261 * 3 Signed 8-bit value, 2 values per uint16
5262 */
5263 UnsizedArrayOf<HBUINT16>
5264 deltaValueZ; /* Array of compressed data */
5265 public:
5266 DEFINE_SIZE_ARRAY (6, deltaValueZ)void _compiles_assertion_on_line_5266 () const { (void) (deltaValueZ
)[0].static_size; } void _instance_assertion_on_line_5266 () const
{ static_assert ((sizeof (*this) == (6) + (1 +0) * sizeof ((
deltaValueZ)[0])), ""); } static constexpr unsigned null_size
= (6); static constexpr unsigned min_size = (6)
;
5267};
5268
5269struct VariationDevice
5270{
5271 friend struct Device;
5272
5273 private:
5274
5275 hb_position_t get_x_delta (hb_font_t *font,
5276 const ItemVariationStore &store,
5277 hb_scalar_cache_t *store_cache = nullptr) const
5278 { return !font->has_nonzero_coords ? 0 : font->em_scalef_x (get_delta (font, store, store_cache)); }
5279
5280 hb_position_t get_y_delta (hb_font_t *font,
5281 const ItemVariationStore &store,
5282 hb_scalar_cache_t *store_cache = nullptr) const
5283 { return !font->has_nonzero_coords ? 0 : font->em_scalef_y (get_delta (font, store, store_cache)); }
5284
5285 VariationDevice* copy (hb_serialize_context_t *c,
5286 const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const
5287 {
5288 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
5289 if (!layout_variation_idx_delta_map) return_trace (nullptr)return trace.ret (nullptr, __PRETTY_FUNCTION__, 5289);
5290
5291 hb_pair_t<unsigned, int> *v;
5292 if (!layout_variation_idx_delta_map->has (varIdx, &v))
5293 return_trace (nullptr)return trace.ret (nullptr, __PRETTY_FUNCTION__, 5293);
5294 /* The varidx was mapped to "no variations" during instancing (e.g. the
5295 * instantiated row is all zeros). Drop the device instead of emitting one
5296 * with an out-of-range varidx. */
5297 if (hb_first (*v) == HB_OT_LAYOUT_NO_VARIATIONS_INDEX0xFFFFFFFFu)
5298 return_trace (nullptr)return trace.ret (nullptr, __PRETTY_FUNCTION__, 5298);
5299
5300 c->start_zerocopy (this->static_size);
5301 auto *out = c->embed (this);
5302 if (unlikely (!out)__builtin_expect (bool(!out), 0)) return_trace (nullptr)return trace.ret (nullptr, __PRETTY_FUNCTION__, 5302);
5303
5304 if (!c->check_assign (out->varIdx, hb_first (*v), HB_SERIALIZE_ERROR_INT_OVERFLOW))
5305 return_trace (nullptr)return trace.ret (nullptr, __PRETTY_FUNCTION__, 5305);
5306 return_trace (out)return trace.ret (out, __PRETTY_FUNCTION__, 5306);
5307 }
5308
5309 void collect_variation_index (hb_collect_variation_indices_context_t *c) const
5310 { c->layout_variation_indices->add (varIdx); }
5311
5312 bool sanitize (hb_sanitize_context_t *c) const
5313 {
5314 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
5315 return_trace (c->check_struct (this))return trace.ret (c->check_struct (this), __PRETTY_FUNCTION__
, 5315)
;
5316 }
5317
5318 private:
5319
5320 float get_delta (hb_font_t *font,
5321 const ItemVariationStore &store,
5322 hb_scalar_cache_t *store_cache = nullptr) const
5323 {
5324 return store.get_delta (varIdx, font->coords, font->num_coords, store_cache);
5325 }
5326
5327 protected:
5328 VarIdx varIdx; /* Variation index */
5329 HBUINT16 deltaFormat; /* Format identifier for this table: 0x0x8000 */
5330 public:
5331 DEFINE_SIZE_STATIC (6)void _instance_assertion_on_line_5331 () 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)
;
5332};
5333
5334struct DeviceHeader
5335{
5336 protected:
5337 HBUINT16 reserved1;
5338 HBUINT16 reserved2;
5339 public:
5340 HBUINT16 format; /* Format identifier */
5341 public:
5342 DEFINE_SIZE_STATIC (6)void _instance_assertion_on_line_5342 () 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)
;
5343};
5344
5345struct Device
5346{
5347 hb_position_t get_x_delta (hb_font_t *font,
5348 const ItemVariationStore &store=Null (ItemVariationStore)NullHelper<ItemVariationStore>::get_null (),
5349 hb_scalar_cache_t *store_cache = nullptr) const
5350 {
5351 switch (u.b.format)
5352 {
5353#ifndef HB_NO_HINTING
5354 case 1: case 2: case 3:
5355 hb_barrier ();
5356 return u.hinting.get_x_delta (font);
5357#endif
5358#ifndef HB_NO_VAR
5359 case 0x8000:
5360 hb_barrier ();
5361 return u.variation.get_x_delta (font, store, store_cache);
5362#endif
5363 default:
5364 return 0;
5365 }
5366 }
5367 hb_position_t get_y_delta (hb_font_t *font,
5368 const ItemVariationStore &store=Null (ItemVariationStore)NullHelper<ItemVariationStore>::get_null (),
5369 hb_scalar_cache_t *store_cache = nullptr) const
5370 {
5371 switch (u.b.format)
5372 {
5373 case 1: case 2: case 3:
5374#ifndef HB_NO_HINTING
5375 hb_barrier ();
5376 return u.hinting.get_y_delta (font);
5377#endif
5378#ifndef HB_NO_VAR
5379 case 0x8000:
5380 hb_barrier ();
5381 return u.variation.get_y_delta (font, store, store_cache);
5382#endif
5383 default:
5384 return 0;
5385 }
5386 }
5387
5388 bool sanitize (hb_sanitize_context_t *c) const
5389 {
5390 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
5391 if (!u.b.format.sanitize (c)) return_trace (false)return trace.ret (false, __PRETTY_FUNCTION__, 5391);
5392 switch (u.b.format) {
5393#ifndef HB_NO_HINTING
5394 case 1: case 2: case 3:
5395 hb_barrier ();
5396 return_trace (u.hinting.sanitize (c))return trace.ret (u.hinting.sanitize (c), __PRETTY_FUNCTION__
, 5396)
;
5397#endif
5398#ifndef HB_NO_VAR
5399 case 0x8000:
5400 hb_barrier ();
5401 return_trace (u.variation.sanitize (c))return trace.ret (u.variation.sanitize (c), __PRETTY_FUNCTION__
, 5401)
;
5402#endif
5403 default:
5404 return_trace (true)return trace.ret (true, __PRETTY_FUNCTION__, 5404);
5405 }
5406 }
5407
5408 Device* copy (hb_serialize_context_t *c,
5409 const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map=nullptr) const
5410 {
5411 TRACE_SERIALIZE (this)hb_no_trace_t<bool> trace;
5412 switch (u.b.format) {
5413#ifndef HB_NO_HINTING
5414 case 1:
5415 case 2:
5416 case 3:
5417 hb_barrier ();
5418 return_trace (reinterpret_cast<Device *> (u.hinting.copy (c)))return trace.ret (reinterpret_cast<Device *> (u.hinting
.copy (c)), __PRETTY_FUNCTION__, 5418)
;
5419#endif
5420#ifndef HB_NO_VAR
5421 case 0x8000:
5422 hb_barrier ();
5423 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__
, 5423)
;
5424#endif
5425 default:
5426 return_trace (nullptr)return trace.ret (nullptr, __PRETTY_FUNCTION__, 5426);
5427 }
5428 }
5429
5430 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
5431 {
5432 switch (u.b.format) {
5433#ifndef HB_NO_HINTING
5434 case 1:
5435 case 2:
5436 case 3:
5437 return;
5438#endif
5439#ifndef HB_NO_VAR
5440 case 0x8000:
5441 hb_barrier ();
5442 u.variation.collect_variation_index (c);
5443 return;
5444#endif
5445 default:
5446 return;
5447 }
5448 }
5449
5450 unsigned get_variation_index () const
5451 {
5452 switch (u.b.format) {
5453#ifndef HB_NO_VAR
5454 case 0x8000:
5455 hb_barrier ();
5456 return u.variation.varIdx;
5457#endif
5458 default:
5459 return HB_OT_LAYOUT_NO_VARIATIONS_INDEX0xFFFFFFFFu;
5460 }
5461 }
5462
5463 bool is_variation_device () const
5464 {
5465 switch (u.b.format) {
5466#ifndef HB_NO_VAR
5467 case 0x8000:
5468 return true;
5469#endif
5470 default:
5471 return false;
5472 }
5473 }
5474
5475 protected:
5476 union {
5477 DeviceHeader b;
5478 HintingDevice hinting;
5479#ifndef HB_NO_VAR
5480 VariationDevice variation;
5481#endif
5482 } u;
5483 public:
5484 DEFINE_SIZE_UNION (6, b)void _compiles_assertion_on_line_5484 () const { (void) this->
u.b.static_size; } void _instance_assertion_on_line_5484 () const
{ static_assert ((sizeof(this->u.b) == (6)), ""); } static
constexpr unsigned null_size = (6); static constexpr unsigned
min_size = (6)
;
5485};
5486
5487
5488} /* namespace OT */
5489
5490
5491#endif /* HB_OT_LAYOUT_COMMON_HH */