xref: /aosp_15_r20/external/harfbuzz_ng/src/hb-ot-layout-common.hh (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
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 &region_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 &region = 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 &regions,
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 &regions,
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 &region_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 &region_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 &regions,
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 ([&region_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