xref: /aosp_15_r20/external/harfbuzz_ng/src/hb-ot-layout-base-table.hh (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
1*2d1272b8SAndroid Build Coastguard Worker /*
2*2d1272b8SAndroid Build Coastguard Worker  * Copyright © 2016  Elie Roux <[email protected]>
3*2d1272b8SAndroid Build Coastguard Worker  * Copyright © 2018  Google, Inc.
4*2d1272b8SAndroid Build Coastguard Worker  * Copyright © 2018-2019  Ebrahim Byagowi
5*2d1272b8SAndroid Build Coastguard Worker  *
6*2d1272b8SAndroid Build Coastguard Worker  *  This is part of HarfBuzz, a text shaping library.
7*2d1272b8SAndroid Build Coastguard Worker  *
8*2d1272b8SAndroid Build Coastguard Worker  * Permission is hereby granted, without written agreement and without
9*2d1272b8SAndroid Build Coastguard Worker  * license or royalty fees, to use, copy, modify, and distribute this
10*2d1272b8SAndroid Build Coastguard Worker  * software and its documentation for any purpose, provided that the
11*2d1272b8SAndroid Build Coastguard Worker  * above copyright notice and the following two paragraphs appear in
12*2d1272b8SAndroid Build Coastguard Worker  * all copies of this software.
13*2d1272b8SAndroid Build Coastguard Worker  *
14*2d1272b8SAndroid Build Coastguard Worker  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
15*2d1272b8SAndroid Build Coastguard Worker  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
16*2d1272b8SAndroid Build Coastguard Worker  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
17*2d1272b8SAndroid Build Coastguard Worker  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
18*2d1272b8SAndroid Build Coastguard Worker  * DAMAGE.
19*2d1272b8SAndroid Build Coastguard Worker  *
20*2d1272b8SAndroid Build Coastguard Worker  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
21*2d1272b8SAndroid Build Coastguard Worker  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
22*2d1272b8SAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
23*2d1272b8SAndroid Build Coastguard Worker  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
24*2d1272b8SAndroid Build Coastguard Worker  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
25*2d1272b8SAndroid Build Coastguard Worker  *
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_BASE_TABLE_HH
30*2d1272b8SAndroid Build Coastguard Worker #define HB_OT_LAYOUT_BASE_TABLE_HH
31*2d1272b8SAndroid Build Coastguard Worker 
32*2d1272b8SAndroid Build Coastguard Worker #include "hb-open-type.hh"
33*2d1272b8SAndroid Build Coastguard Worker #include "hb-ot-layout-common.hh"
34*2d1272b8SAndroid Build Coastguard Worker 
35*2d1272b8SAndroid Build Coastguard Worker namespace OT {
36*2d1272b8SAndroid Build Coastguard Worker 
37*2d1272b8SAndroid Build Coastguard Worker /*
38*2d1272b8SAndroid Build Coastguard Worker  * BASE -- Baseline
39*2d1272b8SAndroid Build Coastguard Worker  * https://docs.microsoft.com/en-us/typography/opentype/spec/base
40*2d1272b8SAndroid Build Coastguard Worker  */
41*2d1272b8SAndroid Build Coastguard Worker 
42*2d1272b8SAndroid Build Coastguard Worker struct BaseCoordFormat1
43*2d1272b8SAndroid Build Coastguard Worker {
get_coordOT::BaseCoordFormat144*2d1272b8SAndroid Build Coastguard Worker   hb_position_t get_coord (hb_font_t *font, hb_direction_t direction) const
45*2d1272b8SAndroid Build Coastguard Worker   {
46*2d1272b8SAndroid Build Coastguard Worker     return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_y (coordinate) : font->em_scale_x (coordinate);
47*2d1272b8SAndroid Build Coastguard Worker   }
48*2d1272b8SAndroid Build Coastguard Worker 
subsetOT::BaseCoordFormat149*2d1272b8SAndroid Build Coastguard Worker   bool subset (hb_subset_context_t *c) const
50*2d1272b8SAndroid Build Coastguard Worker   {
51*2d1272b8SAndroid Build Coastguard Worker     TRACE_SUBSET (this);
52*2d1272b8SAndroid Build Coastguard Worker     return_trace ((bool) c->serializer->embed (*this));
53*2d1272b8SAndroid Build Coastguard Worker   }
54*2d1272b8SAndroid Build Coastguard Worker 
sanitizeOT::BaseCoordFormat155*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
56*2d1272b8SAndroid Build Coastguard Worker   {
57*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
58*2d1272b8SAndroid Build Coastguard Worker     return_trace (c->check_struct (this));
59*2d1272b8SAndroid Build Coastguard Worker   }
60*2d1272b8SAndroid Build Coastguard Worker 
61*2d1272b8SAndroid Build Coastguard Worker   protected:
62*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	format;		/* Format identifier--format = 1 */
63*2d1272b8SAndroid Build Coastguard Worker   FWORD		coordinate;	/* X or Y value, in design units */
64*2d1272b8SAndroid Build Coastguard Worker   public:
65*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_STATIC (4);
66*2d1272b8SAndroid Build Coastguard Worker };
67*2d1272b8SAndroid Build Coastguard Worker 
68*2d1272b8SAndroid Build Coastguard Worker struct BaseCoordFormat2
69*2d1272b8SAndroid Build Coastguard Worker {
get_coordOT::BaseCoordFormat270*2d1272b8SAndroid Build Coastguard Worker   hb_position_t get_coord (hb_font_t *font, hb_direction_t direction) const
71*2d1272b8SAndroid Build Coastguard Worker   {
72*2d1272b8SAndroid Build Coastguard Worker     /* TODO */
73*2d1272b8SAndroid Build Coastguard Worker     return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_y (coordinate) : font->em_scale_x (coordinate);
74*2d1272b8SAndroid Build Coastguard Worker   }
75*2d1272b8SAndroid Build Coastguard Worker 
subsetOT::BaseCoordFormat276*2d1272b8SAndroid Build Coastguard Worker   bool subset (hb_subset_context_t *c) const
77*2d1272b8SAndroid Build Coastguard Worker   {
78*2d1272b8SAndroid Build Coastguard Worker     TRACE_SUBSET (this);
79*2d1272b8SAndroid Build Coastguard Worker     auto *out = c->serializer->embed (*this);
80*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!out)) return_trace (false);
81*2d1272b8SAndroid Build Coastguard Worker 
82*2d1272b8SAndroid Build Coastguard Worker     return_trace (c->serializer->check_assign (out->referenceGlyph,
83*2d1272b8SAndroid Build Coastguard Worker                                                c->plan->glyph_map->get (referenceGlyph),
84*2d1272b8SAndroid Build Coastguard Worker                                                HB_SERIALIZE_ERROR_INT_OVERFLOW));
85*2d1272b8SAndroid Build Coastguard Worker   }
86*2d1272b8SAndroid Build Coastguard Worker 
sanitizeOT::BaseCoordFormat287*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
88*2d1272b8SAndroid Build Coastguard Worker   {
89*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
90*2d1272b8SAndroid Build Coastguard Worker     return_trace (c->check_struct (this));
91*2d1272b8SAndroid Build Coastguard Worker   }
92*2d1272b8SAndroid Build Coastguard Worker 
93*2d1272b8SAndroid Build Coastguard Worker   protected:
94*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	format;		/* Format identifier--format = 2 */
95*2d1272b8SAndroid Build Coastguard Worker   FWORD		coordinate;	/* X or Y value, in design units */
96*2d1272b8SAndroid Build Coastguard Worker   HBGlyphID16	referenceGlyph;	/* Glyph ID of control glyph */
97*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	coordPoint;	/* Index of contour point on the
98*2d1272b8SAndroid Build Coastguard Worker 				 * reference glyph */
99*2d1272b8SAndroid Build Coastguard Worker   public:
100*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_STATIC (8);
101*2d1272b8SAndroid Build Coastguard Worker };
102*2d1272b8SAndroid Build Coastguard Worker 
103*2d1272b8SAndroid Build Coastguard Worker struct BaseCoordFormat3
104*2d1272b8SAndroid Build Coastguard Worker {
get_coordOT::BaseCoordFormat3105*2d1272b8SAndroid Build Coastguard Worker   hb_position_t get_coord (hb_font_t *font,
106*2d1272b8SAndroid Build Coastguard Worker 			   const ItemVariationStore &var_store,
107*2d1272b8SAndroid Build Coastguard Worker 			   hb_direction_t direction) const
108*2d1272b8SAndroid Build Coastguard Worker   {
109*2d1272b8SAndroid Build Coastguard Worker     const Device &device = this+deviceTable;
110*2d1272b8SAndroid Build Coastguard Worker 
111*2d1272b8SAndroid Build Coastguard Worker     return HB_DIRECTION_IS_HORIZONTAL (direction)
112*2d1272b8SAndroid Build Coastguard Worker 	 ? font->em_scale_y (coordinate) + device.get_y_delta (font, var_store)
113*2d1272b8SAndroid Build Coastguard Worker 	 : font->em_scale_x (coordinate) + device.get_x_delta (font, var_store);
114*2d1272b8SAndroid Build Coastguard Worker   }
115*2d1272b8SAndroid Build Coastguard Worker 
collect_variation_indicesOT::BaseCoordFormat3116*2d1272b8SAndroid Build Coastguard Worker   void collect_variation_indices (hb_set_t& varidx_set /* OUT */) const
117*2d1272b8SAndroid Build Coastguard Worker   {
118*2d1272b8SAndroid Build Coastguard Worker     unsigned varidx = (this+deviceTable).get_variation_index ();
119*2d1272b8SAndroid Build Coastguard Worker     varidx_set.add (varidx);
120*2d1272b8SAndroid Build Coastguard Worker   }
121*2d1272b8SAndroid Build Coastguard Worker 
subsetOT::BaseCoordFormat3122*2d1272b8SAndroid Build Coastguard Worker   bool subset (hb_subset_context_t *c) const
123*2d1272b8SAndroid Build Coastguard Worker   {
124*2d1272b8SAndroid Build Coastguard Worker     TRACE_SUBSET (this);
125*2d1272b8SAndroid Build Coastguard Worker     auto *out = c->serializer->embed (*this);
126*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!out)) return_trace (false);
127*2d1272b8SAndroid Build Coastguard Worker 
128*2d1272b8SAndroid Build Coastguard Worker     if (!c->plan->pinned_at_default)
129*2d1272b8SAndroid Build Coastguard Worker     {
130*2d1272b8SAndroid Build Coastguard Worker       unsigned var_idx = (this+deviceTable).get_variation_index ();
131*2d1272b8SAndroid Build Coastguard Worker       if (var_idx != VarIdx::NO_VARIATION)
132*2d1272b8SAndroid Build Coastguard Worker       {
133*2d1272b8SAndroid Build Coastguard Worker         hb_pair_t<unsigned, int> *v;
134*2d1272b8SAndroid Build Coastguard Worker         if (!c->plan->base_variation_idx_map.has (var_idx, &v))
135*2d1272b8SAndroid Build Coastguard Worker           return_trace (false);
136*2d1272b8SAndroid Build Coastguard Worker 
137*2d1272b8SAndroid Build Coastguard Worker         if (unlikely (!c->serializer->check_assign (out->coordinate, coordinate + hb_second (*v),
138*2d1272b8SAndroid Build Coastguard Worker                                                     HB_SERIALIZE_ERROR_INT_OVERFLOW)))
139*2d1272b8SAndroid Build Coastguard Worker           return_trace (false);
140*2d1272b8SAndroid Build Coastguard Worker       }
141*2d1272b8SAndroid Build Coastguard Worker     }
142*2d1272b8SAndroid Build Coastguard Worker     return_trace (out->deviceTable.serialize_copy (c->serializer, deviceTable,
143*2d1272b8SAndroid Build Coastguard Worker                                                    this, 0,
144*2d1272b8SAndroid Build Coastguard Worker                                                    hb_serialize_context_t::Head,
145*2d1272b8SAndroid Build Coastguard Worker                                                    &c->plan->base_variation_idx_map));
146*2d1272b8SAndroid Build Coastguard Worker   }
147*2d1272b8SAndroid Build Coastguard Worker 
sanitizeOT::BaseCoordFormat3148*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
149*2d1272b8SAndroid Build Coastguard Worker   {
150*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
151*2d1272b8SAndroid Build Coastguard Worker     return_trace (likely (c->check_struct (this) &&
152*2d1272b8SAndroid Build Coastguard Worker 			  deviceTable.sanitize (c, this)));
153*2d1272b8SAndroid Build Coastguard Worker   }
154*2d1272b8SAndroid Build Coastguard Worker 
155*2d1272b8SAndroid Build Coastguard Worker   protected:
156*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	format;		/* Format identifier--format = 3 */
157*2d1272b8SAndroid Build Coastguard Worker   FWORD		coordinate;	/* X or Y value, in design units */
158*2d1272b8SAndroid Build Coastguard Worker   Offset16To<Device>
159*2d1272b8SAndroid Build Coastguard Worker 		deviceTable;	/* Offset to Device table for X or
160*2d1272b8SAndroid Build Coastguard Worker 				 * Y value, from beginning of
161*2d1272b8SAndroid Build Coastguard Worker 				 * BaseCoord table (may be NULL). */
162*2d1272b8SAndroid Build Coastguard Worker   public:
163*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_STATIC (6);
164*2d1272b8SAndroid Build Coastguard Worker };
165*2d1272b8SAndroid Build Coastguard Worker 
166*2d1272b8SAndroid Build Coastguard Worker struct BaseCoord
167*2d1272b8SAndroid Build Coastguard Worker {
has_dataOT::BaseCoord168*2d1272b8SAndroid Build Coastguard Worker   bool has_data () const { return u.format; }
169*2d1272b8SAndroid Build Coastguard Worker 
get_coordOT::BaseCoord170*2d1272b8SAndroid Build Coastguard Worker   hb_position_t get_coord (hb_font_t            *font,
171*2d1272b8SAndroid Build Coastguard Worker 			   const ItemVariationStore &var_store,
172*2d1272b8SAndroid Build Coastguard Worker 			   hb_direction_t        direction) const
173*2d1272b8SAndroid Build Coastguard Worker   {
174*2d1272b8SAndroid Build Coastguard Worker     switch (u.format) {
175*2d1272b8SAndroid Build Coastguard Worker     case 1: hb_barrier (); return u.format1.get_coord (font, direction);
176*2d1272b8SAndroid Build Coastguard Worker     case 2: hb_barrier (); return u.format2.get_coord (font, direction);
177*2d1272b8SAndroid Build Coastguard Worker     case 3: hb_barrier (); return u.format3.get_coord (font, var_store, direction);
178*2d1272b8SAndroid Build Coastguard Worker     default:return 0;
179*2d1272b8SAndroid Build Coastguard Worker     }
180*2d1272b8SAndroid Build Coastguard Worker   }
181*2d1272b8SAndroid Build Coastguard Worker 
collect_variation_indicesOT::BaseCoord182*2d1272b8SAndroid Build Coastguard Worker   void collect_variation_indices (hb_set_t& varidx_set /* OUT */) const
183*2d1272b8SAndroid Build Coastguard Worker   {
184*2d1272b8SAndroid Build Coastguard Worker     switch (u.format) {
185*2d1272b8SAndroid Build Coastguard Worker     case 3: hb_barrier (); u.format3.collect_variation_indices (varidx_set);
186*2d1272b8SAndroid Build Coastguard Worker     default:return;
187*2d1272b8SAndroid Build Coastguard Worker     }
188*2d1272b8SAndroid Build Coastguard Worker   }
189*2d1272b8SAndroid Build Coastguard Worker 
190*2d1272b8SAndroid Build Coastguard Worker   template <typename context_t, typename ...Ts>
dispatchOT::BaseCoord191*2d1272b8SAndroid Build Coastguard Worker   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
192*2d1272b8SAndroid Build Coastguard Worker   {
193*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
194*2d1272b8SAndroid Build Coastguard Worker     TRACE_DISPATCH (this, u.format);
195*2d1272b8SAndroid Build Coastguard Worker     switch (u.format) {
196*2d1272b8SAndroid Build Coastguard Worker     case 1: hb_barrier (); return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
197*2d1272b8SAndroid Build Coastguard Worker     case 2: hb_barrier (); return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
198*2d1272b8SAndroid Build Coastguard Worker     case 3: hb_barrier (); return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
199*2d1272b8SAndroid Build Coastguard Worker     default:return_trace (c->default_return_value ());
200*2d1272b8SAndroid Build Coastguard Worker     }
201*2d1272b8SAndroid Build Coastguard Worker   }
202*2d1272b8SAndroid Build Coastguard Worker 
sanitizeOT::BaseCoord203*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
204*2d1272b8SAndroid Build Coastguard Worker   {
205*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
206*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!u.format.sanitize (c))) return_trace (false);
207*2d1272b8SAndroid Build Coastguard Worker     hb_barrier ();
208*2d1272b8SAndroid Build Coastguard Worker     switch (u.format) {
209*2d1272b8SAndroid Build Coastguard Worker     case 1: hb_barrier (); return_trace (u.format1.sanitize (c));
210*2d1272b8SAndroid Build Coastguard Worker     case 2: hb_barrier (); return_trace (u.format2.sanitize (c));
211*2d1272b8SAndroid Build Coastguard Worker     case 3: hb_barrier (); return_trace (u.format3.sanitize (c));
212*2d1272b8SAndroid Build Coastguard Worker     default:return_trace (false);
213*2d1272b8SAndroid Build Coastguard Worker     }
214*2d1272b8SAndroid Build Coastguard Worker   }
215*2d1272b8SAndroid Build Coastguard Worker 
216*2d1272b8SAndroid Build Coastguard Worker   protected:
217*2d1272b8SAndroid Build Coastguard Worker   union {
218*2d1272b8SAndroid Build Coastguard Worker   HBUINT16		format;
219*2d1272b8SAndroid Build Coastguard Worker   BaseCoordFormat1	format1;
220*2d1272b8SAndroid Build Coastguard Worker   BaseCoordFormat2	format2;
221*2d1272b8SAndroid Build Coastguard Worker   BaseCoordFormat3	format3;
222*2d1272b8SAndroid Build Coastguard Worker   } u;
223*2d1272b8SAndroid Build Coastguard Worker   public:
224*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_UNION (2, format);
225*2d1272b8SAndroid Build Coastguard Worker };
226*2d1272b8SAndroid Build Coastguard Worker 
227*2d1272b8SAndroid Build Coastguard Worker struct FeatMinMaxRecord
228*2d1272b8SAndroid Build Coastguard Worker {
cmpOT::FeatMinMaxRecord229*2d1272b8SAndroid Build Coastguard Worker   int cmp (hb_tag_t key) const { return tag.cmp (key); }
230*2d1272b8SAndroid Build Coastguard Worker 
has_dataOT::FeatMinMaxRecord231*2d1272b8SAndroid Build Coastguard Worker   bool has_data () const { return tag; }
232*2d1272b8SAndroid Build Coastguard Worker 
get_feature_tagOT::FeatMinMaxRecord233*2d1272b8SAndroid Build Coastguard Worker   hb_tag_t get_feature_tag () const { return tag; }
234*2d1272b8SAndroid Build Coastguard Worker 
get_min_maxOT::FeatMinMaxRecord235*2d1272b8SAndroid Build Coastguard Worker   void get_min_max (const BaseCoord **min, const BaseCoord **max) const
236*2d1272b8SAndroid Build Coastguard Worker   {
237*2d1272b8SAndroid Build Coastguard Worker     if (likely (min)) *min = &(this+minCoord);
238*2d1272b8SAndroid Build Coastguard Worker     if (likely (max)) *max = &(this+maxCoord);
239*2d1272b8SAndroid Build Coastguard Worker   }
240*2d1272b8SAndroid Build Coastguard Worker 
collect_variation_indicesOT::FeatMinMaxRecord241*2d1272b8SAndroid Build Coastguard Worker   void collect_variation_indices (const hb_subset_plan_t* plan,
242*2d1272b8SAndroid Build Coastguard Worker                                   const void *base,
243*2d1272b8SAndroid Build Coastguard Worker                                   hb_set_t& varidx_set /* OUT */) const
244*2d1272b8SAndroid Build Coastguard Worker   {
245*2d1272b8SAndroid Build Coastguard Worker     if (!plan->layout_features.has (tag))
246*2d1272b8SAndroid Build Coastguard Worker       return;
247*2d1272b8SAndroid Build Coastguard Worker 
248*2d1272b8SAndroid Build Coastguard Worker     (base+minCoord).collect_variation_indices (varidx_set);
249*2d1272b8SAndroid Build Coastguard Worker     (base+maxCoord).collect_variation_indices (varidx_set);
250*2d1272b8SAndroid Build Coastguard Worker   }
251*2d1272b8SAndroid Build Coastguard Worker 
subsetOT::FeatMinMaxRecord252*2d1272b8SAndroid Build Coastguard Worker   bool subset (hb_subset_context_t *c,
253*2d1272b8SAndroid Build Coastguard Worker                const void *base) const
254*2d1272b8SAndroid Build Coastguard Worker   {
255*2d1272b8SAndroid Build Coastguard Worker     TRACE_SUBSET (this);
256*2d1272b8SAndroid Build Coastguard Worker     auto *out = c->serializer->embed (*this);
257*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!out)) return_trace (false);
258*2d1272b8SAndroid Build Coastguard Worker     if (!(out->minCoord.serialize_subset (c, minCoord, base)))
259*2d1272b8SAndroid Build Coastguard Worker       return_trace (false);
260*2d1272b8SAndroid Build Coastguard Worker 
261*2d1272b8SAndroid Build Coastguard Worker     return_trace (out->maxCoord.serialize_subset (c, maxCoord, base));
262*2d1272b8SAndroid Build Coastguard Worker   }
263*2d1272b8SAndroid Build Coastguard Worker 
sanitizeOT::FeatMinMaxRecord264*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c, const void *base) const
265*2d1272b8SAndroid Build Coastguard Worker   {
266*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
267*2d1272b8SAndroid Build Coastguard Worker     return_trace (likely (c->check_struct (this) &&
268*2d1272b8SAndroid Build Coastguard Worker 			  minCoord.sanitize (c, base) &&
269*2d1272b8SAndroid Build Coastguard Worker 			  maxCoord.sanitize (c, base)));
270*2d1272b8SAndroid Build Coastguard Worker   }
271*2d1272b8SAndroid Build Coastguard Worker 
272*2d1272b8SAndroid Build Coastguard Worker   protected:
273*2d1272b8SAndroid Build Coastguard Worker   Tag		tag;		/* 4-byte feature identification tag--must
274*2d1272b8SAndroid Build Coastguard Worker 				 * match feature tag in FeatureList */
275*2d1272b8SAndroid Build Coastguard Worker   Offset16To<BaseCoord>
276*2d1272b8SAndroid Build Coastguard Worker 		minCoord;	/* Offset to BaseCoord table that defines
277*2d1272b8SAndroid Build Coastguard Worker 				 * the minimum extent value, from beginning
278*2d1272b8SAndroid Build Coastguard Worker 				 * of MinMax table (may be NULL) */
279*2d1272b8SAndroid Build Coastguard Worker   Offset16To<BaseCoord>
280*2d1272b8SAndroid Build Coastguard Worker 		maxCoord;	/* Offset to BaseCoord table that defines
281*2d1272b8SAndroid Build Coastguard Worker 				 * the maximum extent value, from beginning
282*2d1272b8SAndroid Build Coastguard Worker 				 * of MinMax table (may be NULL) */
283*2d1272b8SAndroid Build Coastguard Worker   public:
284*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_STATIC (8);
285*2d1272b8SAndroid Build Coastguard Worker };
286*2d1272b8SAndroid Build Coastguard Worker 
287*2d1272b8SAndroid Build Coastguard Worker struct MinMax
288*2d1272b8SAndroid Build Coastguard Worker {
get_min_maxOT::MinMax289*2d1272b8SAndroid Build Coastguard Worker   void get_min_max (hb_tag_t          feature_tag,
290*2d1272b8SAndroid Build Coastguard Worker 		    const BaseCoord **min,
291*2d1272b8SAndroid Build Coastguard Worker 		    const BaseCoord **max) const
292*2d1272b8SAndroid Build Coastguard Worker   {
293*2d1272b8SAndroid Build Coastguard Worker     const FeatMinMaxRecord &minMaxCoord = featMinMaxRecords.bsearch (feature_tag);
294*2d1272b8SAndroid Build Coastguard Worker     if (minMaxCoord.has_data ())
295*2d1272b8SAndroid Build Coastguard Worker       minMaxCoord.get_min_max (min, max);
296*2d1272b8SAndroid Build Coastguard Worker     else
297*2d1272b8SAndroid Build Coastguard Worker     {
298*2d1272b8SAndroid Build Coastguard Worker       if (likely (min)) *min = &(this+minCoord);
299*2d1272b8SAndroid Build Coastguard Worker       if (likely (max)) *max = &(this+maxCoord);
300*2d1272b8SAndroid Build Coastguard Worker     }
301*2d1272b8SAndroid Build Coastguard Worker   }
302*2d1272b8SAndroid Build Coastguard Worker 
collect_variation_indicesOT::MinMax303*2d1272b8SAndroid Build Coastguard Worker   void collect_variation_indices (const hb_subset_plan_t* plan,
304*2d1272b8SAndroid Build Coastguard Worker                                   hb_set_t& varidx_set /* OUT */) const
305*2d1272b8SAndroid Build Coastguard Worker   {
306*2d1272b8SAndroid Build Coastguard Worker     (this+minCoord).collect_variation_indices (varidx_set);
307*2d1272b8SAndroid Build Coastguard Worker     (this+maxCoord).collect_variation_indices (varidx_set);
308*2d1272b8SAndroid Build Coastguard Worker     for (const FeatMinMaxRecord& record : featMinMaxRecords)
309*2d1272b8SAndroid Build Coastguard Worker       record.collect_variation_indices (plan, this, varidx_set);
310*2d1272b8SAndroid Build Coastguard Worker   }
311*2d1272b8SAndroid Build Coastguard Worker 
subsetOT::MinMax312*2d1272b8SAndroid Build Coastguard Worker   bool subset (hb_subset_context_t *c) const
313*2d1272b8SAndroid Build Coastguard Worker   {
314*2d1272b8SAndroid Build Coastguard Worker     TRACE_SUBSET (this);
315*2d1272b8SAndroid Build Coastguard Worker     auto *out = c->serializer->start_embed (*this);
316*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
317*2d1272b8SAndroid Build Coastguard Worker 
318*2d1272b8SAndroid Build Coastguard Worker     if (!(out->minCoord.serialize_subset (c, minCoord, this)) ||
319*2d1272b8SAndroid Build Coastguard Worker         !(out->maxCoord.serialize_subset (c, maxCoord, this)))
320*2d1272b8SAndroid Build Coastguard Worker       return_trace (false);
321*2d1272b8SAndroid Build Coastguard Worker 
322*2d1272b8SAndroid Build Coastguard Worker     unsigned len = 0;
323*2d1272b8SAndroid Build Coastguard Worker     for (const FeatMinMaxRecord& _ : featMinMaxRecords)
324*2d1272b8SAndroid Build Coastguard Worker     {
325*2d1272b8SAndroid Build Coastguard Worker       hb_tag_t feature_tag = _.get_feature_tag ();
326*2d1272b8SAndroid Build Coastguard Worker       if (!c->plan->layout_features.has (feature_tag))
327*2d1272b8SAndroid Build Coastguard Worker         continue;
328*2d1272b8SAndroid Build Coastguard Worker 
329*2d1272b8SAndroid Build Coastguard Worker       if (!_.subset (c, this)) return false;
330*2d1272b8SAndroid Build Coastguard Worker       len++;
331*2d1272b8SAndroid Build Coastguard Worker     }
332*2d1272b8SAndroid Build Coastguard Worker     return_trace (c->serializer->check_assign (out->featMinMaxRecords.len, len,
333*2d1272b8SAndroid Build Coastguard Worker                                                HB_SERIALIZE_ERROR_INT_OVERFLOW));
334*2d1272b8SAndroid Build Coastguard Worker   }
335*2d1272b8SAndroid Build Coastguard Worker 
sanitizeOT::MinMax336*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
337*2d1272b8SAndroid Build Coastguard Worker   {
338*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
339*2d1272b8SAndroid Build Coastguard Worker     return_trace (likely (c->check_struct (this) &&
340*2d1272b8SAndroid Build Coastguard Worker 			  minCoord.sanitize (c, this) &&
341*2d1272b8SAndroid Build Coastguard Worker 			  maxCoord.sanitize (c, this) &&
342*2d1272b8SAndroid Build Coastguard Worker 			  featMinMaxRecords.sanitize (c, this)));
343*2d1272b8SAndroid Build Coastguard Worker   }
344*2d1272b8SAndroid Build Coastguard Worker 
345*2d1272b8SAndroid Build Coastguard Worker   protected:
346*2d1272b8SAndroid Build Coastguard Worker   Offset16To<BaseCoord>
347*2d1272b8SAndroid Build Coastguard Worker 		minCoord;	/* Offset to BaseCoord table that defines
348*2d1272b8SAndroid Build Coastguard Worker 				 * minimum extent value, from the beginning
349*2d1272b8SAndroid Build Coastguard Worker 				 * of MinMax table (may be NULL) */
350*2d1272b8SAndroid Build Coastguard Worker   Offset16To<BaseCoord>
351*2d1272b8SAndroid Build Coastguard Worker 		maxCoord;	/* Offset to BaseCoord table that defines
352*2d1272b8SAndroid Build Coastguard Worker 				 * maximum extent value, from the beginning
353*2d1272b8SAndroid Build Coastguard Worker 				 * of MinMax table (may be NULL) */
354*2d1272b8SAndroid Build Coastguard Worker   SortedArray16Of<FeatMinMaxRecord>
355*2d1272b8SAndroid Build Coastguard Worker 		featMinMaxRecords;
356*2d1272b8SAndroid Build Coastguard Worker 				/* Array of FeatMinMaxRecords, in alphabetical
357*2d1272b8SAndroid Build Coastguard Worker 				 * order by featureTableTag */
358*2d1272b8SAndroid Build Coastguard Worker   public:
359*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_ARRAY (6, featMinMaxRecords);
360*2d1272b8SAndroid Build Coastguard Worker };
361*2d1272b8SAndroid Build Coastguard Worker 
362*2d1272b8SAndroid Build Coastguard Worker struct BaseValues
363*2d1272b8SAndroid Build Coastguard Worker {
get_base_coordOT::BaseValues364*2d1272b8SAndroid Build Coastguard Worker   const BaseCoord &get_base_coord (int baseline_tag_index) const
365*2d1272b8SAndroid Build Coastguard Worker   {
366*2d1272b8SAndroid Build Coastguard Worker     if (baseline_tag_index == -1) baseline_tag_index = defaultIndex;
367*2d1272b8SAndroid Build Coastguard Worker     return this+baseCoords[baseline_tag_index];
368*2d1272b8SAndroid Build Coastguard Worker   }
369*2d1272b8SAndroid Build Coastguard Worker 
collect_variation_indicesOT::BaseValues370*2d1272b8SAndroid Build Coastguard Worker   void collect_variation_indices (hb_set_t& varidx_set /* OUT */) const
371*2d1272b8SAndroid Build Coastguard Worker   {
372*2d1272b8SAndroid Build Coastguard Worker     for (const auto& _ : baseCoords)
373*2d1272b8SAndroid Build Coastguard Worker       (this+_).collect_variation_indices (varidx_set);
374*2d1272b8SAndroid Build Coastguard Worker   }
375*2d1272b8SAndroid Build Coastguard Worker 
subsetOT::BaseValues376*2d1272b8SAndroid Build Coastguard Worker   bool subset (hb_subset_context_t *c) const
377*2d1272b8SAndroid Build Coastguard Worker   {
378*2d1272b8SAndroid Build Coastguard Worker     TRACE_SUBSET (this);
379*2d1272b8SAndroid Build Coastguard Worker     auto *out = c->serializer->start_embed (*this);
380*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
381*2d1272b8SAndroid Build Coastguard Worker     out->defaultIndex = defaultIndex;
382*2d1272b8SAndroid Build Coastguard Worker 
383*2d1272b8SAndroid Build Coastguard Worker     for (const auto& _ : baseCoords)
384*2d1272b8SAndroid Build Coastguard Worker       if (!subset_offset_array (c, out->baseCoords, this) (_))
385*2d1272b8SAndroid Build Coastguard Worker         return_trace (false);
386*2d1272b8SAndroid Build Coastguard Worker 
387*2d1272b8SAndroid Build Coastguard Worker     return_trace (bool (out->baseCoords));
388*2d1272b8SAndroid Build Coastguard Worker   }
389*2d1272b8SAndroid Build Coastguard Worker 
sanitizeOT::BaseValues390*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
391*2d1272b8SAndroid Build Coastguard Worker   {
392*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
393*2d1272b8SAndroid Build Coastguard Worker     return_trace (likely (c->check_struct (this) &&
394*2d1272b8SAndroid Build Coastguard Worker 			  baseCoords.sanitize (c, this)));
395*2d1272b8SAndroid Build Coastguard Worker   }
396*2d1272b8SAndroid Build Coastguard Worker 
397*2d1272b8SAndroid Build Coastguard Worker   protected:
398*2d1272b8SAndroid Build Coastguard Worker   Index		defaultIndex;	/* Index number of default baseline for this
399*2d1272b8SAndroid Build Coastguard Worker 				 * script — equals index position of baseline tag
400*2d1272b8SAndroid Build Coastguard Worker 				 * in baselineTags array of the BaseTagList */
401*2d1272b8SAndroid Build Coastguard Worker   Array16OfOffset16To<BaseCoord>
402*2d1272b8SAndroid Build Coastguard Worker 		baseCoords;	/* Number of BaseCoord tables defined — should equal
403*2d1272b8SAndroid Build Coastguard Worker 				 * baseTagCount in the BaseTagList
404*2d1272b8SAndroid Build Coastguard Worker 				 *
405*2d1272b8SAndroid Build Coastguard Worker 				 * Array of offsets to BaseCoord tables, from beginning of
406*2d1272b8SAndroid Build Coastguard Worker 				 * BaseValues table — order matches baselineTags array in
407*2d1272b8SAndroid Build Coastguard Worker 				 * the BaseTagList */
408*2d1272b8SAndroid Build Coastguard Worker   public:
409*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_ARRAY (4, baseCoords);
410*2d1272b8SAndroid Build Coastguard Worker };
411*2d1272b8SAndroid Build Coastguard Worker 
412*2d1272b8SAndroid Build Coastguard Worker struct BaseLangSysRecord
413*2d1272b8SAndroid Build Coastguard Worker {
cmpOT::BaseLangSysRecord414*2d1272b8SAndroid Build Coastguard Worker   int cmp (hb_tag_t key) const { return baseLangSysTag.cmp (key); }
415*2d1272b8SAndroid Build Coastguard Worker 
has_dataOT::BaseLangSysRecord416*2d1272b8SAndroid Build Coastguard Worker   bool has_data () const { return baseLangSysTag; }
417*2d1272b8SAndroid Build Coastguard Worker 
get_min_maxOT::BaseLangSysRecord418*2d1272b8SAndroid Build Coastguard Worker   const MinMax &get_min_max (const void* base) const { return base+minMax; }
419*2d1272b8SAndroid Build Coastguard Worker 
collect_variation_indicesOT::BaseLangSysRecord420*2d1272b8SAndroid Build Coastguard Worker   void collect_variation_indices (const void* base,
421*2d1272b8SAndroid Build Coastguard Worker                                   const hb_subset_plan_t* plan,
422*2d1272b8SAndroid Build Coastguard Worker                                   hb_set_t& varidx_set /* OUT */) const
423*2d1272b8SAndroid Build Coastguard Worker   { (base+minMax).collect_variation_indices (plan, varidx_set); }
424*2d1272b8SAndroid Build Coastguard Worker 
subsetOT::BaseLangSysRecord425*2d1272b8SAndroid Build Coastguard Worker   bool subset (hb_subset_context_t *c,
426*2d1272b8SAndroid Build Coastguard Worker                const void *base) const
427*2d1272b8SAndroid Build Coastguard Worker   {
428*2d1272b8SAndroid Build Coastguard Worker     TRACE_SUBSET (this);
429*2d1272b8SAndroid Build Coastguard Worker     auto *out = c->serializer->embed (*this);
430*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!out)) return_trace (false);
431*2d1272b8SAndroid Build Coastguard Worker 
432*2d1272b8SAndroid Build Coastguard Worker     return_trace (out->minMax.serialize_subset (c, minMax, base));
433*2d1272b8SAndroid Build Coastguard Worker   }
434*2d1272b8SAndroid Build Coastguard Worker 
sanitizeOT::BaseLangSysRecord435*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c, const void *base) const
436*2d1272b8SAndroid Build Coastguard Worker   {
437*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
438*2d1272b8SAndroid Build Coastguard Worker     return_trace (likely (c->check_struct (this) &&
439*2d1272b8SAndroid Build Coastguard Worker 			  minMax.sanitize (c, base)));
440*2d1272b8SAndroid Build Coastguard Worker   }
441*2d1272b8SAndroid Build Coastguard Worker 
442*2d1272b8SAndroid Build Coastguard Worker   protected:
443*2d1272b8SAndroid Build Coastguard Worker   Tag		baseLangSysTag;	/* 4-byte language system identification tag */
444*2d1272b8SAndroid Build Coastguard Worker   Offset16To<MinMax>
445*2d1272b8SAndroid Build Coastguard Worker 		minMax;		/* Offset to MinMax table, from beginning
446*2d1272b8SAndroid Build Coastguard Worker 				 * of BaseScript table */
447*2d1272b8SAndroid Build Coastguard Worker   public:
448*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_STATIC (6);
449*2d1272b8SAndroid Build Coastguard Worker };
450*2d1272b8SAndroid Build Coastguard Worker 
451*2d1272b8SAndroid Build Coastguard Worker struct BaseScript
452*2d1272b8SAndroid Build Coastguard Worker {
get_min_maxOT::BaseScript453*2d1272b8SAndroid Build Coastguard Worker   const MinMax &get_min_max (hb_tag_t language_tag) const
454*2d1272b8SAndroid Build Coastguard Worker   {
455*2d1272b8SAndroid Build Coastguard Worker     const BaseLangSysRecord& record = baseLangSysRecords.bsearch (language_tag);
456*2d1272b8SAndroid Build Coastguard Worker     return record.has_data () ? record.get_min_max (this) : this+defaultMinMax;
457*2d1272b8SAndroid Build Coastguard Worker   }
458*2d1272b8SAndroid Build Coastguard Worker 
get_base_coordOT::BaseScript459*2d1272b8SAndroid Build Coastguard Worker   const BaseCoord &get_base_coord (int baseline_tag_index) const
460*2d1272b8SAndroid Build Coastguard Worker   { return (this+baseValues).get_base_coord (baseline_tag_index); }
461*2d1272b8SAndroid Build Coastguard Worker 
has_valuesOT::BaseScript462*2d1272b8SAndroid Build Coastguard Worker   bool has_values () const { return baseValues; }
has_min_maxOT::BaseScript463*2d1272b8SAndroid Build Coastguard Worker   bool has_min_max () const { return defaultMinMax; /* TODO What if only per-language is present? */ }
464*2d1272b8SAndroid Build Coastguard Worker 
collect_variation_indicesOT::BaseScript465*2d1272b8SAndroid Build Coastguard Worker   void collect_variation_indices (const hb_subset_plan_t* plan,
466*2d1272b8SAndroid Build Coastguard Worker                                   hb_set_t& varidx_set /* OUT */) const
467*2d1272b8SAndroid Build Coastguard Worker   {
468*2d1272b8SAndroid Build Coastguard Worker     (this+baseValues).collect_variation_indices (varidx_set);
469*2d1272b8SAndroid Build Coastguard Worker     (this+defaultMinMax).collect_variation_indices (plan, varidx_set);
470*2d1272b8SAndroid Build Coastguard Worker 
471*2d1272b8SAndroid Build Coastguard Worker     for (const BaseLangSysRecord& _ : baseLangSysRecords)
472*2d1272b8SAndroid Build Coastguard Worker       _.collect_variation_indices (this, plan, varidx_set);
473*2d1272b8SAndroid Build Coastguard Worker   }
474*2d1272b8SAndroid Build Coastguard Worker 
subsetOT::BaseScript475*2d1272b8SAndroid Build Coastguard Worker   bool subset (hb_subset_context_t *c) const
476*2d1272b8SAndroid Build Coastguard Worker   {
477*2d1272b8SAndroid Build Coastguard Worker     TRACE_SUBSET (this);
478*2d1272b8SAndroid Build Coastguard Worker     auto *out = c->serializer->start_embed (*this);
479*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
480*2d1272b8SAndroid Build Coastguard Worker 
481*2d1272b8SAndroid Build Coastguard Worker     if (baseValues && !out->baseValues.serialize_subset (c, baseValues, this))
482*2d1272b8SAndroid Build Coastguard Worker       return_trace (false);
483*2d1272b8SAndroid Build Coastguard Worker 
484*2d1272b8SAndroid Build Coastguard Worker     if (defaultMinMax && !out->defaultMinMax.serialize_subset (c, defaultMinMax, this))
485*2d1272b8SAndroid Build Coastguard Worker       return_trace (false);
486*2d1272b8SAndroid Build Coastguard Worker 
487*2d1272b8SAndroid Build Coastguard Worker     for (const auto& _ : baseLangSysRecords)
488*2d1272b8SAndroid Build Coastguard Worker       if (!_.subset (c, this)) return_trace (false);
489*2d1272b8SAndroid Build Coastguard Worker 
490*2d1272b8SAndroid Build Coastguard Worker     return_trace (c->serializer->check_assign (out->baseLangSysRecords.len, baseLangSysRecords.len,
491*2d1272b8SAndroid Build Coastguard Worker                                                HB_SERIALIZE_ERROR_INT_OVERFLOW));
492*2d1272b8SAndroid Build Coastguard Worker   }
493*2d1272b8SAndroid Build Coastguard Worker 
sanitizeOT::BaseScript494*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
495*2d1272b8SAndroid Build Coastguard Worker   {
496*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
497*2d1272b8SAndroid Build Coastguard Worker     return_trace (likely (c->check_struct (this) &&
498*2d1272b8SAndroid Build Coastguard Worker 			  baseValues.sanitize (c, this) &&
499*2d1272b8SAndroid Build Coastguard Worker 			  defaultMinMax.sanitize (c, this) &&
500*2d1272b8SAndroid Build Coastguard Worker 			  baseLangSysRecords.sanitize (c, this)));
501*2d1272b8SAndroid Build Coastguard Worker   }
502*2d1272b8SAndroid Build Coastguard Worker 
503*2d1272b8SAndroid Build Coastguard Worker   protected:
504*2d1272b8SAndroid Build Coastguard Worker   Offset16To<BaseValues>
505*2d1272b8SAndroid Build Coastguard Worker 		baseValues;	/* Offset to BaseValues table, from beginning
506*2d1272b8SAndroid Build Coastguard Worker 				 * of BaseScript table (may be NULL) */
507*2d1272b8SAndroid Build Coastguard Worker   Offset16To<MinMax>
508*2d1272b8SAndroid Build Coastguard Worker 		defaultMinMax;	/* Offset to MinMax table, from beginning of
509*2d1272b8SAndroid Build Coastguard Worker 				 * BaseScript table (may be NULL) */
510*2d1272b8SAndroid Build Coastguard Worker   SortedArray16Of<BaseLangSysRecord>
511*2d1272b8SAndroid Build Coastguard Worker 		baseLangSysRecords;
512*2d1272b8SAndroid Build Coastguard Worker 				/* Number of BaseLangSysRecords
513*2d1272b8SAndroid Build Coastguard Worker 				 * defined — may be zero (0) */
514*2d1272b8SAndroid Build Coastguard Worker 
515*2d1272b8SAndroid Build Coastguard Worker   public:
516*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_ARRAY (6, baseLangSysRecords);
517*2d1272b8SAndroid Build Coastguard Worker };
518*2d1272b8SAndroid Build Coastguard Worker 
519*2d1272b8SAndroid Build Coastguard Worker struct BaseScriptList;
520*2d1272b8SAndroid Build Coastguard Worker struct BaseScriptRecord
521*2d1272b8SAndroid Build Coastguard Worker {
cmpOT::BaseScriptRecord522*2d1272b8SAndroid Build Coastguard Worker   int cmp (hb_tag_t key) const { return baseScriptTag.cmp (key); }
523*2d1272b8SAndroid Build Coastguard Worker 
has_dataOT::BaseScriptRecord524*2d1272b8SAndroid Build Coastguard Worker   bool has_data () const { return baseScriptTag; }
525*2d1272b8SAndroid Build Coastguard Worker 
get_script_tagOT::BaseScriptRecord526*2d1272b8SAndroid Build Coastguard Worker   hb_tag_t get_script_tag () const { return baseScriptTag; }
527*2d1272b8SAndroid Build Coastguard Worker 
get_base_scriptOT::BaseScriptRecord528*2d1272b8SAndroid Build Coastguard Worker   const BaseScript &get_base_script (const BaseScriptList *list) const
529*2d1272b8SAndroid Build Coastguard Worker   { return list+baseScript; }
530*2d1272b8SAndroid Build Coastguard Worker 
collect_variation_indicesOT::BaseScriptRecord531*2d1272b8SAndroid Build Coastguard Worker   void collect_variation_indices (const hb_subset_plan_t* plan,
532*2d1272b8SAndroid Build Coastguard Worker                                   const void* list,
533*2d1272b8SAndroid Build Coastguard Worker                                   hb_set_t& varidx_set /* OUT */) const
534*2d1272b8SAndroid Build Coastguard Worker   {
535*2d1272b8SAndroid Build Coastguard Worker     if (!plan->layout_scripts.has (baseScriptTag))
536*2d1272b8SAndroid Build Coastguard Worker       return;
537*2d1272b8SAndroid Build Coastguard Worker 
538*2d1272b8SAndroid Build Coastguard Worker     (list+baseScript).collect_variation_indices (plan, varidx_set);
539*2d1272b8SAndroid Build Coastguard Worker   }
540*2d1272b8SAndroid Build Coastguard Worker 
subsetOT::BaseScriptRecord541*2d1272b8SAndroid Build Coastguard Worker   bool subset (hb_subset_context_t *c,
542*2d1272b8SAndroid Build Coastguard Worker                const void *base) const
543*2d1272b8SAndroid Build Coastguard Worker   {
544*2d1272b8SAndroid Build Coastguard Worker     TRACE_SUBSET (this);
545*2d1272b8SAndroid Build Coastguard Worker     auto *out = c->serializer->embed (*this);
546*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!out)) return_trace (false);
547*2d1272b8SAndroid Build Coastguard Worker 
548*2d1272b8SAndroid Build Coastguard Worker     return_trace (out->baseScript.serialize_subset (c, baseScript, base));
549*2d1272b8SAndroid Build Coastguard Worker   }
550*2d1272b8SAndroid Build Coastguard Worker 
sanitizeOT::BaseScriptRecord551*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c, const void *base) const
552*2d1272b8SAndroid Build Coastguard Worker   {
553*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
554*2d1272b8SAndroid Build Coastguard Worker     return_trace (likely (c->check_struct (this) &&
555*2d1272b8SAndroid Build Coastguard Worker 			  baseScript.sanitize (c, base)));
556*2d1272b8SAndroid Build Coastguard Worker   }
557*2d1272b8SAndroid Build Coastguard Worker 
558*2d1272b8SAndroid Build Coastguard Worker   protected:
559*2d1272b8SAndroid Build Coastguard Worker   Tag		baseScriptTag;	/* 4-byte script identification tag */
560*2d1272b8SAndroid Build Coastguard Worker   Offset16To<BaseScript>
561*2d1272b8SAndroid Build Coastguard Worker 		baseScript;	/* Offset to BaseScript table, from beginning
562*2d1272b8SAndroid Build Coastguard Worker 				 * of BaseScriptList */
563*2d1272b8SAndroid Build Coastguard Worker 
564*2d1272b8SAndroid Build Coastguard Worker   public:
565*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_STATIC (6);
566*2d1272b8SAndroid Build Coastguard Worker };
567*2d1272b8SAndroid Build Coastguard Worker 
568*2d1272b8SAndroid Build Coastguard Worker struct BaseScriptList
569*2d1272b8SAndroid Build Coastguard Worker {
get_base_scriptOT::BaseScriptList570*2d1272b8SAndroid Build Coastguard Worker   const BaseScript &get_base_script (hb_tag_t script) const
571*2d1272b8SAndroid Build Coastguard Worker   {
572*2d1272b8SAndroid Build Coastguard Worker     const BaseScriptRecord *record = &baseScriptRecords.bsearch (script);
573*2d1272b8SAndroid Build Coastguard Worker     if (!record->has_data ()) record = &baseScriptRecords.bsearch (HB_TAG ('D','F','L','T'));
574*2d1272b8SAndroid Build Coastguard Worker     return record->has_data () ? record->get_base_script (this) : Null (BaseScript);
575*2d1272b8SAndroid Build Coastguard Worker   }
576*2d1272b8SAndroid Build Coastguard Worker 
collect_variation_indicesOT::BaseScriptList577*2d1272b8SAndroid Build Coastguard Worker   void collect_variation_indices (const hb_subset_plan_t* plan,
578*2d1272b8SAndroid Build Coastguard Worker                                   hb_set_t& varidx_set /* OUT */) const
579*2d1272b8SAndroid Build Coastguard Worker   {
580*2d1272b8SAndroid Build Coastguard Worker     for (const BaseScriptRecord& _ : baseScriptRecords)
581*2d1272b8SAndroid Build Coastguard Worker       _.collect_variation_indices (plan, this, varidx_set);
582*2d1272b8SAndroid Build Coastguard Worker   }
583*2d1272b8SAndroid Build Coastguard Worker 
subsetOT::BaseScriptList584*2d1272b8SAndroid Build Coastguard Worker   bool subset (hb_subset_context_t *c) const
585*2d1272b8SAndroid Build Coastguard Worker   {
586*2d1272b8SAndroid Build Coastguard Worker     TRACE_SUBSET (this);
587*2d1272b8SAndroid Build Coastguard Worker     auto *out = c->serializer->start_embed (*this);
588*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
589*2d1272b8SAndroid Build Coastguard Worker 
590*2d1272b8SAndroid Build Coastguard Worker     unsigned len = 0;
591*2d1272b8SAndroid Build Coastguard Worker     for (const BaseScriptRecord& _ : baseScriptRecords)
592*2d1272b8SAndroid Build Coastguard Worker     {
593*2d1272b8SAndroid Build Coastguard Worker       hb_tag_t script_tag = _.get_script_tag ();
594*2d1272b8SAndroid Build Coastguard Worker       if (!c->plan->layout_scripts.has (script_tag))
595*2d1272b8SAndroid Build Coastguard Worker         continue;
596*2d1272b8SAndroid Build Coastguard Worker 
597*2d1272b8SAndroid Build Coastguard Worker       if (!_.subset (c, this)) return false;
598*2d1272b8SAndroid Build Coastguard Worker       len++;
599*2d1272b8SAndroid Build Coastguard Worker     }
600*2d1272b8SAndroid Build Coastguard Worker     return_trace (c->serializer->check_assign (out->baseScriptRecords.len, len,
601*2d1272b8SAndroid Build Coastguard Worker                                                HB_SERIALIZE_ERROR_INT_OVERFLOW));
602*2d1272b8SAndroid Build Coastguard Worker   }
603*2d1272b8SAndroid Build Coastguard Worker 
sanitizeOT::BaseScriptList604*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
605*2d1272b8SAndroid Build Coastguard Worker   {
606*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
607*2d1272b8SAndroid Build Coastguard Worker     return_trace (c->check_struct (this) &&
608*2d1272b8SAndroid Build Coastguard Worker 		  baseScriptRecords.sanitize (c, this));
609*2d1272b8SAndroid Build Coastguard Worker   }
610*2d1272b8SAndroid Build Coastguard Worker 
611*2d1272b8SAndroid Build Coastguard Worker   protected:
612*2d1272b8SAndroid Build Coastguard Worker   SortedArray16Of<BaseScriptRecord>
613*2d1272b8SAndroid Build Coastguard Worker 			baseScriptRecords;
614*2d1272b8SAndroid Build Coastguard Worker 
615*2d1272b8SAndroid Build Coastguard Worker   public:
616*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_ARRAY (2, baseScriptRecords);
617*2d1272b8SAndroid Build Coastguard Worker };
618*2d1272b8SAndroid Build Coastguard Worker 
619*2d1272b8SAndroid Build Coastguard Worker struct Axis
620*2d1272b8SAndroid Build Coastguard Worker {
get_baselineOT::Axis621*2d1272b8SAndroid Build Coastguard Worker   bool get_baseline (hb_tag_t          baseline_tag,
622*2d1272b8SAndroid Build Coastguard Worker 		     hb_tag_t          script_tag,
623*2d1272b8SAndroid Build Coastguard Worker 		     hb_tag_t          language_tag,
624*2d1272b8SAndroid Build Coastguard Worker 		     const BaseCoord **coord) const
625*2d1272b8SAndroid Build Coastguard Worker   {
626*2d1272b8SAndroid Build Coastguard Worker     const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag);
627*2d1272b8SAndroid Build Coastguard Worker     if (!base_script.has_values ())
628*2d1272b8SAndroid Build Coastguard Worker     {
629*2d1272b8SAndroid Build Coastguard Worker       *coord = nullptr;
630*2d1272b8SAndroid Build Coastguard Worker       return false;
631*2d1272b8SAndroid Build Coastguard Worker     }
632*2d1272b8SAndroid Build Coastguard Worker 
633*2d1272b8SAndroid Build Coastguard Worker     if (likely (coord))
634*2d1272b8SAndroid Build Coastguard Worker     {
635*2d1272b8SAndroid Build Coastguard Worker       unsigned int tag_index = 0;
636*2d1272b8SAndroid Build Coastguard Worker       if (!(this+baseTagList).bfind (baseline_tag, &tag_index))
637*2d1272b8SAndroid Build Coastguard Worker       {
638*2d1272b8SAndroid Build Coastguard Worker         *coord = nullptr;
639*2d1272b8SAndroid Build Coastguard Worker         return false;
640*2d1272b8SAndroid Build Coastguard Worker       }
641*2d1272b8SAndroid Build Coastguard Worker       *coord = &base_script.get_base_coord (tag_index);
642*2d1272b8SAndroid Build Coastguard Worker     }
643*2d1272b8SAndroid Build Coastguard Worker 
644*2d1272b8SAndroid Build Coastguard Worker     return true;
645*2d1272b8SAndroid Build Coastguard Worker   }
646*2d1272b8SAndroid Build Coastguard Worker 
get_min_maxOT::Axis647*2d1272b8SAndroid Build Coastguard Worker   bool get_min_max (hb_tag_t          script_tag,
648*2d1272b8SAndroid Build Coastguard Worker 		    hb_tag_t          language_tag,
649*2d1272b8SAndroid Build Coastguard Worker 		    hb_tag_t          feature_tag,
650*2d1272b8SAndroid Build Coastguard Worker 		    const BaseCoord **min_coord,
651*2d1272b8SAndroid Build Coastguard Worker 		    const BaseCoord **max_coord) const
652*2d1272b8SAndroid Build Coastguard Worker   {
653*2d1272b8SAndroid Build Coastguard Worker     const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag);
654*2d1272b8SAndroid Build Coastguard Worker     if (!base_script.has_min_max ())
655*2d1272b8SAndroid Build Coastguard Worker     {
656*2d1272b8SAndroid Build Coastguard Worker       *min_coord = *max_coord = nullptr;
657*2d1272b8SAndroid Build Coastguard Worker       return false;
658*2d1272b8SAndroid Build Coastguard Worker     }
659*2d1272b8SAndroid Build Coastguard Worker 
660*2d1272b8SAndroid Build Coastguard Worker     base_script.get_min_max (language_tag).get_min_max (feature_tag, min_coord, max_coord);
661*2d1272b8SAndroid Build Coastguard Worker 
662*2d1272b8SAndroid Build Coastguard Worker     return true;
663*2d1272b8SAndroid Build Coastguard Worker   }
664*2d1272b8SAndroid Build Coastguard Worker 
collect_variation_indicesOT::Axis665*2d1272b8SAndroid Build Coastguard Worker   void collect_variation_indices (const hb_subset_plan_t* plan,
666*2d1272b8SAndroid Build Coastguard Worker                                   hb_set_t& varidx_set /* OUT */) const
667*2d1272b8SAndroid Build Coastguard Worker   { (this+baseScriptList).collect_variation_indices (plan, varidx_set); }
668*2d1272b8SAndroid Build Coastguard Worker 
subsetOT::Axis669*2d1272b8SAndroid Build Coastguard Worker   bool subset (hb_subset_context_t *c) const
670*2d1272b8SAndroid Build Coastguard Worker   {
671*2d1272b8SAndroid Build Coastguard Worker     TRACE_SUBSET (this);
672*2d1272b8SAndroid Build Coastguard Worker     auto *out = c->serializer->embed (*this);
673*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!out)) return_trace (false);
674*2d1272b8SAndroid Build Coastguard Worker 
675*2d1272b8SAndroid Build Coastguard Worker     out->baseTagList.serialize_copy (c->serializer, baseTagList, this);
676*2d1272b8SAndroid Build Coastguard Worker     return_trace (out->baseScriptList.serialize_subset (c, baseScriptList, this));
677*2d1272b8SAndroid Build Coastguard Worker   }
678*2d1272b8SAndroid Build Coastguard Worker 
sanitizeOT::Axis679*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
680*2d1272b8SAndroid Build Coastguard Worker   {
681*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
682*2d1272b8SAndroid Build Coastguard Worker     return_trace (likely (c->check_struct (this) &&
683*2d1272b8SAndroid Build Coastguard Worker 			  baseTagList.sanitize (c, this) &&
684*2d1272b8SAndroid Build Coastguard Worker 			  baseScriptList.sanitize (c, this)));
685*2d1272b8SAndroid Build Coastguard Worker   }
686*2d1272b8SAndroid Build Coastguard Worker 
687*2d1272b8SAndroid Build Coastguard Worker   protected:
688*2d1272b8SAndroid Build Coastguard Worker   Offset16To<SortedArray16Of<Tag>>
689*2d1272b8SAndroid Build Coastguard Worker 		baseTagList;	/* Offset to BaseTagList table, from beginning
690*2d1272b8SAndroid Build Coastguard Worker 				 * of Axis table (may be NULL)
691*2d1272b8SAndroid Build Coastguard Worker 				 * Array of 4-byte baseline identification tags — must
692*2d1272b8SAndroid Build Coastguard Worker 				 * be in alphabetical order */
693*2d1272b8SAndroid Build Coastguard Worker   Offset16To<BaseScriptList>
694*2d1272b8SAndroid Build Coastguard Worker 		baseScriptList;	/* Offset to BaseScriptList table, from beginning
695*2d1272b8SAndroid Build Coastguard Worker 				 * of Axis table
696*2d1272b8SAndroid Build Coastguard Worker 				 * Array of BaseScriptRecords, in alphabetical order
697*2d1272b8SAndroid Build Coastguard Worker 				 * by baseScriptTag */
698*2d1272b8SAndroid Build Coastguard Worker 
699*2d1272b8SAndroid Build Coastguard Worker   public:
700*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_STATIC (4);
701*2d1272b8SAndroid Build Coastguard Worker };
702*2d1272b8SAndroid Build Coastguard Worker 
703*2d1272b8SAndroid Build Coastguard Worker struct BASE
704*2d1272b8SAndroid Build Coastguard Worker {
705*2d1272b8SAndroid Build Coastguard Worker   static constexpr hb_tag_t tableTag = HB_OT_TAG_BASE;
706*2d1272b8SAndroid Build Coastguard Worker 
get_axisOT::BASE707*2d1272b8SAndroid Build Coastguard Worker   const Axis &get_axis (hb_direction_t direction) const
708*2d1272b8SAndroid Build Coastguard Worker   { return HB_DIRECTION_IS_VERTICAL (direction) ? this+vAxis : this+hAxis; }
709*2d1272b8SAndroid Build Coastguard Worker 
has_var_storeOT::BASE710*2d1272b8SAndroid Build Coastguard Worker   bool has_var_store () const
711*2d1272b8SAndroid Build Coastguard Worker   { return version.to_int () >= 0x00010001u && varStore != 0; }
712*2d1272b8SAndroid Build Coastguard Worker 
get_var_storeOT::BASE713*2d1272b8SAndroid Build Coastguard Worker   const ItemVariationStore &get_var_store () const
714*2d1272b8SAndroid Build Coastguard Worker   { return version.to_int () < 0x00010001u ? Null (ItemVariationStore) : this+varStore; }
715*2d1272b8SAndroid Build Coastguard Worker 
collect_variation_indicesOT::BASE716*2d1272b8SAndroid Build Coastguard Worker   void collect_variation_indices (const hb_subset_plan_t* plan,
717*2d1272b8SAndroid Build Coastguard Worker                                   hb_set_t& varidx_set /* OUT */) const
718*2d1272b8SAndroid Build Coastguard Worker   {
719*2d1272b8SAndroid Build Coastguard Worker     (this+hAxis).collect_variation_indices (plan, varidx_set);
720*2d1272b8SAndroid Build Coastguard Worker     (this+vAxis).collect_variation_indices (plan, varidx_set);
721*2d1272b8SAndroid Build Coastguard Worker   }
722*2d1272b8SAndroid Build Coastguard Worker 
subset_varstoreOT::BASE723*2d1272b8SAndroid Build Coastguard Worker   bool subset_varstore (hb_subset_context_t *c,
724*2d1272b8SAndroid Build Coastguard Worker                         BASE *out /* OUT */) const
725*2d1272b8SAndroid Build Coastguard Worker   {
726*2d1272b8SAndroid Build Coastguard Worker     TRACE_SUBSET (this);
727*2d1272b8SAndroid Build Coastguard Worker     if (!c->serializer->allocate_size<Offset32To<ItemVariationStore>> (Offset32To<ItemVariationStore>::static_size))
728*2d1272b8SAndroid Build Coastguard Worker         return_trace (false);
729*2d1272b8SAndroid Build Coastguard Worker     if (!c->plan->normalized_coords)
730*2d1272b8SAndroid Build Coastguard Worker       return_trace (out->varStore.serialize_subset (c, varStore, this, c->plan->base_varstore_inner_maps.as_array ()));
731*2d1272b8SAndroid Build Coastguard Worker 
732*2d1272b8SAndroid Build Coastguard Worker     if (c->plan->all_axes_pinned)
733*2d1272b8SAndroid Build Coastguard Worker       return_trace (true);
734*2d1272b8SAndroid Build Coastguard Worker 
735*2d1272b8SAndroid Build Coastguard Worker     item_variations_t item_vars;
736*2d1272b8SAndroid Build Coastguard Worker     if (!item_vars.instantiate (this+varStore, c->plan, true, true,
737*2d1272b8SAndroid Build Coastguard Worker                                 c->plan->base_varstore_inner_maps.as_array ()))
738*2d1272b8SAndroid Build Coastguard Worker       return_trace (false);
739*2d1272b8SAndroid Build Coastguard Worker 
740*2d1272b8SAndroid Build Coastguard Worker     if (!out->varStore.serialize_serialize (c->serializer,
741*2d1272b8SAndroid Build Coastguard Worker                                             item_vars.has_long_word (),
742*2d1272b8SAndroid Build Coastguard Worker                                             c->plan->axis_tags,
743*2d1272b8SAndroid Build Coastguard Worker                                             item_vars.get_region_list (),
744*2d1272b8SAndroid Build Coastguard Worker                                             item_vars.get_vardata_encodings ()))
745*2d1272b8SAndroid Build Coastguard Worker       return_trace (false);
746*2d1272b8SAndroid Build Coastguard Worker 
747*2d1272b8SAndroid Build Coastguard Worker     const hb_map_t &varidx_map = item_vars.get_varidx_map ();
748*2d1272b8SAndroid Build Coastguard Worker     /* base_variation_idx_map in the plan is old_varidx->(varidx, delta)
749*2d1272b8SAndroid Build Coastguard Worker      * mapping, new varidx is generated for subsetting, we need to remap this
750*2d1272b8SAndroid Build Coastguard Worker      * after instancing */
751*2d1272b8SAndroid Build Coastguard Worker     for (auto _ : c->plan->base_variation_idx_map.iter_ref ())
752*2d1272b8SAndroid Build Coastguard Worker     {
753*2d1272b8SAndroid Build Coastguard Worker       uint32_t varidx = _.second.first;
754*2d1272b8SAndroid Build Coastguard Worker       uint32_t *new_varidx;
755*2d1272b8SAndroid Build Coastguard Worker       if (varidx_map.has (varidx, &new_varidx))
756*2d1272b8SAndroid Build Coastguard Worker         _.second.first = *new_varidx;
757*2d1272b8SAndroid Build Coastguard Worker       else
758*2d1272b8SAndroid Build Coastguard Worker         _.second.first = HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
759*2d1272b8SAndroid Build Coastguard Worker     }
760*2d1272b8SAndroid Build Coastguard Worker     return_trace (true);
761*2d1272b8SAndroid Build Coastguard Worker   }
762*2d1272b8SAndroid Build Coastguard Worker 
subsetOT::BASE763*2d1272b8SAndroid Build Coastguard Worker   bool subset (hb_subset_context_t *c) const
764*2d1272b8SAndroid Build Coastguard Worker   {
765*2d1272b8SAndroid Build Coastguard Worker     TRACE_SUBSET (this);
766*2d1272b8SAndroid Build Coastguard Worker     auto *out = c->serializer->start_embed (*this);
767*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
768*2d1272b8SAndroid Build Coastguard Worker 
769*2d1272b8SAndroid Build Coastguard Worker     out->version = version;
770*2d1272b8SAndroid Build Coastguard Worker     if (has_var_store () && !subset_varstore (c, out))
771*2d1272b8SAndroid Build Coastguard Worker         return_trace (false);
772*2d1272b8SAndroid Build Coastguard Worker 
773*2d1272b8SAndroid Build Coastguard Worker     if (hAxis && !out->hAxis.serialize_subset (c, hAxis, this))
774*2d1272b8SAndroid Build Coastguard Worker       return_trace (false);
775*2d1272b8SAndroid Build Coastguard Worker 
776*2d1272b8SAndroid Build Coastguard Worker     if (vAxis && !out->vAxis.serialize_subset (c, vAxis, this))
777*2d1272b8SAndroid Build Coastguard Worker       return_trace (false);
778*2d1272b8SAndroid Build Coastguard Worker 
779*2d1272b8SAndroid Build Coastguard Worker     return_trace (true);
780*2d1272b8SAndroid Build Coastguard Worker   }
781*2d1272b8SAndroid Build Coastguard Worker 
get_baselineOT::BASE782*2d1272b8SAndroid Build Coastguard Worker   bool get_baseline (hb_font_t      *font,
783*2d1272b8SAndroid Build Coastguard Worker 		     hb_tag_t        baseline_tag,
784*2d1272b8SAndroid Build Coastguard Worker 		     hb_direction_t  direction,
785*2d1272b8SAndroid Build Coastguard Worker 		     hb_tag_t        script_tag,
786*2d1272b8SAndroid Build Coastguard Worker 		     hb_tag_t        language_tag,
787*2d1272b8SAndroid Build Coastguard Worker 		     hb_position_t  *base) const
788*2d1272b8SAndroid Build Coastguard Worker   {
789*2d1272b8SAndroid Build Coastguard Worker     const BaseCoord *base_coord = nullptr;
790*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!get_axis (direction).get_baseline (baseline_tag, script_tag, language_tag, &base_coord) ||
791*2d1272b8SAndroid Build Coastguard Worker 		  !base_coord || !base_coord->has_data ()))
792*2d1272b8SAndroid Build Coastguard Worker       return false;
793*2d1272b8SAndroid Build Coastguard Worker 
794*2d1272b8SAndroid Build Coastguard Worker     if (likely (base))
795*2d1272b8SAndroid Build Coastguard Worker       *base = base_coord->get_coord (font, get_var_store (), direction);
796*2d1272b8SAndroid Build Coastguard Worker 
797*2d1272b8SAndroid Build Coastguard Worker     return true;
798*2d1272b8SAndroid Build Coastguard Worker   }
799*2d1272b8SAndroid Build Coastguard Worker 
get_min_maxOT::BASE800*2d1272b8SAndroid Build Coastguard Worker   bool get_min_max (hb_font_t      *font,
801*2d1272b8SAndroid Build Coastguard Worker 		    hb_direction_t  direction,
802*2d1272b8SAndroid Build Coastguard Worker 		    hb_tag_t        script_tag,
803*2d1272b8SAndroid Build Coastguard Worker 		    hb_tag_t        language_tag,
804*2d1272b8SAndroid Build Coastguard Worker 		    hb_tag_t        feature_tag,
805*2d1272b8SAndroid Build Coastguard Worker 		    hb_position_t  *min,
806*2d1272b8SAndroid Build Coastguard Worker 		    hb_position_t  *max) const
807*2d1272b8SAndroid Build Coastguard Worker   {
808*2d1272b8SAndroid Build Coastguard Worker     const BaseCoord *min_coord, *max_coord;
809*2d1272b8SAndroid Build Coastguard Worker     if (!get_axis (direction).get_min_max (script_tag, language_tag, feature_tag,
810*2d1272b8SAndroid Build Coastguard Worker 					   &min_coord, &max_coord))
811*2d1272b8SAndroid Build Coastguard Worker       return false;
812*2d1272b8SAndroid Build Coastguard Worker 
813*2d1272b8SAndroid Build Coastguard Worker     const ItemVariationStore &var_store = get_var_store ();
814*2d1272b8SAndroid Build Coastguard Worker     if (likely (min && min_coord)) *min = min_coord->get_coord (font, var_store, direction);
815*2d1272b8SAndroid Build Coastguard Worker     if (likely (max && max_coord)) *max = max_coord->get_coord (font, var_store, direction);
816*2d1272b8SAndroid Build Coastguard Worker     return true;
817*2d1272b8SAndroid Build Coastguard Worker   }
818*2d1272b8SAndroid Build Coastguard Worker 
sanitizeOT::BASE819*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
820*2d1272b8SAndroid Build Coastguard Worker   {
821*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
822*2d1272b8SAndroid Build Coastguard Worker     return_trace (likely (c->check_struct (this) &&
823*2d1272b8SAndroid Build Coastguard Worker 			  hb_barrier () &&
824*2d1272b8SAndroid Build Coastguard Worker 			  likely (version.major == 1) &&
825*2d1272b8SAndroid Build Coastguard Worker 			  hAxis.sanitize (c, this) &&
826*2d1272b8SAndroid Build Coastguard Worker 			  vAxis.sanitize (c, this) &&
827*2d1272b8SAndroid Build Coastguard Worker 			  (version.to_int () < 0x00010001u || varStore.sanitize (c, this))));
828*2d1272b8SAndroid Build Coastguard Worker   }
829*2d1272b8SAndroid Build Coastguard Worker 
830*2d1272b8SAndroid Build Coastguard Worker   protected:
831*2d1272b8SAndroid Build Coastguard Worker   FixedVersion<>version;	/* Version of the BASE table */
832*2d1272b8SAndroid Build Coastguard Worker   Offset16To<Axis>hAxis;		/* Offset to horizontal Axis table, from beginning
833*2d1272b8SAndroid Build Coastguard Worker 				 * of BASE table (may be NULL) */
834*2d1272b8SAndroid Build Coastguard Worker   Offset16To<Axis>vAxis;		/* Offset to vertical Axis table, from beginning
835*2d1272b8SAndroid Build Coastguard Worker 				 * of BASE table (may be NULL) */
836*2d1272b8SAndroid Build Coastguard Worker   Offset32To<ItemVariationStore>
837*2d1272b8SAndroid Build Coastguard Worker 		varStore;	/* Offset to the table of Item Variation
838*2d1272b8SAndroid Build Coastguard Worker 				 * Store--from beginning of BASE
839*2d1272b8SAndroid Build Coastguard Worker 				 * header (may be NULL).  Introduced
840*2d1272b8SAndroid Build Coastguard Worker 				 * in version 0x00010001. */
841*2d1272b8SAndroid Build Coastguard Worker   public:
842*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_MIN (8);
843*2d1272b8SAndroid Build Coastguard Worker };
844*2d1272b8SAndroid Build Coastguard Worker 
845*2d1272b8SAndroid Build Coastguard Worker 
846*2d1272b8SAndroid Build Coastguard Worker } /* namespace OT */
847*2d1272b8SAndroid Build Coastguard Worker 
848*2d1272b8SAndroid Build Coastguard Worker 
849*2d1272b8SAndroid Build Coastguard Worker #endif /* HB_OT_LAYOUT_BASE_TABLE_HH */
850