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