xref: /aosp_15_r20/external/harfbuzz_ng/src/hb-aat-layout-common.hh (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
1*2d1272b8SAndroid Build Coastguard Worker /*
2*2d1272b8SAndroid Build Coastguard Worker  * Copyright © 2017  Google, Inc.
3*2d1272b8SAndroid Build Coastguard Worker  *
4*2d1272b8SAndroid Build Coastguard Worker  *  This is part of HarfBuzz, a text shaping library.
5*2d1272b8SAndroid Build Coastguard Worker  *
6*2d1272b8SAndroid Build Coastguard Worker  * Permission is hereby granted, without written agreement and without
7*2d1272b8SAndroid Build Coastguard Worker  * license or royalty fees, to use, copy, modify, and distribute this
8*2d1272b8SAndroid Build Coastguard Worker  * software and its documentation for any purpose, provided that the
9*2d1272b8SAndroid Build Coastguard Worker  * above copyright notice and the following two paragraphs appear in
10*2d1272b8SAndroid Build Coastguard Worker  * all copies of this software.
11*2d1272b8SAndroid Build Coastguard Worker  *
12*2d1272b8SAndroid Build Coastguard Worker  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13*2d1272b8SAndroid Build Coastguard Worker  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14*2d1272b8SAndroid Build Coastguard Worker  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15*2d1272b8SAndroid Build Coastguard Worker  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16*2d1272b8SAndroid Build Coastguard Worker  * DAMAGE.
17*2d1272b8SAndroid Build Coastguard Worker  *
18*2d1272b8SAndroid Build Coastguard Worker  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19*2d1272b8SAndroid Build Coastguard Worker  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20*2d1272b8SAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
21*2d1272b8SAndroid Build Coastguard Worker  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22*2d1272b8SAndroid Build Coastguard Worker  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23*2d1272b8SAndroid Build Coastguard Worker  *
24*2d1272b8SAndroid Build Coastguard Worker  * Google Author(s): Behdad Esfahbod
25*2d1272b8SAndroid Build Coastguard Worker  */
26*2d1272b8SAndroid Build Coastguard Worker 
27*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_AAT_LAYOUT_COMMON_HH
28*2d1272b8SAndroid Build Coastguard Worker #define HB_AAT_LAYOUT_COMMON_HH
29*2d1272b8SAndroid Build Coastguard Worker 
30*2d1272b8SAndroid Build Coastguard Worker #include "hb-aat-layout.hh"
31*2d1272b8SAndroid Build Coastguard Worker #include "hb-aat-map.hh"
32*2d1272b8SAndroid Build Coastguard Worker #include "hb-open-type.hh"
33*2d1272b8SAndroid Build Coastguard Worker 
34*2d1272b8SAndroid Build Coastguard Worker namespace OT {
35*2d1272b8SAndroid Build Coastguard Worker struct GDEF;
36*2d1272b8SAndroid Build Coastguard Worker };
37*2d1272b8SAndroid Build Coastguard Worker 
38*2d1272b8SAndroid Build Coastguard Worker namespace AAT {
39*2d1272b8SAndroid Build Coastguard Worker 
40*2d1272b8SAndroid Build Coastguard Worker using namespace OT;
41*2d1272b8SAndroid Build Coastguard Worker 
42*2d1272b8SAndroid Build Coastguard Worker #define HB_AAT_BUFFER_DIGEST_THRESHOLD 32
43*2d1272b8SAndroid Build Coastguard Worker 
44*2d1272b8SAndroid Build Coastguard Worker struct ankr;
45*2d1272b8SAndroid Build Coastguard Worker 
46*2d1272b8SAndroid Build Coastguard Worker struct hb_aat_apply_context_t :
47*2d1272b8SAndroid Build Coastguard Worker        hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY>
48*2d1272b8SAndroid Build Coastguard Worker {
get_nameAAT::hb_aat_apply_context_t49*2d1272b8SAndroid Build Coastguard Worker   const char *get_name () { return "APPLY"; }
50*2d1272b8SAndroid Build Coastguard Worker   template <typename T, typename ...Ts>
dispatchAAT::hb_aat_apply_context_t51*2d1272b8SAndroid Build Coastguard Worker   return_t dispatch (const T &obj, Ts&&... ds)
52*2d1272b8SAndroid Build Coastguard Worker   { return obj.apply (this, std::forward<Ts> (ds)...); }
default_return_valueAAT::hb_aat_apply_context_t53*2d1272b8SAndroid Build Coastguard Worker   static return_t default_return_value () { return false; }
stop_sublookup_iterationAAT::hb_aat_apply_context_t54*2d1272b8SAndroid Build Coastguard Worker   bool stop_sublookup_iteration (return_t r) const { return r; }
55*2d1272b8SAndroid Build Coastguard Worker 
56*2d1272b8SAndroid Build Coastguard Worker   const hb_ot_shape_plan_t *plan;
57*2d1272b8SAndroid Build Coastguard Worker   hb_font_t *font;
58*2d1272b8SAndroid Build Coastguard Worker   hb_face_t *face;
59*2d1272b8SAndroid Build Coastguard Worker   hb_buffer_t *buffer;
60*2d1272b8SAndroid Build Coastguard Worker   hb_sanitize_context_t sanitizer;
61*2d1272b8SAndroid Build Coastguard Worker   const ankr *ankr_table;
62*2d1272b8SAndroid Build Coastguard Worker   const OT::GDEF *gdef_table;
63*2d1272b8SAndroid Build Coastguard Worker   const hb_sorted_vector_t<hb_aat_map_t::range_flags_t> *range_flags = nullptr;
64*2d1272b8SAndroid Build Coastguard Worker   hb_set_digest_t buffer_digest = hb_set_digest_t::full ();
65*2d1272b8SAndroid Build Coastguard Worker   hb_set_digest_t machine_glyph_set = hb_set_digest_t::full ();
66*2d1272b8SAndroid Build Coastguard Worker   hb_set_digest_t left_set = hb_set_digest_t::full ();
67*2d1272b8SAndroid Build Coastguard Worker   hb_set_digest_t right_set = hb_set_digest_t::full ();
68*2d1272b8SAndroid Build Coastguard Worker   hb_mask_t subtable_flags = 0;
69*2d1272b8SAndroid Build Coastguard Worker 
70*2d1272b8SAndroid Build Coastguard Worker   /* Unused. For debug tracing only. */
71*2d1272b8SAndroid Build Coastguard Worker   unsigned int lookup_index;
72*2d1272b8SAndroid Build Coastguard Worker 
73*2d1272b8SAndroid Build Coastguard Worker   HB_INTERNAL hb_aat_apply_context_t (const hb_ot_shape_plan_t *plan_,
74*2d1272b8SAndroid Build Coastguard Worker 				      hb_font_t *font_,
75*2d1272b8SAndroid Build Coastguard Worker 				      hb_buffer_t *buffer_,
76*2d1272b8SAndroid Build Coastguard Worker 				      hb_blob_t *blob = const_cast<hb_blob_t *> (&Null (hb_blob_t)));
77*2d1272b8SAndroid Build Coastguard Worker 
78*2d1272b8SAndroid Build Coastguard Worker   HB_INTERNAL ~hb_aat_apply_context_t ();
79*2d1272b8SAndroid Build Coastguard Worker 
80*2d1272b8SAndroid Build Coastguard Worker   HB_INTERNAL void set_ankr_table (const AAT::ankr *ankr_table_);
81*2d1272b8SAndroid Build Coastguard Worker 
set_lookup_indexAAT::hb_aat_apply_context_t82*2d1272b8SAndroid Build Coastguard Worker   void set_lookup_index (unsigned int i) { lookup_index = i; }
83*2d1272b8SAndroid Build Coastguard Worker };
84*2d1272b8SAndroid Build Coastguard Worker 
85*2d1272b8SAndroid Build Coastguard Worker 
86*2d1272b8SAndroid Build Coastguard Worker /*
87*2d1272b8SAndroid Build Coastguard Worker  * Lookup Table
88*2d1272b8SAndroid Build Coastguard Worker  */
89*2d1272b8SAndroid Build Coastguard Worker 
90*2d1272b8SAndroid Build Coastguard Worker enum { DELETED_GLYPH = 0xFFFF };
91*2d1272b8SAndroid Build Coastguard Worker 
92*2d1272b8SAndroid Build Coastguard Worker template <typename T> struct Lookup;
93*2d1272b8SAndroid Build Coastguard Worker 
94*2d1272b8SAndroid Build Coastguard Worker template <typename T>
95*2d1272b8SAndroid Build Coastguard Worker struct LookupFormat0
96*2d1272b8SAndroid Build Coastguard Worker {
97*2d1272b8SAndroid Build Coastguard Worker   friend struct Lookup<T>;
98*2d1272b8SAndroid Build Coastguard Worker 
99*2d1272b8SAndroid Build Coastguard Worker   private:
get_valueAAT::LookupFormat0100*2d1272b8SAndroid Build Coastguard Worker   const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
101*2d1272b8SAndroid Build Coastguard Worker   {
102*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (glyph_id >= num_glyphs)) return nullptr;
103*2d1272b8SAndroid Build Coastguard Worker     return &arrayZ[glyph_id];
104*2d1272b8SAndroid Build Coastguard Worker   }
105*2d1272b8SAndroid Build Coastguard Worker 
106*2d1272b8SAndroid Build Coastguard Worker   template <typename set_t>
collect_glyphsAAT::LookupFormat0107*2d1272b8SAndroid Build Coastguard Worker   void collect_glyphs (set_t &glyphs, unsigned num_glyphs) const
108*2d1272b8SAndroid Build Coastguard Worker   {
109*2d1272b8SAndroid Build Coastguard Worker     glyphs.add_range (0, num_glyphs - 1);
110*2d1272b8SAndroid Build Coastguard Worker   }
111*2d1272b8SAndroid Build Coastguard Worker 
sanitizeAAT::LookupFormat0112*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
113*2d1272b8SAndroid Build Coastguard Worker   {
114*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
115*2d1272b8SAndroid Build Coastguard Worker     return_trace (arrayZ.sanitize (c, c->get_num_glyphs ()));
116*2d1272b8SAndroid Build Coastguard Worker   }
sanitizeAAT::LookupFormat0117*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c, const void *base) const
118*2d1272b8SAndroid Build Coastguard Worker   {
119*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
120*2d1272b8SAndroid Build Coastguard Worker     return_trace (arrayZ.sanitize (c, c->get_num_glyphs (), base));
121*2d1272b8SAndroid Build Coastguard Worker   }
122*2d1272b8SAndroid Build Coastguard Worker 
123*2d1272b8SAndroid Build Coastguard Worker   protected:
124*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	format;		/* Format identifier--format = 0 */
125*2d1272b8SAndroid Build Coastguard Worker   UnsizedArrayOf<T>
126*2d1272b8SAndroid Build Coastguard Worker 		arrayZ;		/* Array of lookup values, indexed by glyph index. */
127*2d1272b8SAndroid Build Coastguard Worker   public:
128*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_UNBOUNDED (2);
129*2d1272b8SAndroid Build Coastguard Worker };
130*2d1272b8SAndroid Build Coastguard Worker 
131*2d1272b8SAndroid Build Coastguard Worker 
132*2d1272b8SAndroid Build Coastguard Worker template <typename T>
133*2d1272b8SAndroid Build Coastguard Worker struct LookupSegmentSingle
134*2d1272b8SAndroid Build Coastguard Worker {
135*2d1272b8SAndroid Build Coastguard Worker   static constexpr unsigned TerminationWordCount = 2u;
136*2d1272b8SAndroid Build Coastguard Worker 
cmpAAT::LookupSegmentSingle137*2d1272b8SAndroid Build Coastguard Worker   int cmp (hb_codepoint_t g) const
138*2d1272b8SAndroid Build Coastguard Worker   { return g < first ? -1 : g <= last ? 0 : +1 ; }
139*2d1272b8SAndroid Build Coastguard Worker 
140*2d1272b8SAndroid Build Coastguard Worker   template <typename set_t>
collect_glyphsAAT::LookupSegmentSingle141*2d1272b8SAndroid Build Coastguard Worker   void collect_glyphs (set_t &glyphs) const
142*2d1272b8SAndroid Build Coastguard Worker   {
143*2d1272b8SAndroid Build Coastguard Worker     if (first == DELETED_GLYPH)
144*2d1272b8SAndroid Build Coastguard Worker       return;
145*2d1272b8SAndroid Build Coastguard Worker     glyphs.add_range (first, last);
146*2d1272b8SAndroid Build Coastguard Worker   }
147*2d1272b8SAndroid Build Coastguard Worker 
sanitizeAAT::LookupSegmentSingle148*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 (c->check_struct (this) && value.sanitize (c));
152*2d1272b8SAndroid Build Coastguard Worker   }
sanitizeAAT::LookupSegmentSingle153*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c, const void *base) const
154*2d1272b8SAndroid Build Coastguard Worker   {
155*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
156*2d1272b8SAndroid Build Coastguard Worker     return_trace (c->check_struct (this) && value.sanitize (c, base));
157*2d1272b8SAndroid Build Coastguard Worker   }
158*2d1272b8SAndroid Build Coastguard Worker 
159*2d1272b8SAndroid Build Coastguard Worker   HBGlyphID16	last;		/* Last GlyphID in this segment */
160*2d1272b8SAndroid Build Coastguard Worker   HBGlyphID16	first;		/* First GlyphID in this segment */
161*2d1272b8SAndroid Build Coastguard Worker   T		value;		/* The lookup value (only one) */
162*2d1272b8SAndroid Build Coastguard Worker   public:
163*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_STATIC (4 + T::static_size);
164*2d1272b8SAndroid Build Coastguard Worker };
165*2d1272b8SAndroid Build Coastguard Worker 
166*2d1272b8SAndroid Build Coastguard Worker template <typename T>
167*2d1272b8SAndroid Build Coastguard Worker struct LookupFormat2
168*2d1272b8SAndroid Build Coastguard Worker {
169*2d1272b8SAndroid Build Coastguard Worker   friend struct Lookup<T>;
170*2d1272b8SAndroid Build Coastguard Worker 
171*2d1272b8SAndroid Build Coastguard Worker   private:
get_valueAAT::LookupFormat2172*2d1272b8SAndroid Build Coastguard Worker   const T* get_value (hb_codepoint_t glyph_id) const
173*2d1272b8SAndroid Build Coastguard Worker   {
174*2d1272b8SAndroid Build Coastguard Worker     const LookupSegmentSingle<T> *v = segments.bsearch (glyph_id);
175*2d1272b8SAndroid Build Coastguard Worker     return v ? &v->value : nullptr;
176*2d1272b8SAndroid Build Coastguard Worker   }
177*2d1272b8SAndroid Build Coastguard Worker 
178*2d1272b8SAndroid Build Coastguard Worker   template <typename set_t>
collect_glyphsAAT::LookupFormat2179*2d1272b8SAndroid Build Coastguard Worker   void collect_glyphs (set_t &glyphs) const
180*2d1272b8SAndroid Build Coastguard Worker   {
181*2d1272b8SAndroid Build Coastguard Worker     unsigned count = segments.get_length ();
182*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int i = 0; i < count; i++)
183*2d1272b8SAndroid Build Coastguard Worker       segments[i].collect_glyphs (glyphs);
184*2d1272b8SAndroid Build Coastguard Worker   }
185*2d1272b8SAndroid Build Coastguard Worker 
sanitizeAAT::LookupFormat2186*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
187*2d1272b8SAndroid Build Coastguard Worker   {
188*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
189*2d1272b8SAndroid Build Coastguard Worker     return_trace (segments.sanitize (c));
190*2d1272b8SAndroid Build Coastguard Worker   }
sanitizeAAT::LookupFormat2191*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c, const void *base) const
192*2d1272b8SAndroid Build Coastguard Worker   {
193*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
194*2d1272b8SAndroid Build Coastguard Worker     return_trace (segments.sanitize (c, base));
195*2d1272b8SAndroid Build Coastguard Worker   }
196*2d1272b8SAndroid Build Coastguard Worker 
197*2d1272b8SAndroid Build Coastguard Worker   protected:
198*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	format;		/* Format identifier--format = 2 */
199*2d1272b8SAndroid Build Coastguard Worker   VarSizedBinSearchArrayOf<LookupSegmentSingle<T>>
200*2d1272b8SAndroid Build Coastguard Worker 		segments;	/* The actual segments. These must already be sorted,
201*2d1272b8SAndroid Build Coastguard Worker 				 * according to the first word in each one (the last
202*2d1272b8SAndroid Build Coastguard Worker 				 * glyph in each segment). */
203*2d1272b8SAndroid Build Coastguard Worker   public:
204*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_ARRAY (8, segments);
205*2d1272b8SAndroid Build Coastguard Worker };
206*2d1272b8SAndroid Build Coastguard Worker 
207*2d1272b8SAndroid Build Coastguard Worker template <typename T>
208*2d1272b8SAndroid Build Coastguard Worker struct LookupSegmentArray
209*2d1272b8SAndroid Build Coastguard Worker {
210*2d1272b8SAndroid Build Coastguard Worker   static constexpr unsigned TerminationWordCount = 2u;
211*2d1272b8SAndroid Build Coastguard Worker 
get_valueAAT::LookupSegmentArray212*2d1272b8SAndroid Build Coastguard Worker   const T* get_value (hb_codepoint_t glyph_id, const void *base) const
213*2d1272b8SAndroid Build Coastguard Worker   {
214*2d1272b8SAndroid Build Coastguard Worker     return first <= glyph_id && glyph_id <= last ? &(base+valuesZ)[glyph_id - first] : nullptr;
215*2d1272b8SAndroid Build Coastguard Worker   }
216*2d1272b8SAndroid Build Coastguard Worker 
217*2d1272b8SAndroid Build Coastguard Worker   template <typename set_t>
collect_glyphsAAT::LookupSegmentArray218*2d1272b8SAndroid Build Coastguard Worker   void collect_glyphs (set_t &glyphs) const
219*2d1272b8SAndroid Build Coastguard Worker   {
220*2d1272b8SAndroid Build Coastguard Worker     if (first == DELETED_GLYPH)
221*2d1272b8SAndroid Build Coastguard Worker       return;
222*2d1272b8SAndroid Build Coastguard Worker     glyphs.add_range (first, last);
223*2d1272b8SAndroid Build Coastguard Worker   }
224*2d1272b8SAndroid Build Coastguard Worker 
cmpAAT::LookupSegmentArray225*2d1272b8SAndroid Build Coastguard Worker   int cmp (hb_codepoint_t g) const
226*2d1272b8SAndroid Build Coastguard Worker   { return g < first ? -1 : g <= last ? 0 : +1; }
227*2d1272b8SAndroid Build Coastguard Worker 
sanitizeAAT::LookupSegmentArray228*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c, const void *base) const
229*2d1272b8SAndroid Build Coastguard Worker   {
230*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
231*2d1272b8SAndroid Build Coastguard Worker     return_trace (c->check_struct (this) &&
232*2d1272b8SAndroid Build Coastguard Worker 		  hb_barrier () &&
233*2d1272b8SAndroid Build Coastguard Worker 		  first <= last &&
234*2d1272b8SAndroid Build Coastguard Worker 		  valuesZ.sanitize (c, base, last - first + 1));
235*2d1272b8SAndroid Build Coastguard Worker   }
236*2d1272b8SAndroid Build Coastguard Worker   template <typename ...Ts>
sanitizeAAT::LookupSegmentArray237*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c, const void *base, Ts&&... ds) const
238*2d1272b8SAndroid Build Coastguard Worker   {
239*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
240*2d1272b8SAndroid Build Coastguard Worker     return_trace (c->check_struct (this) &&
241*2d1272b8SAndroid Build Coastguard Worker 		  hb_barrier () &&
242*2d1272b8SAndroid Build Coastguard Worker 		  first <= last &&
243*2d1272b8SAndroid Build Coastguard Worker 		  valuesZ.sanitize (c, base, last - first + 1, std::forward<Ts> (ds)...));
244*2d1272b8SAndroid Build Coastguard Worker   }
245*2d1272b8SAndroid Build Coastguard Worker 
246*2d1272b8SAndroid Build Coastguard Worker   HBGlyphID16	last;		/* Last GlyphID in this segment */
247*2d1272b8SAndroid Build Coastguard Worker   HBGlyphID16	first;		/* First GlyphID in this segment */
248*2d1272b8SAndroid Build Coastguard Worker   NNOffset16To<UnsizedArrayOf<T>>
249*2d1272b8SAndroid Build Coastguard Worker 		valuesZ;	/* A 16-bit offset from the start of
250*2d1272b8SAndroid Build Coastguard Worker 				 * the table to the data. */
251*2d1272b8SAndroid Build Coastguard Worker   public:
252*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_STATIC (6);
253*2d1272b8SAndroid Build Coastguard Worker };
254*2d1272b8SAndroid Build Coastguard Worker 
255*2d1272b8SAndroid Build Coastguard Worker template <typename T>
256*2d1272b8SAndroid Build Coastguard Worker struct LookupFormat4
257*2d1272b8SAndroid Build Coastguard Worker {
258*2d1272b8SAndroid Build Coastguard Worker   friend struct Lookup<T>;
259*2d1272b8SAndroid Build Coastguard Worker 
260*2d1272b8SAndroid Build Coastguard Worker   private:
get_valueAAT::LookupFormat4261*2d1272b8SAndroid Build Coastguard Worker   const T* get_value (hb_codepoint_t glyph_id) const
262*2d1272b8SAndroid Build Coastguard Worker   {
263*2d1272b8SAndroid Build Coastguard Worker     const LookupSegmentArray<T> *v = segments.bsearch (glyph_id);
264*2d1272b8SAndroid Build Coastguard Worker     return v ? v->get_value (glyph_id, this) : nullptr;
265*2d1272b8SAndroid Build Coastguard Worker   }
266*2d1272b8SAndroid Build Coastguard Worker 
267*2d1272b8SAndroid Build Coastguard Worker   template <typename set_t>
collect_glyphsAAT::LookupFormat4268*2d1272b8SAndroid Build Coastguard Worker   void collect_glyphs (set_t &glyphs) const
269*2d1272b8SAndroid Build Coastguard Worker   {
270*2d1272b8SAndroid Build Coastguard Worker     unsigned count = segments.get_length ();
271*2d1272b8SAndroid Build Coastguard Worker     for (unsigned i = 0; i < count; i++)
272*2d1272b8SAndroid Build Coastguard Worker       segments[i].collect_glyphs (glyphs);
273*2d1272b8SAndroid Build Coastguard Worker   }
274*2d1272b8SAndroid Build Coastguard Worker 
sanitizeAAT::LookupFormat4275*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
276*2d1272b8SAndroid Build Coastguard Worker   {
277*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
278*2d1272b8SAndroid Build Coastguard Worker     return_trace (segments.sanitize (c, this));
279*2d1272b8SAndroid Build Coastguard Worker   }
sanitizeAAT::LookupFormat4280*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c, const void *base) const
281*2d1272b8SAndroid Build Coastguard Worker   {
282*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
283*2d1272b8SAndroid Build Coastguard Worker     return_trace (segments.sanitize (c, this, base));
284*2d1272b8SAndroid Build Coastguard Worker   }
285*2d1272b8SAndroid Build Coastguard Worker 
286*2d1272b8SAndroid Build Coastguard Worker   protected:
287*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	format;		/* Format identifier--format = 4 */
288*2d1272b8SAndroid Build Coastguard Worker   VarSizedBinSearchArrayOf<LookupSegmentArray<T>>
289*2d1272b8SAndroid Build Coastguard Worker 		segments;	/* The actual segments. These must already be sorted,
290*2d1272b8SAndroid Build Coastguard Worker 				 * according to the first word in each one (the last
291*2d1272b8SAndroid Build Coastguard Worker 				 * glyph in each segment). */
292*2d1272b8SAndroid Build Coastguard Worker   public:
293*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_ARRAY (8, segments);
294*2d1272b8SAndroid Build Coastguard Worker };
295*2d1272b8SAndroid Build Coastguard Worker 
296*2d1272b8SAndroid Build Coastguard Worker template <typename T>
297*2d1272b8SAndroid Build Coastguard Worker struct LookupSingle
298*2d1272b8SAndroid Build Coastguard Worker {
299*2d1272b8SAndroid Build Coastguard Worker   static constexpr unsigned TerminationWordCount = 1u;
300*2d1272b8SAndroid Build Coastguard Worker 
cmpAAT::LookupSingle301*2d1272b8SAndroid Build Coastguard Worker   int cmp (hb_codepoint_t g) const { return glyph.cmp (g); }
302*2d1272b8SAndroid Build Coastguard Worker 
303*2d1272b8SAndroid Build Coastguard Worker   template <typename set_t>
collect_glyphsAAT::LookupSingle304*2d1272b8SAndroid Build Coastguard Worker   void collect_glyphs (set_t &glyphs) const
305*2d1272b8SAndroid Build Coastguard Worker   {
306*2d1272b8SAndroid Build Coastguard Worker     if (glyph == DELETED_GLYPH)
307*2d1272b8SAndroid Build Coastguard Worker       return;
308*2d1272b8SAndroid Build Coastguard Worker     glyphs.add (glyph);
309*2d1272b8SAndroid Build Coastguard Worker   }
310*2d1272b8SAndroid Build Coastguard Worker 
sanitizeAAT::LookupSingle311*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
312*2d1272b8SAndroid Build Coastguard Worker   {
313*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
314*2d1272b8SAndroid Build Coastguard Worker     return_trace (c->check_struct (this) && value.sanitize (c));
315*2d1272b8SAndroid Build Coastguard Worker   }
sanitizeAAT::LookupSingle316*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c, const void *base) const
317*2d1272b8SAndroid Build Coastguard Worker   {
318*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
319*2d1272b8SAndroid Build Coastguard Worker     return_trace (c->check_struct (this) && value.sanitize (c, base));
320*2d1272b8SAndroid Build Coastguard Worker   }
321*2d1272b8SAndroid Build Coastguard Worker 
322*2d1272b8SAndroid Build Coastguard Worker   HBGlyphID16	glyph;		/* Last GlyphID */
323*2d1272b8SAndroid Build Coastguard Worker   T		value;		/* The lookup value (only one) */
324*2d1272b8SAndroid Build Coastguard Worker   public:
325*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_STATIC (2 + T::static_size);
326*2d1272b8SAndroid Build Coastguard Worker };
327*2d1272b8SAndroid Build Coastguard Worker 
328*2d1272b8SAndroid Build Coastguard Worker template <typename T>
329*2d1272b8SAndroid Build Coastguard Worker struct LookupFormat6
330*2d1272b8SAndroid Build Coastguard Worker {
331*2d1272b8SAndroid Build Coastguard Worker   friend struct Lookup<T>;
332*2d1272b8SAndroid Build Coastguard Worker 
333*2d1272b8SAndroid Build Coastguard Worker   private:
get_valueAAT::LookupFormat6334*2d1272b8SAndroid Build Coastguard Worker   const T* get_value (hb_codepoint_t glyph_id) const
335*2d1272b8SAndroid Build Coastguard Worker   {
336*2d1272b8SAndroid Build Coastguard Worker     const LookupSingle<T> *v = entries.bsearch (glyph_id);
337*2d1272b8SAndroid Build Coastguard Worker     return v ? &v->value : nullptr;
338*2d1272b8SAndroid Build Coastguard Worker   }
339*2d1272b8SAndroid Build Coastguard Worker 
340*2d1272b8SAndroid Build Coastguard Worker   template <typename set_t>
collect_glyphsAAT::LookupFormat6341*2d1272b8SAndroid Build Coastguard Worker   void collect_glyphs (set_t &glyphs) const
342*2d1272b8SAndroid Build Coastguard Worker   {
343*2d1272b8SAndroid Build Coastguard Worker     unsigned count = entries.get_length ();
344*2d1272b8SAndroid Build Coastguard Worker     for (unsigned i = 0; i < count; i++)
345*2d1272b8SAndroid Build Coastguard Worker       entries[i].collect_glyphs (glyphs);
346*2d1272b8SAndroid Build Coastguard Worker   }
347*2d1272b8SAndroid Build Coastguard Worker 
sanitizeAAT::LookupFormat6348*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
349*2d1272b8SAndroid Build Coastguard Worker   {
350*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
351*2d1272b8SAndroid Build Coastguard Worker     return_trace (entries.sanitize (c));
352*2d1272b8SAndroid Build Coastguard Worker   }
sanitizeAAT::LookupFormat6353*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c, const void *base) const
354*2d1272b8SAndroid Build Coastguard Worker   {
355*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
356*2d1272b8SAndroid Build Coastguard Worker     return_trace (entries.sanitize (c, base));
357*2d1272b8SAndroid Build Coastguard Worker   }
358*2d1272b8SAndroid Build Coastguard Worker 
359*2d1272b8SAndroid Build Coastguard Worker   protected:
360*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	format;		/* Format identifier--format = 6 */
361*2d1272b8SAndroid Build Coastguard Worker   VarSizedBinSearchArrayOf<LookupSingle<T>>
362*2d1272b8SAndroid Build Coastguard Worker 		entries;	/* The actual entries, sorted by glyph index. */
363*2d1272b8SAndroid Build Coastguard Worker   public:
364*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_ARRAY (8, entries);
365*2d1272b8SAndroid Build Coastguard Worker };
366*2d1272b8SAndroid Build Coastguard Worker 
367*2d1272b8SAndroid Build Coastguard Worker template <typename T>
368*2d1272b8SAndroid Build Coastguard Worker struct LookupFormat8
369*2d1272b8SAndroid Build Coastguard Worker {
370*2d1272b8SAndroid Build Coastguard Worker   friend struct Lookup<T>;
371*2d1272b8SAndroid Build Coastguard Worker 
372*2d1272b8SAndroid Build Coastguard Worker   private:
get_valueAAT::LookupFormat8373*2d1272b8SAndroid Build Coastguard Worker   const T* get_value (hb_codepoint_t glyph_id) const
374*2d1272b8SAndroid Build Coastguard Worker   {
375*2d1272b8SAndroid Build Coastguard Worker     return firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount ?
376*2d1272b8SAndroid Build Coastguard Worker 	   &valueArrayZ[glyph_id - firstGlyph] : nullptr;
377*2d1272b8SAndroid Build Coastguard Worker   }
378*2d1272b8SAndroid Build Coastguard Worker 
379*2d1272b8SAndroid Build Coastguard Worker   template <typename set_t>
collect_glyphsAAT::LookupFormat8380*2d1272b8SAndroid Build Coastguard Worker   void collect_glyphs (set_t &glyphs) const
381*2d1272b8SAndroid Build Coastguard Worker   {
382*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!glyphCount))
383*2d1272b8SAndroid Build Coastguard Worker       return;
384*2d1272b8SAndroid Build Coastguard Worker     if (firstGlyph == DELETED_GLYPH)
385*2d1272b8SAndroid Build Coastguard Worker       return;
386*2d1272b8SAndroid Build Coastguard Worker     glyphs.add_range (firstGlyph, firstGlyph + glyphCount - 1);
387*2d1272b8SAndroid Build Coastguard Worker   }
388*2d1272b8SAndroid Build Coastguard Worker 
sanitizeAAT::LookupFormat8389*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
390*2d1272b8SAndroid Build Coastguard Worker   {
391*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
392*2d1272b8SAndroid Build Coastguard Worker     return_trace (c->check_struct (this) && valueArrayZ.sanitize (c, glyphCount));
393*2d1272b8SAndroid Build Coastguard Worker   }
sanitizeAAT::LookupFormat8394*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c, const void *base) const
395*2d1272b8SAndroid Build Coastguard Worker   {
396*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
397*2d1272b8SAndroid Build Coastguard Worker     return_trace (c->check_struct (this) && valueArrayZ.sanitize (c, glyphCount, base));
398*2d1272b8SAndroid Build Coastguard Worker   }
399*2d1272b8SAndroid Build Coastguard Worker 
400*2d1272b8SAndroid Build Coastguard Worker   protected:
401*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	format;		/* Format identifier--format = 8 */
402*2d1272b8SAndroid Build Coastguard Worker   HBGlyphID16	firstGlyph;	/* First glyph index included in the trimmed array. */
403*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	glyphCount;	/* Total number of glyphs (equivalent to the last
404*2d1272b8SAndroid Build Coastguard Worker 				 * glyph minus the value of firstGlyph plus 1). */
405*2d1272b8SAndroid Build Coastguard Worker   UnsizedArrayOf<T>
406*2d1272b8SAndroid Build Coastguard Worker 		valueArrayZ;	/* The lookup values (indexed by the glyph index
407*2d1272b8SAndroid Build Coastguard Worker 				 * minus the value of firstGlyph). */
408*2d1272b8SAndroid Build Coastguard Worker   public:
409*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_ARRAY (6, valueArrayZ);
410*2d1272b8SAndroid Build Coastguard Worker };
411*2d1272b8SAndroid Build Coastguard Worker 
412*2d1272b8SAndroid Build Coastguard Worker template <typename T>
413*2d1272b8SAndroid Build Coastguard Worker struct LookupFormat10
414*2d1272b8SAndroid Build Coastguard Worker {
415*2d1272b8SAndroid Build Coastguard Worker   friend struct Lookup<T>;
416*2d1272b8SAndroid Build Coastguard Worker 
417*2d1272b8SAndroid Build Coastguard Worker   private:
get_value_or_nullAAT::LookupFormat10418*2d1272b8SAndroid Build Coastguard Worker   const typename T::type get_value_or_null (hb_codepoint_t glyph_id) const
419*2d1272b8SAndroid Build Coastguard Worker   {
420*2d1272b8SAndroid Build Coastguard Worker     if (!(firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount))
421*2d1272b8SAndroid Build Coastguard Worker       return Null (T);
422*2d1272b8SAndroid Build Coastguard Worker 
423*2d1272b8SAndroid Build Coastguard Worker     const HBUINT8 *p = &valueArrayZ[(glyph_id - firstGlyph) * valueSize];
424*2d1272b8SAndroid Build Coastguard Worker 
425*2d1272b8SAndroid Build Coastguard Worker     unsigned int v = 0;
426*2d1272b8SAndroid Build Coastguard Worker     unsigned int count = valueSize;
427*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int i = 0; i < count; i++)
428*2d1272b8SAndroid Build Coastguard Worker       v = (v << 8) | *p++;
429*2d1272b8SAndroid Build Coastguard Worker 
430*2d1272b8SAndroid Build Coastguard Worker     return v;
431*2d1272b8SAndroid Build Coastguard Worker   }
432*2d1272b8SAndroid Build Coastguard Worker 
433*2d1272b8SAndroid Build Coastguard Worker   template <typename set_t>
collect_glyphsAAT::LookupFormat10434*2d1272b8SAndroid Build Coastguard Worker   void collect_glyphs (set_t &glyphs) const
435*2d1272b8SAndroid Build Coastguard Worker   {
436*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!glyphCount))
437*2d1272b8SAndroid Build Coastguard Worker       return;
438*2d1272b8SAndroid Build Coastguard Worker     if (firstGlyph == DELETED_GLYPH)
439*2d1272b8SAndroid Build Coastguard Worker       return;
440*2d1272b8SAndroid Build Coastguard Worker     glyphs.add_range (firstGlyph, firstGlyph + glyphCount - 1);
441*2d1272b8SAndroid Build Coastguard Worker   }
442*2d1272b8SAndroid Build Coastguard Worker 
sanitizeAAT::LookupFormat10443*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
444*2d1272b8SAndroid Build Coastguard Worker   {
445*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
446*2d1272b8SAndroid Build Coastguard Worker     return_trace (c->check_struct (this) &&
447*2d1272b8SAndroid Build Coastguard Worker 		  hb_barrier () &&
448*2d1272b8SAndroid Build Coastguard Worker 		  valueSize <= 4 &&
449*2d1272b8SAndroid Build Coastguard Worker 		  valueArrayZ.sanitize (c, glyphCount * valueSize));
450*2d1272b8SAndroid Build Coastguard Worker   }
451*2d1272b8SAndroid Build Coastguard Worker 
452*2d1272b8SAndroid Build Coastguard Worker   protected:
453*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	format;		/* Format identifier--format = 8 */
454*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	valueSize;	/* Byte size of each value. */
455*2d1272b8SAndroid Build Coastguard Worker   HBGlyphID16	firstGlyph;	/* First glyph index included in the trimmed array. */
456*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	glyphCount;	/* Total number of glyphs (equivalent to the last
457*2d1272b8SAndroid Build Coastguard Worker 				 * glyph minus the value of firstGlyph plus 1). */
458*2d1272b8SAndroid Build Coastguard Worker   UnsizedArrayOf<HBUINT8>
459*2d1272b8SAndroid Build Coastguard Worker 		valueArrayZ;	/* The lookup values (indexed by the glyph index
460*2d1272b8SAndroid Build Coastguard Worker 				 * minus the value of firstGlyph). */
461*2d1272b8SAndroid Build Coastguard Worker   public:
462*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_ARRAY (8, valueArrayZ);
463*2d1272b8SAndroid Build Coastguard Worker };
464*2d1272b8SAndroid Build Coastguard Worker 
465*2d1272b8SAndroid Build Coastguard Worker template <typename T>
466*2d1272b8SAndroid Build Coastguard Worker struct Lookup
467*2d1272b8SAndroid Build Coastguard Worker {
get_valueAAT::Lookup468*2d1272b8SAndroid Build Coastguard Worker   const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
469*2d1272b8SAndroid Build Coastguard Worker   {
470*2d1272b8SAndroid Build Coastguard Worker     switch (u.format) {
471*2d1272b8SAndroid Build Coastguard Worker     case 0: hb_barrier (); return u.format0.get_value (glyph_id, num_glyphs);
472*2d1272b8SAndroid Build Coastguard Worker     case 2: hb_barrier (); return u.format2.get_value (glyph_id);
473*2d1272b8SAndroid Build Coastguard Worker     case 4: hb_barrier (); return u.format4.get_value (glyph_id);
474*2d1272b8SAndroid Build Coastguard Worker     case 6: hb_barrier (); return u.format6.get_value (glyph_id);
475*2d1272b8SAndroid Build Coastguard Worker     case 8: hb_barrier (); return u.format8.get_value (glyph_id);
476*2d1272b8SAndroid Build Coastguard Worker     default:return nullptr;
477*2d1272b8SAndroid Build Coastguard Worker     }
478*2d1272b8SAndroid Build Coastguard Worker   }
479*2d1272b8SAndroid Build Coastguard Worker 
get_value_or_nullAAT::Lookup480*2d1272b8SAndroid Build Coastguard Worker   const typename T::type get_value_or_null (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
481*2d1272b8SAndroid Build Coastguard Worker   {
482*2d1272b8SAndroid Build Coastguard Worker     switch (u.format) {
483*2d1272b8SAndroid Build Coastguard Worker       /* Format 10 cannot return a pointer. */
484*2d1272b8SAndroid Build Coastguard Worker       case 10: hb_barrier (); return u.format10.get_value_or_null (glyph_id);
485*2d1272b8SAndroid Build Coastguard Worker       default:
486*2d1272b8SAndroid Build Coastguard Worker       const T *v = get_value (glyph_id, num_glyphs);
487*2d1272b8SAndroid Build Coastguard Worker       return v ? *v : Null (T);
488*2d1272b8SAndroid Build Coastguard Worker     }
489*2d1272b8SAndroid Build Coastguard Worker   }
490*2d1272b8SAndroid Build Coastguard Worker 
491*2d1272b8SAndroid Build Coastguard Worker   template <typename set_t>
collect_glyphsAAT::Lookup492*2d1272b8SAndroid Build Coastguard Worker   void collect_glyphs (set_t &glyphs, unsigned int num_glyphs) const
493*2d1272b8SAndroid Build Coastguard Worker   {
494*2d1272b8SAndroid Build Coastguard Worker     switch (u.format) {
495*2d1272b8SAndroid Build Coastguard Worker     case 0: hb_barrier (); u.format0.collect_glyphs (glyphs, num_glyphs); return;
496*2d1272b8SAndroid Build Coastguard Worker     case 2: hb_barrier (); u.format2.collect_glyphs (glyphs); return;
497*2d1272b8SAndroid Build Coastguard Worker     case 4: hb_barrier (); u.format4.collect_glyphs (glyphs); return;
498*2d1272b8SAndroid Build Coastguard Worker     case 6: hb_barrier (); u.format6.collect_glyphs (glyphs); return;
499*2d1272b8SAndroid Build Coastguard Worker     case 8: hb_barrier (); u.format8.collect_glyphs (glyphs); return;
500*2d1272b8SAndroid Build Coastguard Worker     case 10: hb_barrier (); u.format10.collect_glyphs (glyphs); return;
501*2d1272b8SAndroid Build Coastguard Worker     default:return;
502*2d1272b8SAndroid Build Coastguard Worker     }
503*2d1272b8SAndroid Build Coastguard Worker   }
504*2d1272b8SAndroid Build Coastguard Worker 
get_classAAT::Lookup505*2d1272b8SAndroid Build Coastguard Worker   typename T::type get_class (hb_codepoint_t glyph_id,
506*2d1272b8SAndroid Build Coastguard Worker 			      unsigned int num_glyphs,
507*2d1272b8SAndroid Build Coastguard Worker 			      unsigned int outOfRange) const
508*2d1272b8SAndroid Build Coastguard Worker   {
509*2d1272b8SAndroid Build Coastguard Worker     const T *v = get_value (glyph_id, num_glyphs);
510*2d1272b8SAndroid Build Coastguard Worker     return v ? *v : outOfRange;
511*2d1272b8SAndroid Build Coastguard Worker   }
512*2d1272b8SAndroid Build Coastguard Worker 
sanitizeAAT::Lookup513*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
514*2d1272b8SAndroid Build Coastguard Worker   {
515*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
516*2d1272b8SAndroid Build Coastguard Worker     if (!u.format.sanitize (c)) return_trace (false);
517*2d1272b8SAndroid Build Coastguard Worker     hb_barrier ();
518*2d1272b8SAndroid Build Coastguard Worker     switch (u.format) {
519*2d1272b8SAndroid Build Coastguard Worker     case 0: hb_barrier (); return_trace (u.format0.sanitize (c));
520*2d1272b8SAndroid Build Coastguard Worker     case 2: hb_barrier (); return_trace (u.format2.sanitize (c));
521*2d1272b8SAndroid Build Coastguard Worker     case 4: hb_barrier (); return_trace (u.format4.sanitize (c));
522*2d1272b8SAndroid Build Coastguard Worker     case 6: hb_barrier (); return_trace (u.format6.sanitize (c));
523*2d1272b8SAndroid Build Coastguard Worker     case 8: hb_barrier (); return_trace (u.format8.sanitize (c));
524*2d1272b8SAndroid Build Coastguard Worker     case 10: hb_barrier (); return_trace (u.format10.sanitize (c));
525*2d1272b8SAndroid Build Coastguard Worker     default:return_trace (true);
526*2d1272b8SAndroid Build Coastguard Worker     }
527*2d1272b8SAndroid Build Coastguard Worker   }
sanitizeAAT::Lookup528*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c, const void *base) const
529*2d1272b8SAndroid Build Coastguard Worker   {
530*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
531*2d1272b8SAndroid Build Coastguard Worker     if (!u.format.sanitize (c)) return_trace (false);
532*2d1272b8SAndroid Build Coastguard Worker     hb_barrier ();
533*2d1272b8SAndroid Build Coastguard Worker     switch (u.format) {
534*2d1272b8SAndroid Build Coastguard Worker     case 0: hb_barrier (); return_trace (u.format0.sanitize (c, base));
535*2d1272b8SAndroid Build Coastguard Worker     case 2: hb_barrier (); return_trace (u.format2.sanitize (c, base));
536*2d1272b8SAndroid Build Coastguard Worker     case 4: hb_barrier (); return_trace (u.format4.sanitize (c, base));
537*2d1272b8SAndroid Build Coastguard Worker     case 6: hb_barrier (); return_trace (u.format6.sanitize (c, base));
538*2d1272b8SAndroid Build Coastguard Worker     case 8: hb_barrier (); return_trace (u.format8.sanitize (c, base));
539*2d1272b8SAndroid Build Coastguard Worker     case 10: return_trace (false); /* We don't support format10 here currently. */
540*2d1272b8SAndroid Build Coastguard Worker     default:return_trace (true);
541*2d1272b8SAndroid Build Coastguard Worker     }
542*2d1272b8SAndroid Build Coastguard Worker   }
543*2d1272b8SAndroid Build Coastguard Worker 
544*2d1272b8SAndroid Build Coastguard Worker   protected:
545*2d1272b8SAndroid Build Coastguard Worker   union {
546*2d1272b8SAndroid Build Coastguard Worker   HBUINT16		format;		/* Format identifier */
547*2d1272b8SAndroid Build Coastguard Worker   LookupFormat0<T>	format0;
548*2d1272b8SAndroid Build Coastguard Worker   LookupFormat2<T>	format2;
549*2d1272b8SAndroid Build Coastguard Worker   LookupFormat4<T>	format4;
550*2d1272b8SAndroid Build Coastguard Worker   LookupFormat6<T>	format6;
551*2d1272b8SAndroid Build Coastguard Worker   LookupFormat8<T>	format8;
552*2d1272b8SAndroid Build Coastguard Worker   LookupFormat10<T>	format10;
553*2d1272b8SAndroid Build Coastguard Worker   } u;
554*2d1272b8SAndroid Build Coastguard Worker   public:
555*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_UNION (2, format);
556*2d1272b8SAndroid Build Coastguard Worker };
557*2d1272b8SAndroid Build Coastguard Worker DECLARE_NULL_NAMESPACE_BYTES_TEMPLATE1 (AAT, Lookup, 2);
558*2d1272b8SAndroid Build Coastguard Worker 
559*2d1272b8SAndroid Build Coastguard Worker /*
560*2d1272b8SAndroid Build Coastguard Worker  * (Extended) State Table
561*2d1272b8SAndroid Build Coastguard Worker  */
562*2d1272b8SAndroid Build Coastguard Worker 
563*2d1272b8SAndroid Build Coastguard Worker template <typename T>
564*2d1272b8SAndroid Build Coastguard Worker struct Entry
565*2d1272b8SAndroid Build Coastguard Worker {
566*2d1272b8SAndroid Build Coastguard Worker   // This does seem like it's ever called.
sanitizeAAT::Entry567*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
568*2d1272b8SAndroid Build Coastguard Worker   {
569*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
570*2d1272b8SAndroid Build Coastguard Worker     /* Note, we don't recurse-sanitize data because we don't access it.
571*2d1272b8SAndroid Build Coastguard Worker      * That said, in our DEFINE_SIZE_STATIC we access T::static_size,
572*2d1272b8SAndroid Build Coastguard Worker      * which ensures that data has a simple sanitize(). To be determined
573*2d1272b8SAndroid Build Coastguard Worker      * if I need to remove that as well.
574*2d1272b8SAndroid Build Coastguard Worker      *
575*2d1272b8SAndroid Build Coastguard Worker      * HOWEVER! Because we are a template, our DEFINE_SIZE_STATIC
576*2d1272b8SAndroid Build Coastguard Worker      * assertion wouldn't be checked, hence the line below. */
577*2d1272b8SAndroid Build Coastguard Worker     static_assert (T::static_size, "");
578*2d1272b8SAndroid Build Coastguard Worker 
579*2d1272b8SAndroid Build Coastguard Worker     return_trace (c->check_struct (this));
580*2d1272b8SAndroid Build Coastguard Worker   }
581*2d1272b8SAndroid Build Coastguard Worker 
582*2d1272b8SAndroid Build Coastguard Worker   public:
583*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	newState;	/* Byte offset from beginning of state table
584*2d1272b8SAndroid Build Coastguard Worker 				 * to the new state. Really?!?! Or just state
585*2d1272b8SAndroid Build Coastguard Worker 				 * number?  The latter in morx for sure. */
586*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	flags;		/* Table specific. */
587*2d1272b8SAndroid Build Coastguard Worker   T		data;		/* Optional offsets to per-glyph tables. */
588*2d1272b8SAndroid Build Coastguard Worker   public:
589*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_STATIC (4 + T::static_size);
590*2d1272b8SAndroid Build Coastguard Worker };
591*2d1272b8SAndroid Build Coastguard Worker 
592*2d1272b8SAndroid Build Coastguard Worker template <>
593*2d1272b8SAndroid Build Coastguard Worker struct Entry<void>
594*2d1272b8SAndroid Build Coastguard Worker {
595*2d1272b8SAndroid Build Coastguard Worker   // This does seem like it's ever called.
sanitizeAAT::Entry596*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
597*2d1272b8SAndroid Build Coastguard Worker   {
598*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
599*2d1272b8SAndroid Build Coastguard Worker     return_trace (c->check_struct (this));
600*2d1272b8SAndroid Build Coastguard Worker   }
601*2d1272b8SAndroid Build Coastguard Worker 
602*2d1272b8SAndroid Build Coastguard Worker   public:
603*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	newState;	/* Byte offset from beginning of state table to the new state. */
604*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	flags;		/* Table specific. */
605*2d1272b8SAndroid Build Coastguard Worker   public:
606*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_STATIC (4);
607*2d1272b8SAndroid Build Coastguard Worker };
608*2d1272b8SAndroid Build Coastguard Worker 
609*2d1272b8SAndroid Build Coastguard Worker enum Class
610*2d1272b8SAndroid Build Coastguard Worker {
611*2d1272b8SAndroid Build Coastguard Worker   CLASS_END_OF_TEXT = 0,
612*2d1272b8SAndroid Build Coastguard Worker   CLASS_OUT_OF_BOUNDS = 1,
613*2d1272b8SAndroid Build Coastguard Worker   CLASS_DELETED_GLYPH = 2,
614*2d1272b8SAndroid Build Coastguard Worker   CLASS_END_OF_LINE = 3,
615*2d1272b8SAndroid Build Coastguard Worker };
616*2d1272b8SAndroid Build Coastguard Worker 
617*2d1272b8SAndroid Build Coastguard Worker template <typename Types, typename Extra>
618*2d1272b8SAndroid Build Coastguard Worker struct StateTable
619*2d1272b8SAndroid Build Coastguard Worker {
620*2d1272b8SAndroid Build Coastguard Worker   typedef typename Types::HBUINT HBUINT;
621*2d1272b8SAndroid Build Coastguard Worker   typedef typename Types::HBUSHORT HBUSHORT;
622*2d1272b8SAndroid Build Coastguard Worker   typedef typename Types::ClassTypeNarrow ClassType;
623*2d1272b8SAndroid Build Coastguard Worker 
624*2d1272b8SAndroid Build Coastguard Worker   enum State
625*2d1272b8SAndroid Build Coastguard Worker   {
626*2d1272b8SAndroid Build Coastguard Worker     STATE_START_OF_TEXT = 0,
627*2d1272b8SAndroid Build Coastguard Worker     STATE_START_OF_LINE = 1,
628*2d1272b8SAndroid Build Coastguard Worker   };
629*2d1272b8SAndroid Build Coastguard Worker 
630*2d1272b8SAndroid Build Coastguard Worker   template <typename set_t>
collect_glyphsAAT::StateTable631*2d1272b8SAndroid Build Coastguard Worker   void collect_glyphs (set_t &glyphs, unsigned num_glyphs) const
632*2d1272b8SAndroid Build Coastguard Worker   {
633*2d1272b8SAndroid Build Coastguard Worker     (this+classTable).collect_glyphs (glyphs, num_glyphs);
634*2d1272b8SAndroid Build Coastguard Worker   }
635*2d1272b8SAndroid Build Coastguard Worker 
new_stateAAT::StateTable636*2d1272b8SAndroid Build Coastguard Worker   int new_state (unsigned int newState) const
637*2d1272b8SAndroid Build Coastguard Worker   { return Types::extended ? newState : ((int) newState - (int) stateArrayTable) / (int) nClasses; }
638*2d1272b8SAndroid Build Coastguard Worker 
639*2d1272b8SAndroid Build Coastguard Worker   template <typename set_t>
get_classAAT::StateTable640*2d1272b8SAndroid Build Coastguard Worker   unsigned int get_class (hb_codepoint_t glyph_id,
641*2d1272b8SAndroid Build Coastguard Worker 			  unsigned int num_glyphs,
642*2d1272b8SAndroid Build Coastguard Worker 			  const set_t &glyphs) const
643*2d1272b8SAndroid Build Coastguard Worker   {
644*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (glyph_id == DELETED_GLYPH)) return CLASS_DELETED_GLYPH;
645*2d1272b8SAndroid Build Coastguard Worker     if (!glyphs[glyph_id]) return CLASS_OUT_OF_BOUNDS;
646*2d1272b8SAndroid Build Coastguard Worker     return (this+classTable).get_class (glyph_id, num_glyphs, CLASS_OUT_OF_BOUNDS);
647*2d1272b8SAndroid Build Coastguard Worker   }
648*2d1272b8SAndroid Build Coastguard Worker 
get_entriesAAT::StateTable649*2d1272b8SAndroid Build Coastguard Worker   const Entry<Extra> *get_entries () const
650*2d1272b8SAndroid Build Coastguard Worker   { return (this+entryTable).arrayZ; }
651*2d1272b8SAndroid Build Coastguard Worker 
get_entryAAT::StateTable652*2d1272b8SAndroid Build Coastguard Worker   const Entry<Extra> &get_entry (int state, unsigned int klass) const
653*2d1272b8SAndroid Build Coastguard Worker   {
654*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (klass >= nClasses))
655*2d1272b8SAndroid Build Coastguard Worker       klass = CLASS_OUT_OF_BOUNDS;
656*2d1272b8SAndroid Build Coastguard Worker 
657*2d1272b8SAndroid Build Coastguard Worker     const HBUSHORT *states = (this+stateArrayTable).arrayZ;
658*2d1272b8SAndroid Build Coastguard Worker     const Entry<Extra> *entries = (this+entryTable).arrayZ;
659*2d1272b8SAndroid Build Coastguard Worker 
660*2d1272b8SAndroid Build Coastguard Worker     unsigned int entry = states[state * nClasses + klass];
661*2d1272b8SAndroid Build Coastguard Worker     DEBUG_MSG (APPLY, nullptr, "e%u", entry);
662*2d1272b8SAndroid Build Coastguard Worker 
663*2d1272b8SAndroid Build Coastguard Worker     return entries[entry];
664*2d1272b8SAndroid Build Coastguard Worker   }
665*2d1272b8SAndroid Build Coastguard Worker 
sanitizeAAT::StateTable666*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c,
667*2d1272b8SAndroid Build Coastguard Worker 		 unsigned int *num_entries_out = nullptr) const
668*2d1272b8SAndroid Build Coastguard Worker   {
669*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
670*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!(c->check_struct (this) &&
671*2d1272b8SAndroid Build Coastguard Worker 		    hb_barrier () &&
672*2d1272b8SAndroid Build Coastguard Worker 		    nClasses >= 4 /* Ensure pre-defined classes fit.  */ &&
673*2d1272b8SAndroid Build Coastguard Worker 		    classTable.sanitize (c, this)))) return_trace (false);
674*2d1272b8SAndroid Build Coastguard Worker 
675*2d1272b8SAndroid Build Coastguard Worker     const HBUSHORT *states = (this+stateArrayTable).arrayZ;
676*2d1272b8SAndroid Build Coastguard Worker     const Entry<Extra> *entries = (this+entryTable).arrayZ;
677*2d1272b8SAndroid Build Coastguard Worker 
678*2d1272b8SAndroid Build Coastguard Worker     unsigned int num_classes = nClasses;
679*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (hb_unsigned_mul_overflows (num_classes, states[0].static_size)))
680*2d1272b8SAndroid Build Coastguard Worker       return_trace (false);
681*2d1272b8SAndroid Build Coastguard Worker     unsigned int row_stride = num_classes * states[0].static_size;
682*2d1272b8SAndroid Build Coastguard Worker 
683*2d1272b8SAndroid Build Coastguard Worker     /* Apple 'kern' table has this peculiarity:
684*2d1272b8SAndroid Build Coastguard Worker      *
685*2d1272b8SAndroid Build Coastguard Worker      * "Because the stateTableOffset in the state table header is (strictly
686*2d1272b8SAndroid Build Coastguard Worker      * speaking) redundant, some 'kern' tables use it to record an initial
687*2d1272b8SAndroid Build Coastguard Worker      * state where that should not be StartOfText. To determine if this is
688*2d1272b8SAndroid Build Coastguard Worker      * done, calculate what the stateTableOffset should be. If it's different
689*2d1272b8SAndroid Build Coastguard Worker      * from the actual stateTableOffset, use it as the initial state."
690*2d1272b8SAndroid Build Coastguard Worker      *
691*2d1272b8SAndroid Build Coastguard Worker      * We implement this by calling the initial state zero, but allow *negative*
692*2d1272b8SAndroid Build Coastguard Worker      * states if the start state indeed was not the first state.  Since the code
693*2d1272b8SAndroid Build Coastguard Worker      * is shared, this will also apply to 'mort' table.  The 'kerx' / 'morx'
694*2d1272b8SAndroid Build Coastguard Worker      * tables are not affected since those address states by index, not offset.
695*2d1272b8SAndroid Build Coastguard Worker      */
696*2d1272b8SAndroid Build Coastguard Worker 
697*2d1272b8SAndroid Build Coastguard Worker     int min_state = 0;
698*2d1272b8SAndroid Build Coastguard Worker     int max_state = 0;
699*2d1272b8SAndroid Build Coastguard Worker     unsigned int num_entries = 0;
700*2d1272b8SAndroid Build Coastguard Worker 
701*2d1272b8SAndroid Build Coastguard Worker     int state_pos = 0;
702*2d1272b8SAndroid Build Coastguard Worker     int state_neg = 0;
703*2d1272b8SAndroid Build Coastguard Worker     unsigned int entry = 0;
704*2d1272b8SAndroid Build Coastguard Worker     while (min_state < state_neg || state_pos <= max_state)
705*2d1272b8SAndroid Build Coastguard Worker     {
706*2d1272b8SAndroid Build Coastguard Worker       if (min_state < state_neg)
707*2d1272b8SAndroid Build Coastguard Worker       {
708*2d1272b8SAndroid Build Coastguard Worker 	/* Negative states. */
709*2d1272b8SAndroid Build Coastguard Worker 	if (unlikely (hb_unsigned_mul_overflows (min_state, num_classes)))
710*2d1272b8SAndroid Build Coastguard Worker 	  return_trace (false);
711*2d1272b8SAndroid Build Coastguard Worker 	if (unlikely (!c->check_range (&states[min_state * num_classes],
712*2d1272b8SAndroid Build Coastguard Worker 				       -min_state,
713*2d1272b8SAndroid Build Coastguard Worker 				       row_stride)))
714*2d1272b8SAndroid Build Coastguard Worker 	  return_trace (false);
715*2d1272b8SAndroid Build Coastguard Worker 	if ((c->max_ops -= state_neg - min_state) <= 0)
716*2d1272b8SAndroid Build Coastguard Worker 	  return_trace (false);
717*2d1272b8SAndroid Build Coastguard Worker 	{ /* Sweep new states. */
718*2d1272b8SAndroid Build Coastguard Worker 	  const HBUSHORT *stop = &states[min_state * num_classes];
719*2d1272b8SAndroid Build Coastguard Worker 	  if (unlikely (stop > states))
720*2d1272b8SAndroid Build Coastguard Worker 	    return_trace (false);
721*2d1272b8SAndroid Build Coastguard Worker 	  for (const HBUSHORT *p = states; stop < p; p--)
722*2d1272b8SAndroid Build Coastguard Worker 	    num_entries = hb_max (num_entries, *(p - 1) + 1u);
723*2d1272b8SAndroid Build Coastguard Worker 	  state_neg = min_state;
724*2d1272b8SAndroid Build Coastguard Worker 	}
725*2d1272b8SAndroid Build Coastguard Worker       }
726*2d1272b8SAndroid Build Coastguard Worker 
727*2d1272b8SAndroid Build Coastguard Worker       if (state_pos <= max_state)
728*2d1272b8SAndroid Build Coastguard Worker       {
729*2d1272b8SAndroid Build Coastguard Worker 	/* Positive states. */
730*2d1272b8SAndroid Build Coastguard Worker 	if (unlikely (!c->check_range (states,
731*2d1272b8SAndroid Build Coastguard Worker 				       max_state + 1,
732*2d1272b8SAndroid Build Coastguard Worker 				       row_stride)))
733*2d1272b8SAndroid Build Coastguard Worker 	  return_trace (false);
734*2d1272b8SAndroid Build Coastguard Worker 	if ((c->max_ops -= max_state - state_pos + 1) <= 0)
735*2d1272b8SAndroid Build Coastguard Worker 	  return_trace (false);
736*2d1272b8SAndroid Build Coastguard Worker 	{ /* Sweep new states. */
737*2d1272b8SAndroid Build Coastguard Worker 	  if (unlikely (hb_unsigned_mul_overflows ((max_state + 1), num_classes)))
738*2d1272b8SAndroid Build Coastguard Worker 	    return_trace (false);
739*2d1272b8SAndroid Build Coastguard Worker 	  const HBUSHORT *stop = &states[(max_state + 1) * num_classes];
740*2d1272b8SAndroid Build Coastguard Worker 	  if (unlikely (stop < states))
741*2d1272b8SAndroid Build Coastguard Worker 	    return_trace (false);
742*2d1272b8SAndroid Build Coastguard Worker 	  for (const HBUSHORT *p = &states[state_pos * num_classes]; p < stop; p++)
743*2d1272b8SAndroid Build Coastguard Worker 	    num_entries = hb_max (num_entries, *p + 1u);
744*2d1272b8SAndroid Build Coastguard Worker 	  state_pos = max_state + 1;
745*2d1272b8SAndroid Build Coastguard Worker 	}
746*2d1272b8SAndroid Build Coastguard Worker       }
747*2d1272b8SAndroid Build Coastguard Worker 
748*2d1272b8SAndroid Build Coastguard Worker       if (unlikely (!c->check_array (entries, num_entries)))
749*2d1272b8SAndroid Build Coastguard Worker 	return_trace (false);
750*2d1272b8SAndroid Build Coastguard Worker       if ((c->max_ops -= num_entries - entry) <= 0)
751*2d1272b8SAndroid Build Coastguard Worker 	return_trace (false);
752*2d1272b8SAndroid Build Coastguard Worker       { /* Sweep new entries. */
753*2d1272b8SAndroid Build Coastguard Worker 	const Entry<Extra> *stop = &entries[num_entries];
754*2d1272b8SAndroid Build Coastguard Worker 	for (const Entry<Extra> *p = &entries[entry]; p < stop; p++)
755*2d1272b8SAndroid Build Coastguard Worker 	{
756*2d1272b8SAndroid Build Coastguard Worker 	  int newState = new_state (p->newState);
757*2d1272b8SAndroid Build Coastguard Worker 	  min_state = hb_min (min_state, newState);
758*2d1272b8SAndroid Build Coastguard Worker 	  max_state = hb_max (max_state, newState);
759*2d1272b8SAndroid Build Coastguard Worker 	}
760*2d1272b8SAndroid Build Coastguard Worker 	entry = num_entries;
761*2d1272b8SAndroid Build Coastguard Worker       }
762*2d1272b8SAndroid Build Coastguard Worker     }
763*2d1272b8SAndroid Build Coastguard Worker 
764*2d1272b8SAndroid Build Coastguard Worker     if (num_entries_out)
765*2d1272b8SAndroid Build Coastguard Worker       *num_entries_out = num_entries;
766*2d1272b8SAndroid Build Coastguard Worker 
767*2d1272b8SAndroid Build Coastguard Worker     return_trace (true);
768*2d1272b8SAndroid Build Coastguard Worker   }
769*2d1272b8SAndroid Build Coastguard Worker 
770*2d1272b8SAndroid Build Coastguard Worker   protected:
771*2d1272b8SAndroid Build Coastguard Worker   HBUINT	nClasses;	/* Number of classes, which is the number of indices
772*2d1272b8SAndroid Build Coastguard Worker 				 * in a single line in the state array. */
773*2d1272b8SAndroid Build Coastguard Worker   NNOffsetTo<ClassType, HBUINT>
774*2d1272b8SAndroid Build Coastguard Worker 		classTable;	/* Offset to the class table. */
775*2d1272b8SAndroid Build Coastguard Worker   NNOffsetTo<UnsizedArrayOf<HBUSHORT>, HBUINT>
776*2d1272b8SAndroid Build Coastguard Worker 		stateArrayTable;/* Offset to the state array. */
777*2d1272b8SAndroid Build Coastguard Worker   NNOffsetTo<UnsizedArrayOf<Entry<Extra>>, HBUINT>
778*2d1272b8SAndroid Build Coastguard Worker 		entryTable;	/* Offset to the entry array. */
779*2d1272b8SAndroid Build Coastguard Worker 
780*2d1272b8SAndroid Build Coastguard Worker   public:
781*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_STATIC (4 * sizeof (HBUINT));
782*2d1272b8SAndroid Build Coastguard Worker };
783*2d1272b8SAndroid Build Coastguard Worker 
784*2d1272b8SAndroid Build Coastguard Worker template <typename HBUCHAR>
785*2d1272b8SAndroid Build Coastguard Worker struct ClassTable
786*2d1272b8SAndroid Build Coastguard Worker {
get_classAAT::ClassTable787*2d1272b8SAndroid Build Coastguard Worker   unsigned int get_class (hb_codepoint_t glyph_id, unsigned int outOfRange) const
788*2d1272b8SAndroid Build Coastguard Worker   {
789*2d1272b8SAndroid Build Coastguard Worker     unsigned int i = glyph_id - firstGlyph;
790*2d1272b8SAndroid Build Coastguard Worker     return i >= classArray.len ? outOfRange : classArray.arrayZ[i];
791*2d1272b8SAndroid Build Coastguard Worker   }
get_classAAT::ClassTable792*2d1272b8SAndroid Build Coastguard Worker   unsigned int get_class (hb_codepoint_t glyph_id,
793*2d1272b8SAndroid Build Coastguard Worker 			  unsigned int num_glyphs HB_UNUSED,
794*2d1272b8SAndroid Build Coastguard Worker 			  unsigned int outOfRange) const
795*2d1272b8SAndroid Build Coastguard Worker   {
796*2d1272b8SAndroid Build Coastguard Worker     return get_class (glyph_id, outOfRange);
797*2d1272b8SAndroid Build Coastguard Worker   }
798*2d1272b8SAndroid Build Coastguard Worker 
799*2d1272b8SAndroid Build Coastguard Worker   template <typename set_t>
collect_glyphsAAT::ClassTable800*2d1272b8SAndroid Build Coastguard Worker   void collect_glyphs (set_t &glyphs, unsigned num_glyphs) const
801*2d1272b8SAndroid Build Coastguard Worker   {
802*2d1272b8SAndroid Build Coastguard Worker     for (unsigned i = 0; i < classArray.len; i++)
803*2d1272b8SAndroid Build Coastguard Worker       if (classArray.arrayZ[i] != CLASS_OUT_OF_BOUNDS)
804*2d1272b8SAndroid Build Coastguard Worker 	glyphs.add (firstGlyph + i);
805*2d1272b8SAndroid Build Coastguard Worker   }
806*2d1272b8SAndroid Build Coastguard Worker 
sanitizeAAT::ClassTable807*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
808*2d1272b8SAndroid Build Coastguard Worker   {
809*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
810*2d1272b8SAndroid Build Coastguard Worker     return_trace (c->check_struct (this) && classArray.sanitize (c));
811*2d1272b8SAndroid Build Coastguard Worker   }
812*2d1272b8SAndroid Build Coastguard Worker   protected:
813*2d1272b8SAndroid Build Coastguard Worker   HBGlyphID16		firstGlyph;	/* First glyph index included in the trimmed array. */
814*2d1272b8SAndroid Build Coastguard Worker   Array16Of<HBUCHAR>	classArray;	/* The class codes (indexed by glyph index minus
815*2d1272b8SAndroid Build Coastguard Worker 					 * firstGlyph). */
816*2d1272b8SAndroid Build Coastguard Worker   public:
817*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_ARRAY (4, classArray);
818*2d1272b8SAndroid Build Coastguard Worker };
819*2d1272b8SAndroid Build Coastguard Worker 
820*2d1272b8SAndroid Build Coastguard Worker struct SubtableGlyphCoverage
821*2d1272b8SAndroid Build Coastguard Worker {
sanitizeAAT::SubtableGlyphCoverage822*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c, unsigned subtable_count) const
823*2d1272b8SAndroid Build Coastguard Worker   {
824*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
825*2d1272b8SAndroid Build Coastguard Worker 
826*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!c->check_array (&subtableOffsets, subtable_count)))
827*2d1272b8SAndroid Build Coastguard Worker       return_trace (false);
828*2d1272b8SAndroid Build Coastguard Worker 
829*2d1272b8SAndroid Build Coastguard Worker     unsigned bytes = (c->get_num_glyphs () + CHAR_BIT - 1) / CHAR_BIT;
830*2d1272b8SAndroid Build Coastguard Worker     for (unsigned i = 0; i < subtable_count; i++)
831*2d1272b8SAndroid Build Coastguard Worker     {
832*2d1272b8SAndroid Build Coastguard Worker       uint32_t offset = (uint32_t) subtableOffsets[i];
833*2d1272b8SAndroid Build Coastguard Worker       if (offset == 0 || offset == 0xFFFFFFFF)
834*2d1272b8SAndroid Build Coastguard Worker         continue;
835*2d1272b8SAndroid Build Coastguard Worker       if (unlikely (!subtableOffsets[i].sanitize (c, this, bytes)))
836*2d1272b8SAndroid Build Coastguard Worker         return_trace (false);
837*2d1272b8SAndroid Build Coastguard Worker     }
838*2d1272b8SAndroid Build Coastguard Worker 
839*2d1272b8SAndroid Build Coastguard Worker     return_trace (true);
840*2d1272b8SAndroid Build Coastguard Worker   }
841*2d1272b8SAndroid Build Coastguard Worker   protected:
842*2d1272b8SAndroid Build Coastguard Worker   UnsizedArrayOf<NNOffset32To<UnsizedArrayOf<HBUINT8>>> subtableOffsets;
843*2d1272b8SAndroid Build Coastguard Worker 					    /* Array of offsets from the beginning of the
844*2d1272b8SAndroid Build Coastguard Worker 					     * subtable glyph coverage table to the glyph
845*2d1272b8SAndroid Build Coastguard Worker 					     * coverage bitfield for a given subtable; there
846*2d1272b8SAndroid Build Coastguard Worker 					     * is one offset for each subtable in the chain */
847*2d1272b8SAndroid Build Coastguard Worker   /* UnsizedArrayOf<HBUINT8> coverageBitfields; *//* The individual coverage bitfields. */
848*2d1272b8SAndroid Build Coastguard Worker   public:
849*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_ARRAY (0, subtableOffsets);
850*2d1272b8SAndroid Build Coastguard Worker };
851*2d1272b8SAndroid Build Coastguard Worker 
852*2d1272b8SAndroid Build Coastguard Worker struct ObsoleteTypes
853*2d1272b8SAndroid Build Coastguard Worker {
854*2d1272b8SAndroid Build Coastguard Worker   static constexpr bool extended = false;
855*2d1272b8SAndroid Build Coastguard Worker   typedef HBUINT16 HBUINT;
856*2d1272b8SAndroid Build Coastguard Worker   typedef HBUINT8 HBUSHORT;
857*2d1272b8SAndroid Build Coastguard Worker   typedef ClassTable<HBUINT8> ClassTypeNarrow;
858*2d1272b8SAndroid Build Coastguard Worker   typedef ClassTable<HBUINT16> ClassTypeWide;
859*2d1272b8SAndroid Build Coastguard Worker 
860*2d1272b8SAndroid Build Coastguard Worker   template <typename T>
offsetToIndexAAT::ObsoleteTypes861*2d1272b8SAndroid Build Coastguard Worker   static unsigned int offsetToIndex (unsigned int offset,
862*2d1272b8SAndroid Build Coastguard Worker 				     const void *base,
863*2d1272b8SAndroid Build Coastguard Worker 				     const T *array)
864*2d1272b8SAndroid Build Coastguard Worker   {
865*2d1272b8SAndroid Build Coastguard Worker     /* https://github.com/harfbuzz/harfbuzz/issues/3483 */
866*2d1272b8SAndroid Build Coastguard Worker     /* If offset is less than base, return an offset that would
867*2d1272b8SAndroid Build Coastguard Worker      * result in an address half a 32bit address-space away,
868*2d1272b8SAndroid Build Coastguard Worker      * to make sure sanitize fails even on 32bit builds. */
869*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (offset < unsigned ((const char *) array - (const char *) base)))
870*2d1272b8SAndroid Build Coastguard Worker       return INT_MAX / T::static_size;
871*2d1272b8SAndroid Build Coastguard Worker 
872*2d1272b8SAndroid Build Coastguard Worker     /* https://github.com/harfbuzz/harfbuzz/issues/2816 */
873*2d1272b8SAndroid Build Coastguard Worker     return (offset - unsigned ((const char *) array - (const char *) base)) / T::static_size;
874*2d1272b8SAndroid Build Coastguard Worker   }
875*2d1272b8SAndroid Build Coastguard Worker   template <typename T>
byteOffsetToIndexAAT::ObsoleteTypes876*2d1272b8SAndroid Build Coastguard Worker   static unsigned int byteOffsetToIndex (unsigned int offset,
877*2d1272b8SAndroid Build Coastguard Worker 					 const void *base,
878*2d1272b8SAndroid Build Coastguard Worker 					 const T *array)
879*2d1272b8SAndroid Build Coastguard Worker   {
880*2d1272b8SAndroid Build Coastguard Worker     return offsetToIndex (offset, base, array);
881*2d1272b8SAndroid Build Coastguard Worker   }
882*2d1272b8SAndroid Build Coastguard Worker   template <typename T>
wordOffsetToIndexAAT::ObsoleteTypes883*2d1272b8SAndroid Build Coastguard Worker   static unsigned int wordOffsetToIndex (unsigned int offset,
884*2d1272b8SAndroid Build Coastguard Worker 					 const void *base,
885*2d1272b8SAndroid Build Coastguard Worker 					 const T *array)
886*2d1272b8SAndroid Build Coastguard Worker   {
887*2d1272b8SAndroid Build Coastguard Worker     return offsetToIndex (2 * offset, base, array);
888*2d1272b8SAndroid Build Coastguard Worker   }
889*2d1272b8SAndroid Build Coastguard Worker };
890*2d1272b8SAndroid Build Coastguard Worker struct ExtendedTypes
891*2d1272b8SAndroid Build Coastguard Worker {
892*2d1272b8SAndroid Build Coastguard Worker   static constexpr bool extended = true;
893*2d1272b8SAndroid Build Coastguard Worker   typedef HBUINT32 HBUINT;
894*2d1272b8SAndroid Build Coastguard Worker   typedef HBUINT16 HBUSHORT;
895*2d1272b8SAndroid Build Coastguard Worker   typedef Lookup<HBUINT16> ClassTypeNarrow;
896*2d1272b8SAndroid Build Coastguard Worker   typedef Lookup<HBUINT16> ClassTypeWide;
897*2d1272b8SAndroid Build Coastguard Worker 
898*2d1272b8SAndroid Build Coastguard Worker   template <typename T>
offsetToIndexAAT::ExtendedTypes899*2d1272b8SAndroid Build Coastguard Worker   static unsigned int offsetToIndex (unsigned int offset,
900*2d1272b8SAndroid Build Coastguard Worker 				     const void *base HB_UNUSED,
901*2d1272b8SAndroid Build Coastguard Worker 				     const T *array HB_UNUSED)
902*2d1272b8SAndroid Build Coastguard Worker   {
903*2d1272b8SAndroid Build Coastguard Worker     return offset;
904*2d1272b8SAndroid Build Coastguard Worker   }
905*2d1272b8SAndroid Build Coastguard Worker   template <typename T>
byteOffsetToIndexAAT::ExtendedTypes906*2d1272b8SAndroid Build Coastguard Worker   static unsigned int byteOffsetToIndex (unsigned int offset,
907*2d1272b8SAndroid Build Coastguard Worker 					 const void *base HB_UNUSED,
908*2d1272b8SAndroid Build Coastguard Worker 					 const T *array HB_UNUSED)
909*2d1272b8SAndroid Build Coastguard Worker   {
910*2d1272b8SAndroid Build Coastguard Worker     return offset / 2;
911*2d1272b8SAndroid Build Coastguard Worker   }
912*2d1272b8SAndroid Build Coastguard Worker   template <typename T>
wordOffsetToIndexAAT::ExtendedTypes913*2d1272b8SAndroid Build Coastguard Worker   static unsigned int wordOffsetToIndex (unsigned int offset,
914*2d1272b8SAndroid Build Coastguard Worker 					 const void *base HB_UNUSED,
915*2d1272b8SAndroid Build Coastguard Worker 					 const T *array HB_UNUSED)
916*2d1272b8SAndroid Build Coastguard Worker   {
917*2d1272b8SAndroid Build Coastguard Worker     return offset;
918*2d1272b8SAndroid Build Coastguard Worker   }
919*2d1272b8SAndroid Build Coastguard Worker };
920*2d1272b8SAndroid Build Coastguard Worker 
921*2d1272b8SAndroid Build Coastguard Worker template <typename Types, typename EntryData>
922*2d1272b8SAndroid Build Coastguard Worker struct StateTableDriver
923*2d1272b8SAndroid Build Coastguard Worker {
924*2d1272b8SAndroid Build Coastguard Worker   using StateTableT = StateTable<Types, EntryData>;
925*2d1272b8SAndroid Build Coastguard Worker   using EntryT = Entry<EntryData>;
926*2d1272b8SAndroid Build Coastguard Worker 
StateTableDriverAAT::StateTableDriver927*2d1272b8SAndroid Build Coastguard Worker   StateTableDriver (const StateTableT &machine_,
928*2d1272b8SAndroid Build Coastguard Worker 		    hb_face_t *face_) :
929*2d1272b8SAndroid Build Coastguard Worker 	      machine (machine_),
930*2d1272b8SAndroid Build Coastguard Worker 	      num_glyphs (face_->get_num_glyphs ()) {}
931*2d1272b8SAndroid Build Coastguard Worker 
932*2d1272b8SAndroid Build Coastguard Worker   template <typename context_t>
is_idempotent_on_all_out_of_boundsAAT::StateTableDriver933*2d1272b8SAndroid Build Coastguard Worker   bool is_idempotent_on_all_out_of_bounds (context_t *c, hb_aat_apply_context_t *ac)
934*2d1272b8SAndroid Build Coastguard Worker   {
935*2d1272b8SAndroid Build Coastguard Worker     const auto entry = machine.get_entry (StateTableT::STATE_START_OF_TEXT, CLASS_OUT_OF_BOUNDS);
936*2d1272b8SAndroid Build Coastguard Worker     return !c->is_actionable (ac->buffer, this, entry) &&
937*2d1272b8SAndroid Build Coastguard Worker 	    machine.new_state (entry.newState) == StateTableT::STATE_START_OF_TEXT;
938*2d1272b8SAndroid Build Coastguard Worker   }
939*2d1272b8SAndroid Build Coastguard Worker 
940*2d1272b8SAndroid Build Coastguard Worker   template <typename context_t>
driveAAT::StateTableDriver941*2d1272b8SAndroid Build Coastguard Worker   void drive (context_t *c, hb_aat_apply_context_t *ac)
942*2d1272b8SAndroid Build Coastguard Worker   {
943*2d1272b8SAndroid Build Coastguard Worker     hb_buffer_t *buffer = ac->buffer;
944*2d1272b8SAndroid Build Coastguard Worker 
945*2d1272b8SAndroid Build Coastguard Worker     if (!c->in_place)
946*2d1272b8SAndroid Build Coastguard Worker       buffer->clear_output ();
947*2d1272b8SAndroid Build Coastguard Worker 
948*2d1272b8SAndroid Build Coastguard Worker     int state = StateTableT::STATE_START_OF_TEXT;
949*2d1272b8SAndroid Build Coastguard Worker     // If there's only one range, we already checked the flag.
950*2d1272b8SAndroid Build Coastguard Worker     auto *last_range = ac->range_flags && (ac->range_flags->length > 1) ? &(*ac->range_flags)[0] : nullptr;
951*2d1272b8SAndroid Build Coastguard Worker     for (buffer->idx = 0; buffer->successful;)
952*2d1272b8SAndroid Build Coastguard Worker     {
953*2d1272b8SAndroid Build Coastguard Worker       /* This block is copied in NoncontextualSubtable::apply. Keep in sync. */
954*2d1272b8SAndroid Build Coastguard Worker       if (last_range)
955*2d1272b8SAndroid Build Coastguard Worker       {
956*2d1272b8SAndroid Build Coastguard Worker 	auto *range = last_range;
957*2d1272b8SAndroid Build Coastguard Worker 	if (buffer->idx < buffer->len)
958*2d1272b8SAndroid Build Coastguard Worker 	{
959*2d1272b8SAndroid Build Coastguard Worker 	  unsigned cluster = buffer->cur().cluster;
960*2d1272b8SAndroid Build Coastguard Worker 	  while (cluster < range->cluster_first)
961*2d1272b8SAndroid Build Coastguard Worker 	    range--;
962*2d1272b8SAndroid Build Coastguard Worker 	  while (cluster > range->cluster_last)
963*2d1272b8SAndroid Build Coastguard Worker 	    range++;
964*2d1272b8SAndroid Build Coastguard Worker 
965*2d1272b8SAndroid Build Coastguard Worker 
966*2d1272b8SAndroid Build Coastguard Worker 	  last_range = range;
967*2d1272b8SAndroid Build Coastguard Worker 	}
968*2d1272b8SAndroid Build Coastguard Worker 	if (!(range->flags & ac->subtable_flags))
969*2d1272b8SAndroid Build Coastguard Worker 	{
970*2d1272b8SAndroid Build Coastguard Worker 	  if (buffer->idx == buffer->len || unlikely (!buffer->successful))
971*2d1272b8SAndroid Build Coastguard Worker 	    break;
972*2d1272b8SAndroid Build Coastguard Worker 
973*2d1272b8SAndroid Build Coastguard Worker 	  state = StateTableT::STATE_START_OF_TEXT;
974*2d1272b8SAndroid Build Coastguard Worker 	  (void) buffer->next_glyph ();
975*2d1272b8SAndroid Build Coastguard Worker 	  continue;
976*2d1272b8SAndroid Build Coastguard Worker 	}
977*2d1272b8SAndroid Build Coastguard Worker       }
978*2d1272b8SAndroid Build Coastguard Worker 
979*2d1272b8SAndroid Build Coastguard Worker       unsigned int klass = likely (buffer->idx < buffer->len) ?
980*2d1272b8SAndroid Build Coastguard Worker 			   machine.get_class (buffer->cur().codepoint, num_glyphs, ac->machine_glyph_set) :
981*2d1272b8SAndroid Build Coastguard Worker 			   (unsigned) CLASS_END_OF_TEXT;
982*2d1272b8SAndroid Build Coastguard Worker       DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx);
983*2d1272b8SAndroid Build Coastguard Worker       const EntryT &entry = machine.get_entry (state, klass);
984*2d1272b8SAndroid Build Coastguard Worker       const int next_state = machine.new_state (entry.newState);
985*2d1272b8SAndroid Build Coastguard Worker 
986*2d1272b8SAndroid Build Coastguard Worker       /* Conditions under which it's guaranteed safe-to-break before current glyph:
987*2d1272b8SAndroid Build Coastguard Worker        *
988*2d1272b8SAndroid Build Coastguard Worker        * 1. There was no action in this transition; and
989*2d1272b8SAndroid Build Coastguard Worker        *
990*2d1272b8SAndroid Build Coastguard Worker        * 2. If we break before current glyph, the results will be the same. That
991*2d1272b8SAndroid Build Coastguard Worker        *    is guaranteed if:
992*2d1272b8SAndroid Build Coastguard Worker        *
993*2d1272b8SAndroid Build Coastguard Worker        *    2a. We were already in start-of-text state; or
994*2d1272b8SAndroid Build Coastguard Worker        *
995*2d1272b8SAndroid Build Coastguard Worker        *    2b. We are epsilon-transitioning to start-of-text state; or
996*2d1272b8SAndroid Build Coastguard Worker        *
997*2d1272b8SAndroid Build Coastguard Worker        *    2c. Starting from start-of-text state seeing current glyph:
998*2d1272b8SAndroid Build Coastguard Worker        *
999*2d1272b8SAndroid Build Coastguard Worker        *        2c'. There won't be any actions; and
1000*2d1272b8SAndroid Build Coastguard Worker        *
1001*2d1272b8SAndroid Build Coastguard Worker        *        2c". We would end up in the same state that we were going to end up
1002*2d1272b8SAndroid Build Coastguard Worker        *             in now, including whether epsilon-transitioning.
1003*2d1272b8SAndroid Build Coastguard Worker        *
1004*2d1272b8SAndroid Build Coastguard Worker        *    and
1005*2d1272b8SAndroid Build Coastguard Worker        *
1006*2d1272b8SAndroid Build Coastguard Worker        * 3. If we break before current glyph, there won't be any end-of-text action
1007*2d1272b8SAndroid Build Coastguard Worker        *    after previous glyph.
1008*2d1272b8SAndroid Build Coastguard Worker        *
1009*2d1272b8SAndroid Build Coastguard Worker        * This triples the transitions we need to look up, but is worth returning
1010*2d1272b8SAndroid Build Coastguard Worker        * granular unsafe-to-break results. See eg.:
1011*2d1272b8SAndroid Build Coastguard Worker        *
1012*2d1272b8SAndroid Build Coastguard Worker        *   https://github.com/harfbuzz/harfbuzz/issues/2860
1013*2d1272b8SAndroid Build Coastguard Worker        */
1014*2d1272b8SAndroid Build Coastguard Worker 
1015*2d1272b8SAndroid Build Coastguard Worker       const auto is_safe_to_break_extra = [&]()
1016*2d1272b8SAndroid Build Coastguard Worker       {
1017*2d1272b8SAndroid Build Coastguard Worker           /* 2c. */
1018*2d1272b8SAndroid Build Coastguard Worker           const auto &wouldbe_entry = machine.get_entry(StateTableT::STATE_START_OF_TEXT, klass);
1019*2d1272b8SAndroid Build Coastguard Worker 
1020*2d1272b8SAndroid Build Coastguard Worker           /* 2c'. */
1021*2d1272b8SAndroid Build Coastguard Worker           if (c->is_actionable (buffer, this, wouldbe_entry))
1022*2d1272b8SAndroid Build Coastguard Worker 	    return false;
1023*2d1272b8SAndroid Build Coastguard Worker 
1024*2d1272b8SAndroid Build Coastguard Worker           /* 2c". */
1025*2d1272b8SAndroid Build Coastguard Worker           return next_state == machine.new_state(wouldbe_entry.newState)
1026*2d1272b8SAndroid Build Coastguard Worker               && (entry.flags & context_t::DontAdvance) == (wouldbe_entry.flags & context_t::DontAdvance);
1027*2d1272b8SAndroid Build Coastguard Worker       };
1028*2d1272b8SAndroid Build Coastguard Worker 
1029*2d1272b8SAndroid Build Coastguard Worker       const auto is_safe_to_break = [&]()
1030*2d1272b8SAndroid Build Coastguard Worker       {
1031*2d1272b8SAndroid Build Coastguard Worker           /* 1. */
1032*2d1272b8SAndroid Build Coastguard Worker           if (c->is_actionable (buffer, this, entry))
1033*2d1272b8SAndroid Build Coastguard Worker               return false;
1034*2d1272b8SAndroid Build Coastguard Worker 
1035*2d1272b8SAndroid Build Coastguard Worker           /* 2. */
1036*2d1272b8SAndroid Build Coastguard Worker           // This one is meh, I know...
1037*2d1272b8SAndroid Build Coastguard Worker           const auto ok =
1038*2d1272b8SAndroid Build Coastguard Worker                  state == StateTableT::STATE_START_OF_TEXT
1039*2d1272b8SAndroid Build Coastguard Worker               || ((entry.flags & context_t::DontAdvance) && next_state == StateTableT::STATE_START_OF_TEXT)
1040*2d1272b8SAndroid Build Coastguard Worker               || is_safe_to_break_extra();
1041*2d1272b8SAndroid Build Coastguard Worker           if (!ok)
1042*2d1272b8SAndroid Build Coastguard Worker               return false;
1043*2d1272b8SAndroid Build Coastguard Worker 
1044*2d1272b8SAndroid Build Coastguard Worker           /* 3. */
1045*2d1272b8SAndroid Build Coastguard Worker           return !c->is_actionable (buffer, this, machine.get_entry (state, CLASS_END_OF_TEXT));
1046*2d1272b8SAndroid Build Coastguard Worker       };
1047*2d1272b8SAndroid Build Coastguard Worker 
1048*2d1272b8SAndroid Build Coastguard Worker       if (!is_safe_to_break () && buffer->backtrack_len () && buffer->idx < buffer->len)
1049*2d1272b8SAndroid Build Coastguard Worker 	buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1);
1050*2d1272b8SAndroid Build Coastguard Worker 
1051*2d1272b8SAndroid Build Coastguard Worker       c->transition (buffer, this, entry);
1052*2d1272b8SAndroid Build Coastguard Worker 
1053*2d1272b8SAndroid Build Coastguard Worker       state = next_state;
1054*2d1272b8SAndroid Build Coastguard Worker       DEBUG_MSG (APPLY, nullptr, "s%d", state);
1055*2d1272b8SAndroid Build Coastguard Worker 
1056*2d1272b8SAndroid Build Coastguard Worker       if (buffer->idx == buffer->len || unlikely (!buffer->successful))
1057*2d1272b8SAndroid Build Coastguard Worker 	break;
1058*2d1272b8SAndroid Build Coastguard Worker 
1059*2d1272b8SAndroid Build Coastguard Worker       if (!(entry.flags & context_t::DontAdvance) || buffer->max_ops-- <= 0)
1060*2d1272b8SAndroid Build Coastguard Worker 	(void) buffer->next_glyph ();
1061*2d1272b8SAndroid Build Coastguard Worker     }
1062*2d1272b8SAndroid Build Coastguard Worker 
1063*2d1272b8SAndroid Build Coastguard Worker     if (!c->in_place)
1064*2d1272b8SAndroid Build Coastguard Worker       buffer->sync ();
1065*2d1272b8SAndroid Build Coastguard Worker   }
1066*2d1272b8SAndroid Build Coastguard Worker 
1067*2d1272b8SAndroid Build Coastguard Worker   public:
1068*2d1272b8SAndroid Build Coastguard Worker   const StateTableT &machine;
1069*2d1272b8SAndroid Build Coastguard Worker   unsigned int num_glyphs;
1070*2d1272b8SAndroid Build Coastguard Worker };
1071*2d1272b8SAndroid Build Coastguard Worker 
1072*2d1272b8SAndroid Build Coastguard Worker 
1073*2d1272b8SAndroid Build Coastguard Worker } /* namespace AAT */
1074*2d1272b8SAndroid Build Coastguard Worker 
1075*2d1272b8SAndroid Build Coastguard Worker 
1076*2d1272b8SAndroid Build Coastguard Worker #endif /* HB_AAT_LAYOUT_COMMON_HH */
1077