xref: /aosp_15_r20/external/harfbuzz_ng/src/hb-aat-layout-kerx-table.hh (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
1*2d1272b8SAndroid Build Coastguard Worker /*
2*2d1272b8SAndroid Build Coastguard Worker  * Copyright © 2018  Ebrahim Byagowi
3*2d1272b8SAndroid Build Coastguard Worker  * Copyright © 2018  Google, Inc.
4*2d1272b8SAndroid Build Coastguard Worker  *
5*2d1272b8SAndroid Build Coastguard Worker  *  This is part of HarfBuzz, a text shaping library.
6*2d1272b8SAndroid Build Coastguard Worker  *
7*2d1272b8SAndroid Build Coastguard Worker  * Permission is hereby granted, without written agreement and without
8*2d1272b8SAndroid Build Coastguard Worker  * license or royalty fees, to use, copy, modify, and distribute this
9*2d1272b8SAndroid Build Coastguard Worker  * software and its documentation for any purpose, provided that the
10*2d1272b8SAndroid Build Coastguard Worker  * above copyright notice and the following two paragraphs appear in
11*2d1272b8SAndroid Build Coastguard Worker  * all copies of this software.
12*2d1272b8SAndroid Build Coastguard Worker  *
13*2d1272b8SAndroid Build Coastguard Worker  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14*2d1272b8SAndroid Build Coastguard Worker  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15*2d1272b8SAndroid Build Coastguard Worker  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16*2d1272b8SAndroid Build Coastguard Worker  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17*2d1272b8SAndroid Build Coastguard Worker  * DAMAGE.
18*2d1272b8SAndroid Build Coastguard Worker  *
19*2d1272b8SAndroid Build Coastguard Worker  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20*2d1272b8SAndroid Build Coastguard Worker  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21*2d1272b8SAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
22*2d1272b8SAndroid Build Coastguard Worker  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23*2d1272b8SAndroid Build Coastguard Worker  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24*2d1272b8SAndroid Build Coastguard Worker  *
25*2d1272b8SAndroid Build Coastguard Worker  * Google Author(s): Behdad Esfahbod
26*2d1272b8SAndroid Build Coastguard Worker  */
27*2d1272b8SAndroid Build Coastguard Worker 
28*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_AAT_LAYOUT_KERX_TABLE_HH
29*2d1272b8SAndroid Build Coastguard Worker #define HB_AAT_LAYOUT_KERX_TABLE_HH
30*2d1272b8SAndroid Build Coastguard Worker 
31*2d1272b8SAndroid Build Coastguard Worker #include "hb-kern.hh"
32*2d1272b8SAndroid Build Coastguard Worker #include "hb-aat-layout-ankr-table.hh"
33*2d1272b8SAndroid Build Coastguard Worker #include "hb-set-digest.hh"
34*2d1272b8SAndroid Build Coastguard Worker 
35*2d1272b8SAndroid Build Coastguard Worker /*
36*2d1272b8SAndroid Build Coastguard Worker  * kerx -- Extended Kerning
37*2d1272b8SAndroid Build Coastguard Worker  * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6kerx.html
38*2d1272b8SAndroid Build Coastguard Worker  */
39*2d1272b8SAndroid Build Coastguard Worker #define HB_AAT_TAG_kerx HB_TAG('k','e','r','x')
40*2d1272b8SAndroid Build Coastguard Worker 
41*2d1272b8SAndroid Build Coastguard Worker 
42*2d1272b8SAndroid Build Coastguard Worker namespace AAT {
43*2d1272b8SAndroid Build Coastguard Worker 
44*2d1272b8SAndroid Build Coastguard Worker using namespace OT;
45*2d1272b8SAndroid Build Coastguard Worker 
46*2d1272b8SAndroid Build Coastguard Worker 
47*2d1272b8SAndroid Build Coastguard Worker static inline int
kerxTupleKern(int value,unsigned int tupleCount,const void * base,hb_aat_apply_context_t * c)48*2d1272b8SAndroid Build Coastguard Worker kerxTupleKern (int value,
49*2d1272b8SAndroid Build Coastguard Worker 	       unsigned int tupleCount,
50*2d1272b8SAndroid Build Coastguard Worker 	       const void *base,
51*2d1272b8SAndroid Build Coastguard Worker 	       hb_aat_apply_context_t *c)
52*2d1272b8SAndroid Build Coastguard Worker {
53*2d1272b8SAndroid Build Coastguard Worker   if (likely (!tupleCount || !c)) return value;
54*2d1272b8SAndroid Build Coastguard Worker 
55*2d1272b8SAndroid Build Coastguard Worker   unsigned int offset = value;
56*2d1272b8SAndroid Build Coastguard Worker   const FWORD *pv = &StructAtOffset<FWORD> (base, offset);
57*2d1272b8SAndroid Build Coastguard Worker   if (unlikely (!c->sanitizer.check_array (pv, tupleCount))) return 0;
58*2d1272b8SAndroid Build Coastguard Worker   hb_barrier ();
59*2d1272b8SAndroid Build Coastguard Worker   return *pv;
60*2d1272b8SAndroid Build Coastguard Worker }
61*2d1272b8SAndroid Build Coastguard Worker 
62*2d1272b8SAndroid Build Coastguard Worker 
63*2d1272b8SAndroid Build Coastguard Worker struct hb_glyph_pair_t
64*2d1272b8SAndroid Build Coastguard Worker {
65*2d1272b8SAndroid Build Coastguard Worker   hb_codepoint_t left;
66*2d1272b8SAndroid Build Coastguard Worker   hb_codepoint_t right;
67*2d1272b8SAndroid Build Coastguard Worker };
68*2d1272b8SAndroid Build Coastguard Worker 
69*2d1272b8SAndroid Build Coastguard Worker struct KernPair
70*2d1272b8SAndroid Build Coastguard Worker {
get_kerningAAT::KernPair71*2d1272b8SAndroid Build Coastguard Worker   int get_kerning () const { return value; }
72*2d1272b8SAndroid Build Coastguard Worker 
cmpAAT::KernPair73*2d1272b8SAndroid Build Coastguard Worker   int cmp (const hb_glyph_pair_t &o) const
74*2d1272b8SAndroid Build Coastguard Worker   {
75*2d1272b8SAndroid Build Coastguard Worker     int ret = left.cmp (o.left);
76*2d1272b8SAndroid Build Coastguard Worker     if (ret) return ret;
77*2d1272b8SAndroid Build Coastguard Worker     return right.cmp (o.right);
78*2d1272b8SAndroid Build Coastguard Worker   }
79*2d1272b8SAndroid Build Coastguard Worker 
sanitizeAAT::KernPair80*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
81*2d1272b8SAndroid Build Coastguard Worker   {
82*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
83*2d1272b8SAndroid Build Coastguard Worker     return_trace (c->check_struct (this));
84*2d1272b8SAndroid Build Coastguard Worker   }
85*2d1272b8SAndroid Build Coastguard Worker 
86*2d1272b8SAndroid Build Coastguard Worker   public:
87*2d1272b8SAndroid Build Coastguard Worker   HBGlyphID16	left;
88*2d1272b8SAndroid Build Coastguard Worker   HBGlyphID16	right;
89*2d1272b8SAndroid Build Coastguard Worker   FWORD		value;
90*2d1272b8SAndroid Build Coastguard Worker   public:
91*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_STATIC (6);
92*2d1272b8SAndroid Build Coastguard Worker };
93*2d1272b8SAndroid Build Coastguard Worker 
94*2d1272b8SAndroid Build Coastguard Worker template <typename KernSubTableHeader>
95*2d1272b8SAndroid Build Coastguard Worker struct KerxSubTableFormat0
96*2d1272b8SAndroid Build Coastguard Worker {
get_kerningAAT::KerxSubTableFormat097*2d1272b8SAndroid Build Coastguard Worker   int get_kerning (hb_codepoint_t left, hb_codepoint_t right,
98*2d1272b8SAndroid Build Coastguard Worker 		   hb_aat_apply_context_t *c = nullptr) const
99*2d1272b8SAndroid Build Coastguard Worker   {
100*2d1272b8SAndroid Build Coastguard Worker     hb_glyph_pair_t pair = {left, right};
101*2d1272b8SAndroid Build Coastguard Worker     int v = pairs.bsearch (pair).get_kerning ();
102*2d1272b8SAndroid Build Coastguard Worker     return kerxTupleKern (v, header.tuple_count (), this, c);
103*2d1272b8SAndroid Build Coastguard Worker   }
104*2d1272b8SAndroid Build Coastguard Worker 
applyAAT::KerxSubTableFormat0105*2d1272b8SAndroid Build Coastguard Worker   bool apply (hb_aat_apply_context_t *c) const
106*2d1272b8SAndroid Build Coastguard Worker   {
107*2d1272b8SAndroid Build Coastguard Worker     TRACE_APPLY (this);
108*2d1272b8SAndroid Build Coastguard Worker 
109*2d1272b8SAndroid Build Coastguard Worker     if (!c->plan->requested_kerning)
110*2d1272b8SAndroid Build Coastguard Worker       return_trace (false);
111*2d1272b8SAndroid Build Coastguard Worker 
112*2d1272b8SAndroid Build Coastguard Worker     if (header.coverage & header.Backwards)
113*2d1272b8SAndroid Build Coastguard Worker       return_trace (false);
114*2d1272b8SAndroid Build Coastguard Worker 
115*2d1272b8SAndroid Build Coastguard Worker     if (!(c->buffer_digest.may_have (c->left_set) &&
116*2d1272b8SAndroid Build Coastguard Worker 	  c->buffer_digest.may_have (c->right_set)))
117*2d1272b8SAndroid Build Coastguard Worker       return_trace (false);
118*2d1272b8SAndroid Build Coastguard Worker 
119*2d1272b8SAndroid Build Coastguard Worker     accelerator_t accel (*this, c);
120*2d1272b8SAndroid Build Coastguard Worker     hb_kern_machine_t<accelerator_t> machine (accel, header.coverage & header.CrossStream);
121*2d1272b8SAndroid Build Coastguard Worker     machine.kern (c->font, c->buffer, c->plan->kern_mask);
122*2d1272b8SAndroid Build Coastguard Worker 
123*2d1272b8SAndroid Build Coastguard Worker     return_trace (true);
124*2d1272b8SAndroid Build Coastguard Worker   }
125*2d1272b8SAndroid Build Coastguard Worker 
126*2d1272b8SAndroid Build Coastguard Worker   template <typename set_t>
collect_glyphsAAT::KerxSubTableFormat0127*2d1272b8SAndroid Build Coastguard Worker   void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
128*2d1272b8SAndroid Build Coastguard Worker   {
129*2d1272b8SAndroid Build Coastguard Worker     for (const KernPair& pair : pairs)
130*2d1272b8SAndroid Build Coastguard Worker     {
131*2d1272b8SAndroid Build Coastguard Worker       left_set.add (pair.left);
132*2d1272b8SAndroid Build Coastguard Worker       right_set.add (pair.right);
133*2d1272b8SAndroid Build Coastguard Worker     }
134*2d1272b8SAndroid Build Coastguard Worker   }
135*2d1272b8SAndroid Build Coastguard Worker 
136*2d1272b8SAndroid Build Coastguard Worker   struct accelerator_t
137*2d1272b8SAndroid Build Coastguard Worker   {
138*2d1272b8SAndroid Build Coastguard Worker     const KerxSubTableFormat0 &table;
139*2d1272b8SAndroid Build Coastguard Worker     hb_aat_apply_context_t *c;
140*2d1272b8SAndroid Build Coastguard Worker 
accelerator_tAAT::KerxSubTableFormat0::accelerator_t141*2d1272b8SAndroid Build Coastguard Worker     accelerator_t (const KerxSubTableFormat0 &table_,
142*2d1272b8SAndroid Build Coastguard Worker 		   hb_aat_apply_context_t *c_) :
143*2d1272b8SAndroid Build Coastguard Worker 		     table (table_), c (c_) {}
144*2d1272b8SAndroid Build Coastguard Worker 
get_kerningAAT::KerxSubTableFormat0::accelerator_t145*2d1272b8SAndroid Build Coastguard Worker     int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
146*2d1272b8SAndroid Build Coastguard Worker     {
147*2d1272b8SAndroid Build Coastguard Worker       if (!c->left_set[left] || !c->right_set[right]) return 0;
148*2d1272b8SAndroid Build Coastguard Worker       return table.get_kerning (left, right, c);
149*2d1272b8SAndroid Build Coastguard Worker     }
150*2d1272b8SAndroid Build Coastguard Worker   };
151*2d1272b8SAndroid Build Coastguard Worker 
152*2d1272b8SAndroid Build Coastguard Worker 
sanitizeAAT::KerxSubTableFormat0153*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
154*2d1272b8SAndroid Build Coastguard Worker   {
155*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
156*2d1272b8SAndroid Build Coastguard Worker     return_trace (likely (pairs.sanitize (c)));
157*2d1272b8SAndroid Build Coastguard Worker   }
158*2d1272b8SAndroid Build Coastguard Worker 
159*2d1272b8SAndroid Build Coastguard Worker   protected:
160*2d1272b8SAndroid Build Coastguard Worker   KernSubTableHeader	header;
161*2d1272b8SAndroid Build Coastguard Worker   BinSearchArrayOf<KernPair, typename KernSubTableHeader::Types::HBUINT>
162*2d1272b8SAndroid Build Coastguard Worker 			pairs;	/* Sorted kern records. */
163*2d1272b8SAndroid Build Coastguard Worker   public:
164*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_ARRAY (KernSubTableHeader::static_size + 16, pairs);
165*2d1272b8SAndroid Build Coastguard Worker };
166*2d1272b8SAndroid Build Coastguard Worker 
167*2d1272b8SAndroid Build Coastguard Worker 
168*2d1272b8SAndroid Build Coastguard Worker template <bool extended>
169*2d1272b8SAndroid Build Coastguard Worker struct Format1Entry;
170*2d1272b8SAndroid Build Coastguard Worker 
171*2d1272b8SAndroid Build Coastguard Worker template <>
172*2d1272b8SAndroid Build Coastguard Worker struct Format1Entry<true>
173*2d1272b8SAndroid Build Coastguard Worker {
174*2d1272b8SAndroid Build Coastguard Worker   enum Flags
175*2d1272b8SAndroid Build Coastguard Worker   {
176*2d1272b8SAndroid Build Coastguard Worker     Push		= 0x8000,	/* If set, push this glyph on the kerning stack. */
177*2d1272b8SAndroid Build Coastguard Worker     DontAdvance		= 0x4000,	/* If set, don't advance to the next glyph
178*2d1272b8SAndroid Build Coastguard Worker 					 * before going to the new state. */
179*2d1272b8SAndroid Build Coastguard Worker     Reset		= 0x2000,	/* If set, reset the kerning data (clear the stack) */
180*2d1272b8SAndroid Build Coastguard Worker     Reserved		= 0x1FFF,	/* Not used; set to 0. */
181*2d1272b8SAndroid Build Coastguard Worker   };
182*2d1272b8SAndroid Build Coastguard Worker 
183*2d1272b8SAndroid Build Coastguard Worker   struct EntryData
184*2d1272b8SAndroid Build Coastguard Worker   {
185*2d1272b8SAndroid Build Coastguard Worker     HBUINT16	kernActionIndex;/* Index into the kerning value array. If
186*2d1272b8SAndroid Build Coastguard Worker 				 * this index is 0xFFFF, then no kerning
187*2d1272b8SAndroid Build Coastguard Worker 				 * is to be performed. */
188*2d1272b8SAndroid Build Coastguard Worker     public:
189*2d1272b8SAndroid Build Coastguard Worker     DEFINE_SIZE_STATIC (2);
190*2d1272b8SAndroid Build Coastguard Worker   };
191*2d1272b8SAndroid Build Coastguard Worker 
performActionAAT::Format1Entry192*2d1272b8SAndroid Build Coastguard Worker   static bool performAction (const Entry<EntryData> &entry)
193*2d1272b8SAndroid Build Coastguard Worker   { return entry.data.kernActionIndex != 0xFFFF; }
194*2d1272b8SAndroid Build Coastguard Worker 
kernActionIndexAAT::Format1Entry195*2d1272b8SAndroid Build Coastguard Worker   static unsigned int kernActionIndex (const Entry<EntryData> &entry)
196*2d1272b8SAndroid Build Coastguard Worker   { return entry.data.kernActionIndex; }
197*2d1272b8SAndroid Build Coastguard Worker };
198*2d1272b8SAndroid Build Coastguard Worker template <>
199*2d1272b8SAndroid Build Coastguard Worker struct Format1Entry<false>
200*2d1272b8SAndroid Build Coastguard Worker {
201*2d1272b8SAndroid Build Coastguard Worker   enum Flags
202*2d1272b8SAndroid Build Coastguard Worker   {
203*2d1272b8SAndroid Build Coastguard Worker     Push		= 0x8000,	/* If set, push this glyph on the kerning stack. */
204*2d1272b8SAndroid Build Coastguard Worker     DontAdvance		= 0x4000,	/* If set, don't advance to the next glyph
205*2d1272b8SAndroid Build Coastguard Worker 					 * before going to the new state. */
206*2d1272b8SAndroid Build Coastguard Worker     Offset		= 0x3FFF,	/* Byte offset from beginning of subtable to the
207*2d1272b8SAndroid Build Coastguard Worker 					 * value table for the glyphs on the kerning stack. */
208*2d1272b8SAndroid Build Coastguard Worker 
209*2d1272b8SAndroid Build Coastguard Worker     Reset		= 0x0000,	/* Not supported? */
210*2d1272b8SAndroid Build Coastguard Worker   };
211*2d1272b8SAndroid Build Coastguard Worker 
212*2d1272b8SAndroid Build Coastguard Worker   typedef void EntryData;
213*2d1272b8SAndroid Build Coastguard Worker 
performActionAAT::Format1Entry214*2d1272b8SAndroid Build Coastguard Worker   static bool performAction (const Entry<EntryData> &entry)
215*2d1272b8SAndroid Build Coastguard Worker   { return entry.flags & Offset; }
216*2d1272b8SAndroid Build Coastguard Worker 
kernActionIndexAAT::Format1Entry217*2d1272b8SAndroid Build Coastguard Worker   static unsigned int kernActionIndex (const Entry<EntryData> &entry)
218*2d1272b8SAndroid Build Coastguard Worker   { return entry.flags & Offset; }
219*2d1272b8SAndroid Build Coastguard Worker };
220*2d1272b8SAndroid Build Coastguard Worker 
221*2d1272b8SAndroid Build Coastguard Worker template <typename KernSubTableHeader>
222*2d1272b8SAndroid Build Coastguard Worker struct KerxSubTableFormat1
223*2d1272b8SAndroid Build Coastguard Worker {
224*2d1272b8SAndroid Build Coastguard Worker   typedef typename KernSubTableHeader::Types Types;
225*2d1272b8SAndroid Build Coastguard Worker   typedef typename Types::HBUINT HBUINT;
226*2d1272b8SAndroid Build Coastguard Worker 
227*2d1272b8SAndroid Build Coastguard Worker   typedef Format1Entry<Types::extended> Format1EntryT;
228*2d1272b8SAndroid Build Coastguard Worker   typedef typename Format1EntryT::EntryData EntryData;
229*2d1272b8SAndroid Build Coastguard Worker 
230*2d1272b8SAndroid Build Coastguard Worker   struct driver_context_t
231*2d1272b8SAndroid Build Coastguard Worker   {
232*2d1272b8SAndroid Build Coastguard Worker     static constexpr bool in_place = true;
233*2d1272b8SAndroid Build Coastguard Worker     enum
234*2d1272b8SAndroid Build Coastguard Worker     {
235*2d1272b8SAndroid Build Coastguard Worker       DontAdvance	= Format1EntryT::DontAdvance,
236*2d1272b8SAndroid Build Coastguard Worker     };
237*2d1272b8SAndroid Build Coastguard Worker 
driver_context_tAAT::KerxSubTableFormat1::driver_context_t238*2d1272b8SAndroid Build Coastguard Worker     driver_context_t (const KerxSubTableFormat1 *table_,
239*2d1272b8SAndroid Build Coastguard Worker 		      hb_aat_apply_context_t *c_) :
240*2d1272b8SAndroid Build Coastguard Worker 	c (c_),
241*2d1272b8SAndroid Build Coastguard Worker 	table (table_),
242*2d1272b8SAndroid Build Coastguard Worker 	/* Apparently the offset kernAction is from the beginning of the state-machine,
243*2d1272b8SAndroid Build Coastguard Worker 	 * similar to offsets in morx table, NOT from beginning of this table, like
244*2d1272b8SAndroid Build Coastguard Worker 	 * other subtables in kerx.  Discovered via testing. */
245*2d1272b8SAndroid Build Coastguard Worker 	kernAction (&table->machine + table->kernAction),
246*2d1272b8SAndroid Build Coastguard Worker 	depth (0),
247*2d1272b8SAndroid Build Coastguard Worker 	crossStream (table->header.coverage & table->header.CrossStream) {}
248*2d1272b8SAndroid Build Coastguard Worker 
is_actionableAAT::KerxSubTableFormat1::driver_context_t249*2d1272b8SAndroid Build Coastguard Worker     bool is_actionable (hb_buffer_t *buffer HB_UNUSED,
250*2d1272b8SAndroid Build Coastguard Worker 			StateTableDriver<Types, EntryData> *driver HB_UNUSED,
251*2d1272b8SAndroid Build Coastguard Worker 			const Entry<EntryData> &entry)
252*2d1272b8SAndroid Build Coastguard Worker     { return Format1EntryT::performAction (entry); }
transitionAAT::KerxSubTableFormat1::driver_context_t253*2d1272b8SAndroid Build Coastguard Worker     void transition (hb_buffer_t *buffer,
254*2d1272b8SAndroid Build Coastguard Worker 		     StateTableDriver<Types, EntryData> *driver,
255*2d1272b8SAndroid Build Coastguard Worker 		     const Entry<EntryData> &entry)
256*2d1272b8SAndroid Build Coastguard Worker     {
257*2d1272b8SAndroid Build Coastguard Worker       unsigned int flags = entry.flags;
258*2d1272b8SAndroid Build Coastguard Worker 
259*2d1272b8SAndroid Build Coastguard Worker       if (flags & Format1EntryT::Reset)
260*2d1272b8SAndroid Build Coastguard Worker 	depth = 0;
261*2d1272b8SAndroid Build Coastguard Worker 
262*2d1272b8SAndroid Build Coastguard Worker       if (flags & Format1EntryT::Push)
263*2d1272b8SAndroid Build Coastguard Worker       {
264*2d1272b8SAndroid Build Coastguard Worker 	if (likely (depth < ARRAY_LENGTH (stack)))
265*2d1272b8SAndroid Build Coastguard Worker 	  stack[depth++] = buffer->idx;
266*2d1272b8SAndroid Build Coastguard Worker 	else
267*2d1272b8SAndroid Build Coastguard Worker 	  depth = 0; /* Probably not what CoreText does, but better? */
268*2d1272b8SAndroid Build Coastguard Worker       }
269*2d1272b8SAndroid Build Coastguard Worker 
270*2d1272b8SAndroid Build Coastguard Worker       if (Format1EntryT::performAction (entry) && depth)
271*2d1272b8SAndroid Build Coastguard Worker       {
272*2d1272b8SAndroid Build Coastguard Worker 	unsigned int tuple_count = hb_max (1u, table->header.tuple_count ());
273*2d1272b8SAndroid Build Coastguard Worker 
274*2d1272b8SAndroid Build Coastguard Worker 	unsigned int kern_idx = Format1EntryT::kernActionIndex (entry);
275*2d1272b8SAndroid Build Coastguard Worker 	kern_idx = Types::byteOffsetToIndex (kern_idx, &table->machine, kernAction.arrayZ);
276*2d1272b8SAndroid Build Coastguard Worker 	const FWORD *actions = &kernAction[kern_idx];
277*2d1272b8SAndroid Build Coastguard Worker 	if (!c->sanitizer.check_array (actions, depth, tuple_count))
278*2d1272b8SAndroid Build Coastguard Worker 	{
279*2d1272b8SAndroid Build Coastguard Worker 	  depth = 0;
280*2d1272b8SAndroid Build Coastguard Worker 	  return;
281*2d1272b8SAndroid Build Coastguard Worker 	}
282*2d1272b8SAndroid Build Coastguard Worker 	hb_barrier ();
283*2d1272b8SAndroid Build Coastguard Worker 
284*2d1272b8SAndroid Build Coastguard Worker 	hb_mask_t kern_mask = c->plan->kern_mask;
285*2d1272b8SAndroid Build Coastguard Worker 
286*2d1272b8SAndroid Build Coastguard Worker 	/* From Apple 'kern' spec:
287*2d1272b8SAndroid Build Coastguard Worker 	 * "Each pops one glyph from the kerning stack and applies the kerning value to it.
288*2d1272b8SAndroid Build Coastguard Worker 	 * The end of the list is marked by an odd value... */
289*2d1272b8SAndroid Build Coastguard Worker 	bool last = false;
290*2d1272b8SAndroid Build Coastguard Worker 	while (!last && depth)
291*2d1272b8SAndroid Build Coastguard Worker 	{
292*2d1272b8SAndroid Build Coastguard Worker 	  unsigned int idx = stack[--depth];
293*2d1272b8SAndroid Build Coastguard Worker 	  int v = *actions;
294*2d1272b8SAndroid Build Coastguard Worker 	  actions += tuple_count;
295*2d1272b8SAndroid Build Coastguard Worker 	  if (idx >= buffer->len) continue;
296*2d1272b8SAndroid Build Coastguard Worker 
297*2d1272b8SAndroid Build Coastguard Worker 	  /* "The end of the list is marked by an odd value..." */
298*2d1272b8SAndroid Build Coastguard Worker 	  last = v & 1;
299*2d1272b8SAndroid Build Coastguard Worker 	  v &= ~1;
300*2d1272b8SAndroid Build Coastguard Worker 
301*2d1272b8SAndroid Build Coastguard Worker 	  hb_glyph_position_t &o = buffer->pos[idx];
302*2d1272b8SAndroid Build Coastguard Worker 
303*2d1272b8SAndroid Build Coastguard Worker 	  if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
304*2d1272b8SAndroid Build Coastguard Worker 	  {
305*2d1272b8SAndroid Build Coastguard Worker 	    if (crossStream)
306*2d1272b8SAndroid Build Coastguard Worker 	    {
307*2d1272b8SAndroid Build Coastguard Worker 	      /* The following flag is undocumented in the spec, but described
308*2d1272b8SAndroid Build Coastguard Worker 	       * in the 'kern' table example. */
309*2d1272b8SAndroid Build Coastguard Worker 	      if (v == -0x8000)
310*2d1272b8SAndroid Build Coastguard Worker 	      {
311*2d1272b8SAndroid Build Coastguard Worker 		o.attach_type() = OT::Layout::GPOS_impl::ATTACH_TYPE_NONE;
312*2d1272b8SAndroid Build Coastguard Worker 		o.attach_chain() = 0;
313*2d1272b8SAndroid Build Coastguard Worker 		o.y_offset = 0;
314*2d1272b8SAndroid Build Coastguard Worker 	      }
315*2d1272b8SAndroid Build Coastguard Worker 	      else if (o.attach_type())
316*2d1272b8SAndroid Build Coastguard Worker 	      {
317*2d1272b8SAndroid Build Coastguard Worker 		o.y_offset += c->font->em_scale_y (v);
318*2d1272b8SAndroid Build Coastguard Worker 		buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
319*2d1272b8SAndroid Build Coastguard Worker 	      }
320*2d1272b8SAndroid Build Coastguard Worker 	    }
321*2d1272b8SAndroid Build Coastguard Worker 	    else if (buffer->info[idx].mask & kern_mask)
322*2d1272b8SAndroid Build Coastguard Worker 	    {
323*2d1272b8SAndroid Build Coastguard Worker 	      o.x_advance += c->font->em_scale_x (v);
324*2d1272b8SAndroid Build Coastguard Worker 	      o.x_offset += c->font->em_scale_x (v);
325*2d1272b8SAndroid Build Coastguard Worker 	    }
326*2d1272b8SAndroid Build Coastguard Worker 	  }
327*2d1272b8SAndroid Build Coastguard Worker 	  else
328*2d1272b8SAndroid Build Coastguard Worker 	  {
329*2d1272b8SAndroid Build Coastguard Worker 	    if (crossStream)
330*2d1272b8SAndroid Build Coastguard Worker 	    {
331*2d1272b8SAndroid Build Coastguard Worker 	      /* CoreText doesn't do crossStream kerning in vertical.  We do. */
332*2d1272b8SAndroid Build Coastguard Worker 	      if (v == -0x8000)
333*2d1272b8SAndroid Build Coastguard Worker 	      {
334*2d1272b8SAndroid Build Coastguard Worker 		o.attach_type() = OT::Layout::GPOS_impl::ATTACH_TYPE_NONE;
335*2d1272b8SAndroid Build Coastguard Worker 		o.attach_chain() = 0;
336*2d1272b8SAndroid Build Coastguard Worker 		o.x_offset = 0;
337*2d1272b8SAndroid Build Coastguard Worker 	      }
338*2d1272b8SAndroid Build Coastguard Worker 	      else if (o.attach_type())
339*2d1272b8SAndroid Build Coastguard Worker 	      {
340*2d1272b8SAndroid Build Coastguard Worker 		o.x_offset += c->font->em_scale_x (v);
341*2d1272b8SAndroid Build Coastguard Worker 		buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
342*2d1272b8SAndroid Build Coastguard Worker 	      }
343*2d1272b8SAndroid Build Coastguard Worker 	    }
344*2d1272b8SAndroid Build Coastguard Worker 	    else if (buffer->info[idx].mask & kern_mask)
345*2d1272b8SAndroid Build Coastguard Worker 	    {
346*2d1272b8SAndroid Build Coastguard Worker 	      o.y_advance += c->font->em_scale_y (v);
347*2d1272b8SAndroid Build Coastguard Worker 	      o.y_offset += c->font->em_scale_y (v);
348*2d1272b8SAndroid Build Coastguard Worker 	    }
349*2d1272b8SAndroid Build Coastguard Worker 	  }
350*2d1272b8SAndroid Build Coastguard Worker 	}
351*2d1272b8SAndroid Build Coastguard Worker       }
352*2d1272b8SAndroid Build Coastguard Worker     }
353*2d1272b8SAndroid Build Coastguard Worker 
354*2d1272b8SAndroid Build Coastguard Worker     private:
355*2d1272b8SAndroid Build Coastguard Worker     hb_aat_apply_context_t *c;
356*2d1272b8SAndroid Build Coastguard Worker     const KerxSubTableFormat1 *table;
357*2d1272b8SAndroid Build Coastguard Worker     const UnsizedArrayOf<FWORD> &kernAction;
358*2d1272b8SAndroid Build Coastguard Worker     unsigned int stack[8];
359*2d1272b8SAndroid Build Coastguard Worker     unsigned int depth;
360*2d1272b8SAndroid Build Coastguard Worker     bool crossStream;
361*2d1272b8SAndroid Build Coastguard Worker   };
362*2d1272b8SAndroid Build Coastguard Worker 
applyAAT::KerxSubTableFormat1363*2d1272b8SAndroid Build Coastguard Worker   bool apply (hb_aat_apply_context_t *c) const
364*2d1272b8SAndroid Build Coastguard Worker   {
365*2d1272b8SAndroid Build Coastguard Worker     TRACE_APPLY (this);
366*2d1272b8SAndroid Build Coastguard Worker 
367*2d1272b8SAndroid Build Coastguard Worker     if (!c->plan->requested_kerning &&
368*2d1272b8SAndroid Build Coastguard Worker 	!(header.coverage & header.CrossStream))
369*2d1272b8SAndroid Build Coastguard Worker       return false;
370*2d1272b8SAndroid Build Coastguard Worker 
371*2d1272b8SAndroid Build Coastguard Worker     driver_context_t dc (this, c);
372*2d1272b8SAndroid Build Coastguard Worker 
373*2d1272b8SAndroid Build Coastguard Worker     StateTableDriver<Types, EntryData> driver (machine, c->font->face);
374*2d1272b8SAndroid Build Coastguard Worker 
375*2d1272b8SAndroid Build Coastguard Worker     if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) &&
376*2d1272b8SAndroid Build Coastguard Worker 	!(c->buffer_digest.may_have (c->left_set) &&
377*2d1272b8SAndroid Build Coastguard Worker 	  c->buffer_digest.may_have (c->right_set)))
378*2d1272b8SAndroid Build Coastguard Worker       return_trace (false);
379*2d1272b8SAndroid Build Coastguard Worker 
380*2d1272b8SAndroid Build Coastguard Worker     driver.drive (&dc, c);
381*2d1272b8SAndroid Build Coastguard Worker 
382*2d1272b8SAndroid Build Coastguard Worker     return_trace (true);
383*2d1272b8SAndroid Build Coastguard Worker   }
384*2d1272b8SAndroid Build Coastguard Worker 
sanitizeAAT::KerxSubTableFormat1385*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
386*2d1272b8SAndroid Build Coastguard Worker   {
387*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
388*2d1272b8SAndroid Build Coastguard Worker     /* The rest of array sanitizations are done at run-time. */
389*2d1272b8SAndroid Build Coastguard Worker     return_trace (likely (c->check_struct (this) &&
390*2d1272b8SAndroid Build Coastguard Worker 			  machine.sanitize (c)));
391*2d1272b8SAndroid Build Coastguard Worker   }
392*2d1272b8SAndroid Build Coastguard Worker 
393*2d1272b8SAndroid Build Coastguard Worker   template <typename set_t>
collect_glyphsAAT::KerxSubTableFormat1394*2d1272b8SAndroid Build Coastguard Worker   void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
395*2d1272b8SAndroid Build Coastguard Worker   {
396*2d1272b8SAndroid Build Coastguard Worker     set_t set;
397*2d1272b8SAndroid Build Coastguard Worker     machine.collect_glyphs (set, num_glyphs);
398*2d1272b8SAndroid Build Coastguard Worker     left_set.union_ (set);
399*2d1272b8SAndroid Build Coastguard Worker     right_set.union_ (set);
400*2d1272b8SAndroid Build Coastguard Worker   }
401*2d1272b8SAndroid Build Coastguard Worker 
402*2d1272b8SAndroid Build Coastguard Worker   protected:
403*2d1272b8SAndroid Build Coastguard Worker   KernSubTableHeader				header;
404*2d1272b8SAndroid Build Coastguard Worker   StateTable<Types, EntryData>			machine;
405*2d1272b8SAndroid Build Coastguard Worker   NNOffsetTo<UnsizedArrayOf<FWORD>, HBUINT>	kernAction;
406*2d1272b8SAndroid Build Coastguard Worker   public:
407*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + (StateTable<Types, EntryData>::static_size + HBUINT::static_size));
408*2d1272b8SAndroid Build Coastguard Worker };
409*2d1272b8SAndroid Build Coastguard Worker 
410*2d1272b8SAndroid Build Coastguard Worker template <typename KernSubTableHeader>
411*2d1272b8SAndroid Build Coastguard Worker struct KerxSubTableFormat2
412*2d1272b8SAndroid Build Coastguard Worker {
413*2d1272b8SAndroid Build Coastguard Worker   typedef typename KernSubTableHeader::Types Types;
414*2d1272b8SAndroid Build Coastguard Worker   typedef typename Types::HBUINT HBUINT;
415*2d1272b8SAndroid Build Coastguard Worker 
get_kerningAAT::KerxSubTableFormat2416*2d1272b8SAndroid Build Coastguard Worker   int get_kerning (hb_codepoint_t left, hb_codepoint_t right,
417*2d1272b8SAndroid Build Coastguard Worker 		   hb_aat_apply_context_t *c) const
418*2d1272b8SAndroid Build Coastguard Worker   {
419*2d1272b8SAndroid Build Coastguard Worker     unsigned int num_glyphs = c->sanitizer.get_num_glyphs ();
420*2d1272b8SAndroid Build Coastguard Worker     unsigned int l = (this+leftClassTable).get_class (left, num_glyphs, 0);
421*2d1272b8SAndroid Build Coastguard Worker     unsigned int r = (this+rightClassTable).get_class (right, num_glyphs, 0);
422*2d1272b8SAndroid Build Coastguard Worker 
423*2d1272b8SAndroid Build Coastguard Worker     const UnsizedArrayOf<FWORD> &arrayZ = this+array;
424*2d1272b8SAndroid Build Coastguard Worker     unsigned int kern_idx = l + r;
425*2d1272b8SAndroid Build Coastguard Worker     kern_idx = Types::offsetToIndex (kern_idx, this, arrayZ.arrayZ);
426*2d1272b8SAndroid Build Coastguard Worker     const FWORD *v = &arrayZ[kern_idx];
427*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!v->sanitize (&c->sanitizer))) return 0;
428*2d1272b8SAndroid Build Coastguard Worker     hb_barrier ();
429*2d1272b8SAndroid Build Coastguard Worker 
430*2d1272b8SAndroid Build Coastguard Worker     return kerxTupleKern (*v, header.tuple_count (), this, c);
431*2d1272b8SAndroid Build Coastguard Worker   }
432*2d1272b8SAndroid Build Coastguard Worker 
applyAAT::KerxSubTableFormat2433*2d1272b8SAndroid Build Coastguard Worker   bool apply (hb_aat_apply_context_t *c) const
434*2d1272b8SAndroid Build Coastguard Worker   {
435*2d1272b8SAndroid Build Coastguard Worker     TRACE_APPLY (this);
436*2d1272b8SAndroid Build Coastguard Worker 
437*2d1272b8SAndroid Build Coastguard Worker     if (!c->plan->requested_kerning)
438*2d1272b8SAndroid Build Coastguard Worker       return_trace (false);
439*2d1272b8SAndroid Build Coastguard Worker 
440*2d1272b8SAndroid Build Coastguard Worker     if (header.coverage & header.Backwards)
441*2d1272b8SAndroid Build Coastguard Worker       return_trace (false);
442*2d1272b8SAndroid Build Coastguard Worker 
443*2d1272b8SAndroid Build Coastguard Worker     if (!(c->buffer_digest.may_have (c->left_set) &&
444*2d1272b8SAndroid Build Coastguard Worker 	  c->buffer_digest.may_have (c->right_set)))
445*2d1272b8SAndroid Build Coastguard Worker       return_trace (false);
446*2d1272b8SAndroid Build Coastguard Worker 
447*2d1272b8SAndroid Build Coastguard Worker     accelerator_t accel (*this, c);
448*2d1272b8SAndroid Build Coastguard Worker     hb_kern_machine_t<accelerator_t> machine (accel, header.coverage & header.CrossStream);
449*2d1272b8SAndroid Build Coastguard Worker     machine.kern (c->font, c->buffer, c->plan->kern_mask);
450*2d1272b8SAndroid Build Coastguard Worker 
451*2d1272b8SAndroid Build Coastguard Worker     return_trace (true);
452*2d1272b8SAndroid Build Coastguard Worker   }
453*2d1272b8SAndroid Build Coastguard Worker 
454*2d1272b8SAndroid Build Coastguard Worker   template <typename set_t>
collect_glyphsAAT::KerxSubTableFormat2455*2d1272b8SAndroid Build Coastguard Worker   void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
456*2d1272b8SAndroid Build Coastguard Worker   {
457*2d1272b8SAndroid Build Coastguard Worker     (this+leftClassTable).collect_glyphs (left_set, num_glyphs);
458*2d1272b8SAndroid Build Coastguard Worker     (this+rightClassTable).collect_glyphs (right_set, num_glyphs);
459*2d1272b8SAndroid Build Coastguard Worker   }
460*2d1272b8SAndroid Build Coastguard Worker 
461*2d1272b8SAndroid Build Coastguard Worker   struct accelerator_t
462*2d1272b8SAndroid Build Coastguard Worker   {
463*2d1272b8SAndroid Build Coastguard Worker     const KerxSubTableFormat2 &table;
464*2d1272b8SAndroid Build Coastguard Worker     hb_aat_apply_context_t *c;
465*2d1272b8SAndroid Build Coastguard Worker 
accelerator_tAAT::KerxSubTableFormat2::accelerator_t466*2d1272b8SAndroid Build Coastguard Worker     accelerator_t (const KerxSubTableFormat2 &table_,
467*2d1272b8SAndroid Build Coastguard Worker 		   hb_aat_apply_context_t *c_) :
468*2d1272b8SAndroid Build Coastguard Worker 		     table (table_), c (c_) {}
469*2d1272b8SAndroid Build Coastguard Worker 
get_kerningAAT::KerxSubTableFormat2::accelerator_t470*2d1272b8SAndroid Build Coastguard Worker     int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
471*2d1272b8SAndroid Build Coastguard Worker     {
472*2d1272b8SAndroid Build Coastguard Worker       if (!c->left_set[left] || !c->right_set[right]) return 0;
473*2d1272b8SAndroid Build Coastguard Worker       return table.get_kerning (left, right, c);
474*2d1272b8SAndroid Build Coastguard Worker     }
475*2d1272b8SAndroid Build Coastguard Worker   };
476*2d1272b8SAndroid Build Coastguard Worker 
sanitizeAAT::KerxSubTableFormat2477*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
478*2d1272b8SAndroid Build Coastguard Worker   {
479*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
480*2d1272b8SAndroid Build Coastguard Worker     return_trace (likely (c->check_struct (this) &&
481*2d1272b8SAndroid Build Coastguard Worker 			  leftClassTable.sanitize (c, this) &&
482*2d1272b8SAndroid Build Coastguard Worker 			  rightClassTable.sanitize (c, this) &&
483*2d1272b8SAndroid Build Coastguard Worker 			  hb_barrier () &&
484*2d1272b8SAndroid Build Coastguard Worker 			  c->check_range (this, array)));
485*2d1272b8SAndroid Build Coastguard Worker   }
486*2d1272b8SAndroid Build Coastguard Worker 
487*2d1272b8SAndroid Build Coastguard Worker   protected:
488*2d1272b8SAndroid Build Coastguard Worker   KernSubTableHeader	header;
489*2d1272b8SAndroid Build Coastguard Worker   HBUINT		rowWidth;	/* The width, in bytes, of a row in the table. */
490*2d1272b8SAndroid Build Coastguard Worker   NNOffsetTo<typename Types::ClassTypeWide, HBUINT>
491*2d1272b8SAndroid Build Coastguard Worker 			leftClassTable;	/* Offset from beginning of this subtable to
492*2d1272b8SAndroid Build Coastguard Worker 					 * left-hand class table. */
493*2d1272b8SAndroid Build Coastguard Worker   NNOffsetTo<typename Types::ClassTypeWide, HBUINT>
494*2d1272b8SAndroid Build Coastguard Worker 			rightClassTable;/* Offset from beginning of this subtable to
495*2d1272b8SAndroid Build Coastguard Worker 					 * right-hand class table. */
496*2d1272b8SAndroid Build Coastguard Worker   NNOffsetTo<UnsizedArrayOf<FWORD>, HBUINT>
497*2d1272b8SAndroid Build Coastguard Worker 			 array;		/* Offset from beginning of this subtable to
498*2d1272b8SAndroid Build Coastguard Worker 					 * the start of the kerning array. */
499*2d1272b8SAndroid Build Coastguard Worker   public:
500*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 4 * sizeof (HBUINT));
501*2d1272b8SAndroid Build Coastguard Worker };
502*2d1272b8SAndroid Build Coastguard Worker 
503*2d1272b8SAndroid Build Coastguard Worker template <typename KernSubTableHeader>
504*2d1272b8SAndroid Build Coastguard Worker struct KerxSubTableFormat4
505*2d1272b8SAndroid Build Coastguard Worker {
506*2d1272b8SAndroid Build Coastguard Worker   typedef ExtendedTypes Types;
507*2d1272b8SAndroid Build Coastguard Worker 
508*2d1272b8SAndroid Build Coastguard Worker   struct EntryData
509*2d1272b8SAndroid Build Coastguard Worker   {
510*2d1272b8SAndroid Build Coastguard Worker     HBUINT16	ankrActionIndex;/* Either 0xFFFF (for no action) or the index of
511*2d1272b8SAndroid Build Coastguard Worker 				 * the action to perform. */
512*2d1272b8SAndroid Build Coastguard Worker     public:
513*2d1272b8SAndroid Build Coastguard Worker     DEFINE_SIZE_STATIC (2);
514*2d1272b8SAndroid Build Coastguard Worker   };
515*2d1272b8SAndroid Build Coastguard Worker 
516*2d1272b8SAndroid Build Coastguard Worker   struct driver_context_t
517*2d1272b8SAndroid Build Coastguard Worker   {
518*2d1272b8SAndroid Build Coastguard Worker     static constexpr bool in_place = true;
519*2d1272b8SAndroid Build Coastguard Worker     enum Flags
520*2d1272b8SAndroid Build Coastguard Worker     {
521*2d1272b8SAndroid Build Coastguard Worker       Mark		= 0x8000,	/* If set, remember this glyph as the marked glyph. */
522*2d1272b8SAndroid Build Coastguard Worker       DontAdvance	= 0x4000,	/* If set, don't advance to the next glyph before
523*2d1272b8SAndroid Build Coastguard Worker 					 * going to the new state. */
524*2d1272b8SAndroid Build Coastguard Worker       Reserved		= 0x3FFF,	/* Not used; set to 0. */
525*2d1272b8SAndroid Build Coastguard Worker     };
526*2d1272b8SAndroid Build Coastguard Worker 
527*2d1272b8SAndroid Build Coastguard Worker     enum SubTableFlags
528*2d1272b8SAndroid Build Coastguard Worker     {
529*2d1272b8SAndroid Build Coastguard Worker       ActionType	= 0xC0000000,	/* A two-bit field containing the action type. */
530*2d1272b8SAndroid Build Coastguard Worker       Unused		= 0x3F000000,	/* Unused - must be zero. */
531*2d1272b8SAndroid Build Coastguard Worker       Offset		= 0x00FFFFFF,	/* Masks the offset in bytes from the beginning
532*2d1272b8SAndroid Build Coastguard Worker 					 * of the subtable to the beginning of the control
533*2d1272b8SAndroid Build Coastguard Worker 					 * point table. */
534*2d1272b8SAndroid Build Coastguard Worker     };
535*2d1272b8SAndroid Build Coastguard Worker 
driver_context_tAAT::KerxSubTableFormat4::driver_context_t536*2d1272b8SAndroid Build Coastguard Worker     driver_context_t (const KerxSubTableFormat4 *table,
537*2d1272b8SAndroid Build Coastguard Worker 		      hb_aat_apply_context_t *c_) :
538*2d1272b8SAndroid Build Coastguard Worker 	c (c_),
539*2d1272b8SAndroid Build Coastguard Worker 	action_type ((table->flags & ActionType) >> 30),
540*2d1272b8SAndroid Build Coastguard Worker 	ankrData ((HBUINT16 *) ((const char *) &table->machine + (table->flags & Offset))),
541*2d1272b8SAndroid Build Coastguard Worker 	mark_set (false),
542*2d1272b8SAndroid Build Coastguard Worker 	mark (0) {}
543*2d1272b8SAndroid Build Coastguard Worker 
is_actionableAAT::KerxSubTableFormat4::driver_context_t544*2d1272b8SAndroid Build Coastguard Worker     bool is_actionable (hb_buffer_t *buffer HB_UNUSED,
545*2d1272b8SAndroid Build Coastguard Worker 			StateTableDriver<Types, EntryData> *driver HB_UNUSED,
546*2d1272b8SAndroid Build Coastguard Worker 			const Entry<EntryData> &entry)
547*2d1272b8SAndroid Build Coastguard Worker     { return entry.data.ankrActionIndex != 0xFFFF; }
transitionAAT::KerxSubTableFormat4::driver_context_t548*2d1272b8SAndroid Build Coastguard Worker     void transition (hb_buffer_t *buffer,
549*2d1272b8SAndroid Build Coastguard Worker 		     StateTableDriver<Types, EntryData> *driver,
550*2d1272b8SAndroid Build Coastguard Worker 		     const Entry<EntryData> &entry)
551*2d1272b8SAndroid Build Coastguard Worker     {
552*2d1272b8SAndroid Build Coastguard Worker       if (mark_set && entry.data.ankrActionIndex != 0xFFFF && buffer->idx < buffer->len)
553*2d1272b8SAndroid Build Coastguard Worker       {
554*2d1272b8SAndroid Build Coastguard Worker 	hb_glyph_position_t &o = buffer->cur_pos();
555*2d1272b8SAndroid Build Coastguard Worker 	switch (action_type)
556*2d1272b8SAndroid Build Coastguard Worker 	{
557*2d1272b8SAndroid Build Coastguard Worker 	  case 0: /* Control Point Actions.*/
558*2d1272b8SAndroid Build Coastguard Worker 	  {
559*2d1272b8SAndroid Build Coastguard Worker 	    /* Indexed into glyph outline. */
560*2d1272b8SAndroid Build Coastguard Worker 	    /* Each action (record in ankrData) contains two 16-bit fields, so we must
561*2d1272b8SAndroid Build Coastguard Worker 	       double the ankrActionIndex to get the correct offset here. */
562*2d1272b8SAndroid Build Coastguard Worker 	    const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex * 2];
563*2d1272b8SAndroid Build Coastguard Worker 	    if (!c->sanitizer.check_array (data, 2)) return;
564*2d1272b8SAndroid Build Coastguard Worker 	    hb_barrier ();
565*2d1272b8SAndroid Build Coastguard Worker 	    unsigned int markControlPoint = *data++;
566*2d1272b8SAndroid Build Coastguard Worker 	    unsigned int currControlPoint = *data++;
567*2d1272b8SAndroid Build Coastguard Worker 	    hb_position_t markX = 0;
568*2d1272b8SAndroid Build Coastguard Worker 	    hb_position_t markY = 0;
569*2d1272b8SAndroid Build Coastguard Worker 	    hb_position_t currX = 0;
570*2d1272b8SAndroid Build Coastguard Worker 	    hb_position_t currY = 0;
571*2d1272b8SAndroid Build Coastguard Worker 	    if (!c->font->get_glyph_contour_point_for_origin (c->buffer->info[mark].codepoint,
572*2d1272b8SAndroid Build Coastguard Worker 							      markControlPoint,
573*2d1272b8SAndroid Build Coastguard Worker 							      HB_DIRECTION_LTR /*XXX*/,
574*2d1272b8SAndroid Build Coastguard Worker 							      &markX, &markY) ||
575*2d1272b8SAndroid Build Coastguard Worker 		!c->font->get_glyph_contour_point_for_origin (c->buffer->cur ().codepoint,
576*2d1272b8SAndroid Build Coastguard Worker 							      currControlPoint,
577*2d1272b8SAndroid Build Coastguard Worker 							      HB_DIRECTION_LTR /*XXX*/,
578*2d1272b8SAndroid Build Coastguard Worker 							      &currX, &currY))
579*2d1272b8SAndroid Build Coastguard Worker 	      return;
580*2d1272b8SAndroid Build Coastguard Worker 
581*2d1272b8SAndroid Build Coastguard Worker 	    o.x_offset = markX - currX;
582*2d1272b8SAndroid Build Coastguard Worker 	    o.y_offset = markY - currY;
583*2d1272b8SAndroid Build Coastguard Worker 	  }
584*2d1272b8SAndroid Build Coastguard Worker 	  break;
585*2d1272b8SAndroid Build Coastguard Worker 
586*2d1272b8SAndroid Build Coastguard Worker 	  case 1: /* Anchor Point Actions. */
587*2d1272b8SAndroid Build Coastguard Worker 	  {
588*2d1272b8SAndroid Build Coastguard Worker 	    /* Indexed into 'ankr' table. */
589*2d1272b8SAndroid Build Coastguard Worker 	    /* Each action (record in ankrData) contains two 16-bit fields, so we must
590*2d1272b8SAndroid Build Coastguard Worker 	       double the ankrActionIndex to get the correct offset here. */
591*2d1272b8SAndroid Build Coastguard Worker 	    const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex * 2];
592*2d1272b8SAndroid Build Coastguard Worker 	    if (!c->sanitizer.check_array (data, 2)) return;
593*2d1272b8SAndroid Build Coastguard Worker 	    hb_barrier ();
594*2d1272b8SAndroid Build Coastguard Worker 	    unsigned int markAnchorPoint = *data++;
595*2d1272b8SAndroid Build Coastguard Worker 	    unsigned int currAnchorPoint = *data++;
596*2d1272b8SAndroid Build Coastguard Worker 	    const Anchor &markAnchor = c->ankr_table->get_anchor (c->buffer->info[mark].codepoint,
597*2d1272b8SAndroid Build Coastguard Worker 								  markAnchorPoint,
598*2d1272b8SAndroid Build Coastguard Worker 								  c->sanitizer.get_num_glyphs ());
599*2d1272b8SAndroid Build Coastguard Worker 	    const Anchor &currAnchor = c->ankr_table->get_anchor (c->buffer->cur ().codepoint,
600*2d1272b8SAndroid Build Coastguard Worker 								  currAnchorPoint,
601*2d1272b8SAndroid Build Coastguard Worker 								  c->sanitizer.get_num_glyphs ());
602*2d1272b8SAndroid Build Coastguard Worker 
603*2d1272b8SAndroid Build Coastguard Worker 	    o.x_offset = c->font->em_scale_x (markAnchor.xCoordinate) - c->font->em_scale_x (currAnchor.xCoordinate);
604*2d1272b8SAndroid Build Coastguard Worker 	    o.y_offset = c->font->em_scale_y (markAnchor.yCoordinate) - c->font->em_scale_y (currAnchor.yCoordinate);
605*2d1272b8SAndroid Build Coastguard Worker 	  }
606*2d1272b8SAndroid Build Coastguard Worker 	  break;
607*2d1272b8SAndroid Build Coastguard Worker 
608*2d1272b8SAndroid Build Coastguard Worker 	  case 2: /* Control Point Coordinate Actions. */
609*2d1272b8SAndroid Build Coastguard Worker 	  {
610*2d1272b8SAndroid Build Coastguard Worker 	    /* Each action contains four 16-bit fields, so we multiply the ankrActionIndex
611*2d1272b8SAndroid Build Coastguard Worker 	       by 4 to get the correct offset for the given action. */
612*2d1272b8SAndroid Build Coastguard Worker 	    const FWORD *data = (const FWORD *) &ankrData[entry.data.ankrActionIndex * 4];
613*2d1272b8SAndroid Build Coastguard Worker 	    if (!c->sanitizer.check_array (data, 4)) return;
614*2d1272b8SAndroid Build Coastguard Worker 	    hb_barrier ();
615*2d1272b8SAndroid Build Coastguard Worker 	    int markX = *data++;
616*2d1272b8SAndroid Build Coastguard Worker 	    int markY = *data++;
617*2d1272b8SAndroid Build Coastguard Worker 	    int currX = *data++;
618*2d1272b8SAndroid Build Coastguard Worker 	    int currY = *data++;
619*2d1272b8SAndroid Build Coastguard Worker 
620*2d1272b8SAndroid Build Coastguard Worker 	    o.x_offset = c->font->em_scale_x (markX) - c->font->em_scale_x (currX);
621*2d1272b8SAndroid Build Coastguard Worker 	    o.y_offset = c->font->em_scale_y (markY) - c->font->em_scale_y (currY);
622*2d1272b8SAndroid Build Coastguard Worker 	  }
623*2d1272b8SAndroid Build Coastguard Worker 	  break;
624*2d1272b8SAndroid Build Coastguard Worker 	}
625*2d1272b8SAndroid Build Coastguard Worker 	o.attach_type() = OT::Layout::GPOS_impl::ATTACH_TYPE_MARK;
626*2d1272b8SAndroid Build Coastguard Worker 	o.attach_chain() = (int) mark - (int) buffer->idx;
627*2d1272b8SAndroid Build Coastguard Worker 	buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
628*2d1272b8SAndroid Build Coastguard Worker       }
629*2d1272b8SAndroid Build Coastguard Worker 
630*2d1272b8SAndroid Build Coastguard Worker       if (entry.flags & Mark)
631*2d1272b8SAndroid Build Coastguard Worker       {
632*2d1272b8SAndroid Build Coastguard Worker 	mark_set = true;
633*2d1272b8SAndroid Build Coastguard Worker 	mark = buffer->idx;
634*2d1272b8SAndroid Build Coastguard Worker       }
635*2d1272b8SAndroid Build Coastguard Worker     }
636*2d1272b8SAndroid Build Coastguard Worker 
637*2d1272b8SAndroid Build Coastguard Worker     private:
638*2d1272b8SAndroid Build Coastguard Worker     hb_aat_apply_context_t *c;
639*2d1272b8SAndroid Build Coastguard Worker     unsigned int action_type;
640*2d1272b8SAndroid Build Coastguard Worker     const HBUINT16 *ankrData;
641*2d1272b8SAndroid Build Coastguard Worker     bool mark_set;
642*2d1272b8SAndroid Build Coastguard Worker     unsigned int mark;
643*2d1272b8SAndroid Build Coastguard Worker   };
644*2d1272b8SAndroid Build Coastguard Worker 
applyAAT::KerxSubTableFormat4645*2d1272b8SAndroid Build Coastguard Worker   bool apply (hb_aat_apply_context_t *c) const
646*2d1272b8SAndroid Build Coastguard Worker   {
647*2d1272b8SAndroid Build Coastguard Worker     TRACE_APPLY (this);
648*2d1272b8SAndroid Build Coastguard Worker 
649*2d1272b8SAndroid Build Coastguard Worker     driver_context_t dc (this, c);
650*2d1272b8SAndroid Build Coastguard Worker 
651*2d1272b8SAndroid Build Coastguard Worker     StateTableDriver<Types, EntryData> driver (machine, c->font->face);
652*2d1272b8SAndroid Build Coastguard Worker 
653*2d1272b8SAndroid Build Coastguard Worker     if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) &&
654*2d1272b8SAndroid Build Coastguard Worker 	!(c->buffer_digest.may_have (c->left_set) &&
655*2d1272b8SAndroid Build Coastguard Worker 	  c->buffer_digest.may_have (c->right_set)))
656*2d1272b8SAndroid Build Coastguard Worker       return_trace (false);
657*2d1272b8SAndroid Build Coastguard Worker 
658*2d1272b8SAndroid Build Coastguard Worker     driver.drive (&dc, c);
659*2d1272b8SAndroid Build Coastguard Worker 
660*2d1272b8SAndroid Build Coastguard Worker     return_trace (true);
661*2d1272b8SAndroid Build Coastguard Worker   }
662*2d1272b8SAndroid Build Coastguard Worker 
sanitizeAAT::KerxSubTableFormat4663*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
664*2d1272b8SAndroid Build Coastguard Worker   {
665*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
666*2d1272b8SAndroid Build Coastguard Worker     /* The rest of array sanitizations are done at run-time. */
667*2d1272b8SAndroid Build Coastguard Worker     return_trace (likely (c->check_struct (this) &&
668*2d1272b8SAndroid Build Coastguard Worker 			  machine.sanitize (c)));
669*2d1272b8SAndroid Build Coastguard Worker   }
670*2d1272b8SAndroid Build Coastguard Worker 
671*2d1272b8SAndroid Build Coastguard Worker   template <typename set_t>
collect_glyphsAAT::KerxSubTableFormat4672*2d1272b8SAndroid Build Coastguard Worker   void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
673*2d1272b8SAndroid Build Coastguard Worker   {
674*2d1272b8SAndroid Build Coastguard Worker     set_t set;
675*2d1272b8SAndroid Build Coastguard Worker     machine.collect_glyphs (set, num_glyphs);
676*2d1272b8SAndroid Build Coastguard Worker     left_set.union_ (set);
677*2d1272b8SAndroid Build Coastguard Worker     right_set.union_ (set);
678*2d1272b8SAndroid Build Coastguard Worker   }
679*2d1272b8SAndroid Build Coastguard Worker 
680*2d1272b8SAndroid Build Coastguard Worker   protected:
681*2d1272b8SAndroid Build Coastguard Worker   KernSubTableHeader		header;
682*2d1272b8SAndroid Build Coastguard Worker   StateTable<Types, EntryData>	machine;
683*2d1272b8SAndroid Build Coastguard Worker   HBUINT32			flags;
684*2d1272b8SAndroid Build Coastguard Worker   public:
685*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + (StateTable<Types, EntryData>::static_size + HBUINT32::static_size));
686*2d1272b8SAndroid Build Coastguard Worker };
687*2d1272b8SAndroid Build Coastguard Worker 
688*2d1272b8SAndroid Build Coastguard Worker template <typename KernSubTableHeader>
689*2d1272b8SAndroid Build Coastguard Worker struct KerxSubTableFormat6
690*2d1272b8SAndroid Build Coastguard Worker {
691*2d1272b8SAndroid Build Coastguard Worker   enum Flags
692*2d1272b8SAndroid Build Coastguard Worker   {
693*2d1272b8SAndroid Build Coastguard Worker     ValuesAreLong	= 0x00000001,
694*2d1272b8SAndroid Build Coastguard Worker   };
695*2d1272b8SAndroid Build Coastguard Worker 
is_longAAT::KerxSubTableFormat6696*2d1272b8SAndroid Build Coastguard Worker   bool is_long () const { return flags & ValuesAreLong; }
697*2d1272b8SAndroid Build Coastguard Worker 
get_kerningAAT::KerxSubTableFormat6698*2d1272b8SAndroid Build Coastguard Worker   int get_kerning (hb_codepoint_t left, hb_codepoint_t right,
699*2d1272b8SAndroid Build Coastguard Worker 		   hb_aat_apply_context_t *c) const
700*2d1272b8SAndroid Build Coastguard Worker   {
701*2d1272b8SAndroid Build Coastguard Worker     unsigned int num_glyphs = c->sanitizer.get_num_glyphs ();
702*2d1272b8SAndroid Build Coastguard Worker     if (is_long ())
703*2d1272b8SAndroid Build Coastguard Worker     {
704*2d1272b8SAndroid Build Coastguard Worker       const auto &t = u.l;
705*2d1272b8SAndroid Build Coastguard Worker       unsigned int l = (this+t.rowIndexTable).get_value_or_null (left, num_glyphs);
706*2d1272b8SAndroid Build Coastguard Worker       unsigned int r = (this+t.columnIndexTable).get_value_or_null (right, num_glyphs);
707*2d1272b8SAndroid Build Coastguard Worker       unsigned int offset = l + r;
708*2d1272b8SAndroid Build Coastguard Worker       if (unlikely (offset < l)) return 0; /* Addition overflow. */
709*2d1272b8SAndroid Build Coastguard Worker       if (unlikely (hb_unsigned_mul_overflows (offset, sizeof (FWORD32)))) return 0;
710*2d1272b8SAndroid Build Coastguard Worker       const FWORD32 *v = &StructAtOffset<FWORD32> (&(this+t.array), offset * sizeof (FWORD32));
711*2d1272b8SAndroid Build Coastguard Worker       if (unlikely (!v->sanitize (&c->sanitizer))) return 0;
712*2d1272b8SAndroid Build Coastguard Worker       hb_barrier ();
713*2d1272b8SAndroid Build Coastguard Worker       return kerxTupleKern (*v, header.tuple_count (), &(this+vector), c);
714*2d1272b8SAndroid Build Coastguard Worker     }
715*2d1272b8SAndroid Build Coastguard Worker     else
716*2d1272b8SAndroid Build Coastguard Worker     {
717*2d1272b8SAndroid Build Coastguard Worker       const auto &t = u.s;
718*2d1272b8SAndroid Build Coastguard Worker       unsigned int l = (this+t.rowIndexTable).get_value_or_null (left, num_glyphs);
719*2d1272b8SAndroid Build Coastguard Worker       unsigned int r = (this+t.columnIndexTable).get_value_or_null (right, num_glyphs);
720*2d1272b8SAndroid Build Coastguard Worker       unsigned int offset = l + r;
721*2d1272b8SAndroid Build Coastguard Worker       const FWORD *v = &StructAtOffset<FWORD> (&(this+t.array), offset * sizeof (FWORD));
722*2d1272b8SAndroid Build Coastguard Worker       if (unlikely (!v->sanitize (&c->sanitizer))) return 0;
723*2d1272b8SAndroid Build Coastguard Worker       hb_barrier ();
724*2d1272b8SAndroid Build Coastguard Worker       return kerxTupleKern (*v, header.tuple_count (), &(this+vector), c);
725*2d1272b8SAndroid Build Coastguard Worker     }
726*2d1272b8SAndroid Build Coastguard Worker   }
727*2d1272b8SAndroid Build Coastguard Worker 
applyAAT::KerxSubTableFormat6728*2d1272b8SAndroid Build Coastguard Worker   bool apply (hb_aat_apply_context_t *c) const
729*2d1272b8SAndroid Build Coastguard Worker   {
730*2d1272b8SAndroid Build Coastguard Worker     TRACE_APPLY (this);
731*2d1272b8SAndroid Build Coastguard Worker 
732*2d1272b8SAndroid Build Coastguard Worker     if (!c->plan->requested_kerning)
733*2d1272b8SAndroid Build Coastguard Worker       return_trace (false);
734*2d1272b8SAndroid Build Coastguard Worker 
735*2d1272b8SAndroid Build Coastguard Worker     if (header.coverage & header.Backwards)
736*2d1272b8SAndroid Build Coastguard Worker       return_trace (false);
737*2d1272b8SAndroid Build Coastguard Worker 
738*2d1272b8SAndroid Build Coastguard Worker     if (!(c->buffer_digest.may_have (c->left_set) &&
739*2d1272b8SAndroid Build Coastguard Worker 	  c->buffer_digest.may_have (c->right_set)))
740*2d1272b8SAndroid Build Coastguard Worker       return_trace (false);
741*2d1272b8SAndroid Build Coastguard Worker 
742*2d1272b8SAndroid Build Coastguard Worker     accelerator_t accel (*this, c);
743*2d1272b8SAndroid Build Coastguard Worker     hb_kern_machine_t<accelerator_t> machine (accel, header.coverage & header.CrossStream);
744*2d1272b8SAndroid Build Coastguard Worker     machine.kern (c->font, c->buffer, c->plan->kern_mask);
745*2d1272b8SAndroid Build Coastguard Worker 
746*2d1272b8SAndroid Build Coastguard Worker     return_trace (true);
747*2d1272b8SAndroid Build Coastguard Worker   }
748*2d1272b8SAndroid Build Coastguard Worker 
sanitizeAAT::KerxSubTableFormat6749*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
750*2d1272b8SAndroid Build Coastguard Worker   {
751*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
752*2d1272b8SAndroid Build Coastguard Worker     return_trace (likely (c->check_struct (this) &&
753*2d1272b8SAndroid Build Coastguard Worker 			  hb_barrier () &&
754*2d1272b8SAndroid Build Coastguard Worker 			  (is_long () ?
755*2d1272b8SAndroid Build Coastguard Worker 			   (
756*2d1272b8SAndroid Build Coastguard Worker 			     u.l.rowIndexTable.sanitize (c, this) &&
757*2d1272b8SAndroid Build Coastguard Worker 			     u.l.columnIndexTable.sanitize (c, this) &&
758*2d1272b8SAndroid Build Coastguard Worker 			     c->check_range (this, u.l.array)
759*2d1272b8SAndroid Build Coastguard Worker 			   ) : (
760*2d1272b8SAndroid Build Coastguard Worker 			     u.s.rowIndexTable.sanitize (c, this) &&
761*2d1272b8SAndroid Build Coastguard Worker 			     u.s.columnIndexTable.sanitize (c, this) &&
762*2d1272b8SAndroid Build Coastguard Worker 			     c->check_range (this, u.s.array)
763*2d1272b8SAndroid Build Coastguard Worker 			   )) &&
764*2d1272b8SAndroid Build Coastguard Worker 			  (header.tuple_count () == 0 ||
765*2d1272b8SAndroid Build Coastguard Worker 			   c->check_range (this, vector))));
766*2d1272b8SAndroid Build Coastguard Worker   }
767*2d1272b8SAndroid Build Coastguard Worker 
768*2d1272b8SAndroid Build Coastguard Worker   template <typename set_t>
collect_glyphsAAT::KerxSubTableFormat6769*2d1272b8SAndroid Build Coastguard Worker   void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
770*2d1272b8SAndroid Build Coastguard Worker   {
771*2d1272b8SAndroid Build Coastguard Worker     if (is_long ())
772*2d1272b8SAndroid Build Coastguard Worker     {
773*2d1272b8SAndroid Build Coastguard Worker       const auto &t = u.l;
774*2d1272b8SAndroid Build Coastguard Worker       (this+t.rowIndexTable).collect_glyphs (left_set, num_glyphs);
775*2d1272b8SAndroid Build Coastguard Worker       (this+t.columnIndexTable).collect_glyphs (right_set, num_glyphs);
776*2d1272b8SAndroid Build Coastguard Worker     }
777*2d1272b8SAndroid Build Coastguard Worker     else
778*2d1272b8SAndroid Build Coastguard Worker     {
779*2d1272b8SAndroid Build Coastguard Worker       const auto &t = u.s;
780*2d1272b8SAndroid Build Coastguard Worker       (this+t.rowIndexTable).collect_glyphs (left_set, num_glyphs);
781*2d1272b8SAndroid Build Coastguard Worker       (this+t.columnIndexTable).collect_glyphs (right_set, num_glyphs);
782*2d1272b8SAndroid Build Coastguard Worker     }
783*2d1272b8SAndroid Build Coastguard Worker   }
784*2d1272b8SAndroid Build Coastguard Worker 
785*2d1272b8SAndroid Build Coastguard Worker   struct accelerator_t
786*2d1272b8SAndroid Build Coastguard Worker   {
787*2d1272b8SAndroid Build Coastguard Worker     const KerxSubTableFormat6 &table;
788*2d1272b8SAndroid Build Coastguard Worker     hb_aat_apply_context_t *c;
789*2d1272b8SAndroid Build Coastguard Worker 
accelerator_tAAT::KerxSubTableFormat6::accelerator_t790*2d1272b8SAndroid Build Coastguard Worker     accelerator_t (const KerxSubTableFormat6 &table_,
791*2d1272b8SAndroid Build Coastguard Worker 		   hb_aat_apply_context_t *c_) :
792*2d1272b8SAndroid Build Coastguard Worker 		     table (table_), c (c_) {}
793*2d1272b8SAndroid Build Coastguard Worker 
get_kerningAAT::KerxSubTableFormat6::accelerator_t794*2d1272b8SAndroid Build Coastguard Worker     int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
795*2d1272b8SAndroid Build Coastguard Worker     {
796*2d1272b8SAndroid Build Coastguard Worker       if (!c->left_set[left] || !c->right_set[right]) return 0;
797*2d1272b8SAndroid Build Coastguard Worker       return table.get_kerning (left, right, c);
798*2d1272b8SAndroid Build Coastguard Worker     }
799*2d1272b8SAndroid Build Coastguard Worker   };
800*2d1272b8SAndroid Build Coastguard Worker 
801*2d1272b8SAndroid Build Coastguard Worker   protected:
802*2d1272b8SAndroid Build Coastguard Worker   KernSubTableHeader		header;
803*2d1272b8SAndroid Build Coastguard Worker   HBUINT32			flags;
804*2d1272b8SAndroid Build Coastguard Worker   HBUINT16			rowCount;
805*2d1272b8SAndroid Build Coastguard Worker   HBUINT16			columnCount;
806*2d1272b8SAndroid Build Coastguard Worker   union U
807*2d1272b8SAndroid Build Coastguard Worker   {
808*2d1272b8SAndroid Build Coastguard Worker     struct Long
809*2d1272b8SAndroid Build Coastguard Worker     {
810*2d1272b8SAndroid Build Coastguard Worker       NNOffset32To<Lookup<HBUINT32>>		rowIndexTable;
811*2d1272b8SAndroid Build Coastguard Worker       NNOffset32To<Lookup<HBUINT32>>		columnIndexTable;
812*2d1272b8SAndroid Build Coastguard Worker       NNOffset32To<UnsizedArrayOf<FWORD32>>	array;
813*2d1272b8SAndroid Build Coastguard Worker     } l;
814*2d1272b8SAndroid Build Coastguard Worker     struct Short
815*2d1272b8SAndroid Build Coastguard Worker     {
816*2d1272b8SAndroid Build Coastguard Worker       NNOffset32To<Lookup<HBUINT16>>		rowIndexTable;
817*2d1272b8SAndroid Build Coastguard Worker       NNOffset32To<Lookup<HBUINT16>>		columnIndexTable;
818*2d1272b8SAndroid Build Coastguard Worker       NNOffset32To<UnsizedArrayOf<FWORD>>	array;
819*2d1272b8SAndroid Build Coastguard Worker     } s;
820*2d1272b8SAndroid Build Coastguard Worker   } u;
821*2d1272b8SAndroid Build Coastguard Worker   NNOffset32To<UnsizedArrayOf<FWORD>>	vector;
822*2d1272b8SAndroid Build Coastguard Worker   public:
823*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 24);
824*2d1272b8SAndroid Build Coastguard Worker };
825*2d1272b8SAndroid Build Coastguard Worker 
826*2d1272b8SAndroid Build Coastguard Worker 
827*2d1272b8SAndroid Build Coastguard Worker struct KerxSubTableHeader
828*2d1272b8SAndroid Build Coastguard Worker {
829*2d1272b8SAndroid Build Coastguard Worker   typedef ExtendedTypes Types;
830*2d1272b8SAndroid Build Coastguard Worker 
tuple_countAAT::KerxSubTableHeader831*2d1272b8SAndroid Build Coastguard Worker   unsigned   tuple_count () const { return tupleCount; }
is_horizontalAAT::KerxSubTableHeader832*2d1272b8SAndroid Build Coastguard Worker   bool     is_horizontal () const { return !(coverage & Vertical); }
833*2d1272b8SAndroid Build Coastguard Worker 
834*2d1272b8SAndroid Build Coastguard Worker   enum Coverage
835*2d1272b8SAndroid Build Coastguard Worker   {
836*2d1272b8SAndroid Build Coastguard Worker     Vertical	= 0x80000000u,	/* Set if table has vertical kerning values. */
837*2d1272b8SAndroid Build Coastguard Worker     CrossStream	= 0x40000000u,	/* Set if table has cross-stream kerning values. */
838*2d1272b8SAndroid Build Coastguard Worker     Variation	= 0x20000000u,	/* Set if table has variation kerning values. */
839*2d1272b8SAndroid Build Coastguard Worker     Backwards	= 0x10000000u,	/* If clear, process the glyphs forwards, that
840*2d1272b8SAndroid Build Coastguard Worker 				 * is, from first to last in the glyph stream.
841*2d1272b8SAndroid Build Coastguard Worker 				 * If we, process them from last to first.
842*2d1272b8SAndroid Build Coastguard Worker 				 * This flag only applies to state-table based
843*2d1272b8SAndroid Build Coastguard Worker 				 * 'kerx' subtables (types 1 and 4). */
844*2d1272b8SAndroid Build Coastguard Worker     Reserved	= 0x0FFFFF00u,	/* Reserved, set to zero. */
845*2d1272b8SAndroid Build Coastguard Worker     SubtableType= 0x000000FFu,	/* Subtable type. */
846*2d1272b8SAndroid Build Coastguard Worker   };
847*2d1272b8SAndroid Build Coastguard Worker 
sanitizeAAT::KerxSubTableHeader848*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
849*2d1272b8SAndroid Build Coastguard Worker   {
850*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
851*2d1272b8SAndroid Build Coastguard Worker     return_trace (c->check_struct (this));
852*2d1272b8SAndroid Build Coastguard Worker   }
853*2d1272b8SAndroid Build Coastguard Worker 
854*2d1272b8SAndroid Build Coastguard Worker   public:
855*2d1272b8SAndroid Build Coastguard Worker   HBUINT32	length;
856*2d1272b8SAndroid Build Coastguard Worker   HBUINT32	coverage;
857*2d1272b8SAndroid Build Coastguard Worker   HBUINT32	tupleCount;
858*2d1272b8SAndroid Build Coastguard Worker   public:
859*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_STATIC (12);
860*2d1272b8SAndroid Build Coastguard Worker };
861*2d1272b8SAndroid Build Coastguard Worker 
862*2d1272b8SAndroid Build Coastguard Worker struct KerxSubTable
863*2d1272b8SAndroid Build Coastguard Worker {
864*2d1272b8SAndroid Build Coastguard Worker   friend struct kerx;
865*2d1272b8SAndroid Build Coastguard Worker 
get_sizeAAT::KerxSubTable866*2d1272b8SAndroid Build Coastguard Worker   unsigned int get_size () const { return u.header.length; }
get_typeAAT::KerxSubTable867*2d1272b8SAndroid Build Coastguard Worker   unsigned int get_type () const { return u.header.coverage & u.header.SubtableType; }
868*2d1272b8SAndroid Build Coastguard Worker 
869*2d1272b8SAndroid Build Coastguard Worker   template <typename context_t, typename ...Ts>
dispatchAAT::KerxSubTable870*2d1272b8SAndroid Build Coastguard Worker   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
871*2d1272b8SAndroid Build Coastguard Worker   {
872*2d1272b8SAndroid Build Coastguard Worker     unsigned int subtable_type = get_type ();
873*2d1272b8SAndroid Build Coastguard Worker     TRACE_DISPATCH (this, subtable_type);
874*2d1272b8SAndroid Build Coastguard Worker     switch (subtable_type) {
875*2d1272b8SAndroid Build Coastguard Worker     case 0:	return_trace (c->dispatch (u.format0, std::forward<Ts> (ds)...));
876*2d1272b8SAndroid Build Coastguard Worker     case 1:	return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
877*2d1272b8SAndroid Build Coastguard Worker     case 2:	return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
878*2d1272b8SAndroid Build Coastguard Worker     case 4:	return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
879*2d1272b8SAndroid Build Coastguard Worker     case 6:	return_trace (c->dispatch (u.format6, std::forward<Ts> (ds)...));
880*2d1272b8SAndroid Build Coastguard Worker     default:	return_trace (c->default_return_value ());
881*2d1272b8SAndroid Build Coastguard Worker     }
882*2d1272b8SAndroid Build Coastguard Worker   }
883*2d1272b8SAndroid Build Coastguard Worker 
884*2d1272b8SAndroid Build Coastguard Worker   template <typename set_t>
collect_glyphsAAT::KerxSubTable885*2d1272b8SAndroid Build Coastguard Worker   void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
886*2d1272b8SAndroid Build Coastguard Worker   {
887*2d1272b8SAndroid Build Coastguard Worker     unsigned int subtable_type = get_type ();
888*2d1272b8SAndroid Build Coastguard Worker     switch (subtable_type) {
889*2d1272b8SAndroid Build Coastguard Worker     case 0:	u.format0.collect_glyphs (left_set, right_set, num_glyphs); return;
890*2d1272b8SAndroid Build Coastguard Worker     case 1:	u.format1.collect_glyphs (left_set, right_set, num_glyphs); return;
891*2d1272b8SAndroid Build Coastguard Worker     case 2:	u.format2.collect_glyphs (left_set, right_set, num_glyphs); return;
892*2d1272b8SAndroid Build Coastguard Worker     case 4:	u.format4.collect_glyphs (left_set, right_set, num_glyphs); return;
893*2d1272b8SAndroid Build Coastguard Worker     case 6:	u.format6.collect_glyphs (left_set, right_set, num_glyphs); return;
894*2d1272b8SAndroid Build Coastguard Worker     default:	return;
895*2d1272b8SAndroid Build Coastguard Worker     }
896*2d1272b8SAndroid Build Coastguard Worker   }
897*2d1272b8SAndroid Build Coastguard Worker 
sanitizeAAT::KerxSubTable898*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
899*2d1272b8SAndroid Build Coastguard Worker   {
900*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
901*2d1272b8SAndroid Build Coastguard Worker     if (!(u.header.sanitize (c) &&
902*2d1272b8SAndroid Build Coastguard Worker 	  hb_barrier () &&
903*2d1272b8SAndroid Build Coastguard Worker 	  u.header.length >= u.header.static_size &&
904*2d1272b8SAndroid Build Coastguard Worker 	  c->check_range (this, u.header.length)))
905*2d1272b8SAndroid Build Coastguard Worker       return_trace (false);
906*2d1272b8SAndroid Build Coastguard Worker 
907*2d1272b8SAndroid Build Coastguard Worker     return_trace (dispatch (c));
908*2d1272b8SAndroid Build Coastguard Worker   }
909*2d1272b8SAndroid Build Coastguard Worker 
910*2d1272b8SAndroid Build Coastguard Worker   public:
911*2d1272b8SAndroid Build Coastguard Worker   union {
912*2d1272b8SAndroid Build Coastguard Worker   KerxSubTableHeader				header;
913*2d1272b8SAndroid Build Coastguard Worker   KerxSubTableFormat0<KerxSubTableHeader>	format0;
914*2d1272b8SAndroid Build Coastguard Worker   KerxSubTableFormat1<KerxSubTableHeader>	format1;
915*2d1272b8SAndroid Build Coastguard Worker   KerxSubTableFormat2<KerxSubTableHeader>	format2;
916*2d1272b8SAndroid Build Coastguard Worker   KerxSubTableFormat4<KerxSubTableHeader>	format4;
917*2d1272b8SAndroid Build Coastguard Worker   KerxSubTableFormat6<KerxSubTableHeader>	format6;
918*2d1272b8SAndroid Build Coastguard Worker   } u;
919*2d1272b8SAndroid Build Coastguard Worker   public:
920*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_MIN (12);
921*2d1272b8SAndroid Build Coastguard Worker };
922*2d1272b8SAndroid Build Coastguard Worker 
923*2d1272b8SAndroid Build Coastguard Worker 
924*2d1272b8SAndroid Build Coastguard Worker /*
925*2d1272b8SAndroid Build Coastguard Worker  * The 'kerx' Table
926*2d1272b8SAndroid Build Coastguard Worker  */
927*2d1272b8SAndroid Build Coastguard Worker 
928*2d1272b8SAndroid Build Coastguard Worker using kern_accelerator_data_t = hb_vector_t<hb_pair_t<hb_set_digest_t, hb_set_digest_t>>;
929*2d1272b8SAndroid Build Coastguard Worker 
930*2d1272b8SAndroid Build Coastguard Worker template <typename T>
931*2d1272b8SAndroid Build Coastguard Worker struct KerxTable
932*2d1272b8SAndroid Build Coastguard Worker {
933*2d1272b8SAndroid Build Coastguard Worker   /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
thizAAT::KerxTable934*2d1272b8SAndroid Build Coastguard Worker   const T* thiz () const { return static_cast<const T *> (this); }
935*2d1272b8SAndroid Build Coastguard Worker 
has_state_machineAAT::KerxTable936*2d1272b8SAndroid Build Coastguard Worker   bool has_state_machine () const
937*2d1272b8SAndroid Build Coastguard Worker   {
938*2d1272b8SAndroid Build Coastguard Worker     typedef typename T::SubTable SubTable;
939*2d1272b8SAndroid Build Coastguard Worker 
940*2d1272b8SAndroid Build Coastguard Worker     const SubTable *st = &thiz()->firstSubTable;
941*2d1272b8SAndroid Build Coastguard Worker     unsigned int count = thiz()->tableCount;
942*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int i = 0; i < count; i++)
943*2d1272b8SAndroid Build Coastguard Worker     {
944*2d1272b8SAndroid Build Coastguard Worker       if (st->get_type () == 1)
945*2d1272b8SAndroid Build Coastguard Worker 	return true;
946*2d1272b8SAndroid Build Coastguard Worker 
947*2d1272b8SAndroid Build Coastguard Worker       // TODO: What about format 4? What's this API used for anyway?
948*2d1272b8SAndroid Build Coastguard Worker 
949*2d1272b8SAndroid Build Coastguard Worker       st = &StructAfter<SubTable> (*st);
950*2d1272b8SAndroid Build Coastguard Worker     }
951*2d1272b8SAndroid Build Coastguard Worker     return false;
952*2d1272b8SAndroid Build Coastguard Worker   }
953*2d1272b8SAndroid Build Coastguard Worker 
has_cross_streamAAT::KerxTable954*2d1272b8SAndroid Build Coastguard Worker   bool has_cross_stream () const
955*2d1272b8SAndroid Build Coastguard Worker   {
956*2d1272b8SAndroid Build Coastguard Worker     typedef typename T::SubTable SubTable;
957*2d1272b8SAndroid Build Coastguard Worker 
958*2d1272b8SAndroid Build Coastguard Worker     const SubTable *st = &thiz()->firstSubTable;
959*2d1272b8SAndroid Build Coastguard Worker     unsigned int count = thiz()->tableCount;
960*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int i = 0; i < count; i++)
961*2d1272b8SAndroid Build Coastguard Worker     {
962*2d1272b8SAndroid Build Coastguard Worker       if (st->u.header.coverage & st->u.header.CrossStream)
963*2d1272b8SAndroid Build Coastguard Worker 	return true;
964*2d1272b8SAndroid Build Coastguard Worker       st = &StructAfter<SubTable> (*st);
965*2d1272b8SAndroid Build Coastguard Worker     }
966*2d1272b8SAndroid Build Coastguard Worker     return false;
967*2d1272b8SAndroid Build Coastguard Worker   }
968*2d1272b8SAndroid Build Coastguard Worker 
get_h_kerningAAT::KerxTable969*2d1272b8SAndroid Build Coastguard Worker   int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right) const
970*2d1272b8SAndroid Build Coastguard Worker   {
971*2d1272b8SAndroid Build Coastguard Worker     typedef typename T::SubTable SubTable;
972*2d1272b8SAndroid Build Coastguard Worker 
973*2d1272b8SAndroid Build Coastguard Worker     int v = 0;
974*2d1272b8SAndroid Build Coastguard Worker     const SubTable *st = &thiz()->firstSubTable;
975*2d1272b8SAndroid Build Coastguard Worker     unsigned int count = thiz()->tableCount;
976*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int i = 0; i < count; i++)
977*2d1272b8SAndroid Build Coastguard Worker     {
978*2d1272b8SAndroid Build Coastguard Worker       if ((st->u.header.coverage & (st->u.header.Variation | st->u.header.CrossStream)) ||
979*2d1272b8SAndroid Build Coastguard Worker 	  !st->u.header.is_horizontal ())
980*2d1272b8SAndroid Build Coastguard Worker 	continue;
981*2d1272b8SAndroid Build Coastguard Worker       v += st->get_kerning (left, right);
982*2d1272b8SAndroid Build Coastguard Worker       st = &StructAfter<SubTable> (*st);
983*2d1272b8SAndroid Build Coastguard Worker     }
984*2d1272b8SAndroid Build Coastguard Worker     return v;
985*2d1272b8SAndroid Build Coastguard Worker   }
986*2d1272b8SAndroid Build Coastguard Worker 
applyAAT::KerxTable987*2d1272b8SAndroid Build Coastguard Worker   bool apply (AAT::hb_aat_apply_context_t *c,
988*2d1272b8SAndroid Build Coastguard Worker 	      const kern_accelerator_data_t *accel_data = nullptr) const
989*2d1272b8SAndroid Build Coastguard Worker   {
990*2d1272b8SAndroid Build Coastguard Worker     c->buffer->unsafe_to_concat ();
991*2d1272b8SAndroid Build Coastguard Worker 
992*2d1272b8SAndroid Build Coastguard Worker     if (c->buffer->len < HB_AAT_BUFFER_DIGEST_THRESHOLD)
993*2d1272b8SAndroid Build Coastguard Worker       c->buffer_digest = c->buffer->digest ();
994*2d1272b8SAndroid Build Coastguard Worker     else
995*2d1272b8SAndroid Build Coastguard Worker       c->buffer_digest = hb_set_digest_t::full ();
996*2d1272b8SAndroid Build Coastguard Worker 
997*2d1272b8SAndroid Build Coastguard Worker     typedef typename T::SubTable SubTable;
998*2d1272b8SAndroid Build Coastguard Worker 
999*2d1272b8SAndroid Build Coastguard Worker     bool ret = false;
1000*2d1272b8SAndroid Build Coastguard Worker     bool seenCrossStream = false;
1001*2d1272b8SAndroid Build Coastguard Worker     c->set_lookup_index (0);
1002*2d1272b8SAndroid Build Coastguard Worker     const SubTable *st = &thiz()->firstSubTable;
1003*2d1272b8SAndroid Build Coastguard Worker     unsigned int count = thiz()->tableCount;
1004*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int i = 0; i < count; i++)
1005*2d1272b8SAndroid Build Coastguard Worker     {
1006*2d1272b8SAndroid Build Coastguard Worker       bool reverse;
1007*2d1272b8SAndroid Build Coastguard Worker 
1008*2d1272b8SAndroid Build Coastguard Worker       if (!T::Types::extended && (st->u.header.coverage & st->u.header.Variation))
1009*2d1272b8SAndroid Build Coastguard Worker 	goto skip;
1010*2d1272b8SAndroid Build Coastguard Worker 
1011*2d1272b8SAndroid Build Coastguard Worker       if (HB_DIRECTION_IS_HORIZONTAL (c->buffer->props.direction) != st->u.header.is_horizontal ())
1012*2d1272b8SAndroid Build Coastguard Worker 	goto skip;
1013*2d1272b8SAndroid Build Coastguard Worker 
1014*2d1272b8SAndroid Build Coastguard Worker       reverse = bool (st->u.header.coverage & st->u.header.Backwards) !=
1015*2d1272b8SAndroid Build Coastguard Worker 		HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
1016*2d1272b8SAndroid Build Coastguard Worker 
1017*2d1272b8SAndroid Build Coastguard Worker       if (!c->buffer->message (c->font, "start subtable %u", c->lookup_index))
1018*2d1272b8SAndroid Build Coastguard Worker 	goto skip;
1019*2d1272b8SAndroid Build Coastguard Worker 
1020*2d1272b8SAndroid Build Coastguard Worker       if (!seenCrossStream &&
1021*2d1272b8SAndroid Build Coastguard Worker 	  (st->u.header.coverage & st->u.header.CrossStream))
1022*2d1272b8SAndroid Build Coastguard Worker       {
1023*2d1272b8SAndroid Build Coastguard Worker 	/* Attach all glyphs into a chain. */
1024*2d1272b8SAndroid Build Coastguard Worker 	seenCrossStream = true;
1025*2d1272b8SAndroid Build Coastguard Worker 	hb_glyph_position_t *pos = c->buffer->pos;
1026*2d1272b8SAndroid Build Coastguard Worker 	unsigned int count = c->buffer->len;
1027*2d1272b8SAndroid Build Coastguard Worker 	for (unsigned int i = 0; i < count; i++)
1028*2d1272b8SAndroid Build Coastguard Worker 	{
1029*2d1272b8SAndroid Build Coastguard Worker 	  pos[i].attach_type() = OT::Layout::GPOS_impl::ATTACH_TYPE_CURSIVE;
1030*2d1272b8SAndroid Build Coastguard Worker 	  pos[i].attach_chain() = HB_DIRECTION_IS_FORWARD (c->buffer->props.direction) ? -1 : +1;
1031*2d1272b8SAndroid Build Coastguard Worker 	  /* We intentionally don't set HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT,
1032*2d1272b8SAndroid Build Coastguard Worker 	   * since there needs to be a non-zero attachment for post-positioning to
1033*2d1272b8SAndroid Build Coastguard Worker 	   * be needed. */
1034*2d1272b8SAndroid Build Coastguard Worker 	}
1035*2d1272b8SAndroid Build Coastguard Worker       }
1036*2d1272b8SAndroid Build Coastguard Worker 
1037*2d1272b8SAndroid Build Coastguard Worker       if (reverse)
1038*2d1272b8SAndroid Build Coastguard Worker 	c->buffer->reverse ();
1039*2d1272b8SAndroid Build Coastguard Worker 
1040*2d1272b8SAndroid Build Coastguard Worker       if (accel_data)
1041*2d1272b8SAndroid Build Coastguard Worker       {
1042*2d1272b8SAndroid Build Coastguard Worker 	c->left_set = (*accel_data)[i].first;
1043*2d1272b8SAndroid Build Coastguard Worker 	c->right_set = (*accel_data)[i].second;
1044*2d1272b8SAndroid Build Coastguard Worker       }
1045*2d1272b8SAndroid Build Coastguard Worker       else
1046*2d1272b8SAndroid Build Coastguard Worker       {
1047*2d1272b8SAndroid Build Coastguard Worker         c->left_set = c->right_set = hb_set_digest_t::full ();
1048*2d1272b8SAndroid Build Coastguard Worker       }
1049*2d1272b8SAndroid Build Coastguard Worker 
1050*2d1272b8SAndroid Build Coastguard Worker       {
1051*2d1272b8SAndroid Build Coastguard Worker 	/* See comment in sanitize() for conditional here. */
1052*2d1272b8SAndroid Build Coastguard Worker 	hb_sanitize_with_object_t with (&c->sanitizer, i < count - 1 ? st : (const SubTable *) nullptr);
1053*2d1272b8SAndroid Build Coastguard Worker 	ret |= st->dispatch (c);
1054*2d1272b8SAndroid Build Coastguard Worker       }
1055*2d1272b8SAndroid Build Coastguard Worker 
1056*2d1272b8SAndroid Build Coastguard Worker       if (reverse)
1057*2d1272b8SAndroid Build Coastguard Worker 	c->buffer->reverse ();
1058*2d1272b8SAndroid Build Coastguard Worker 
1059*2d1272b8SAndroid Build Coastguard Worker       (void) c->buffer->message (c->font, "end subtable %u", c->lookup_index);
1060*2d1272b8SAndroid Build Coastguard Worker 
1061*2d1272b8SAndroid Build Coastguard Worker     skip:
1062*2d1272b8SAndroid Build Coastguard Worker       st = &StructAfter<SubTable> (*st);
1063*2d1272b8SAndroid Build Coastguard Worker       c->set_lookup_index (c->lookup_index + 1);
1064*2d1272b8SAndroid Build Coastguard Worker     }
1065*2d1272b8SAndroid Build Coastguard Worker 
1066*2d1272b8SAndroid Build Coastguard Worker     return ret;
1067*2d1272b8SAndroid Build Coastguard Worker   }
1068*2d1272b8SAndroid Build Coastguard Worker 
sanitizeAAT::KerxTable1069*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
1070*2d1272b8SAndroid Build Coastguard Worker   {
1071*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
1072*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!(thiz()->version.sanitize (c) &&
1073*2d1272b8SAndroid Build Coastguard Worker 		    hb_barrier () &&
1074*2d1272b8SAndroid Build Coastguard Worker 		    (unsigned) thiz()->version >= (unsigned) T::minVersion &&
1075*2d1272b8SAndroid Build Coastguard Worker 		    thiz()->tableCount.sanitize (c))))
1076*2d1272b8SAndroid Build Coastguard Worker       return_trace (false);
1077*2d1272b8SAndroid Build Coastguard Worker 
1078*2d1272b8SAndroid Build Coastguard Worker     typedef typename T::SubTable SubTable;
1079*2d1272b8SAndroid Build Coastguard Worker 
1080*2d1272b8SAndroid Build Coastguard Worker     const SubTable *st = &thiz()->firstSubTable;
1081*2d1272b8SAndroid Build Coastguard Worker     unsigned int count = thiz()->tableCount;
1082*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int i = 0; i < count; i++)
1083*2d1272b8SAndroid Build Coastguard Worker     {
1084*2d1272b8SAndroid Build Coastguard Worker       if (unlikely (!st->u.header.sanitize (c)))
1085*2d1272b8SAndroid Build Coastguard Worker 	return_trace (false);
1086*2d1272b8SAndroid Build Coastguard Worker       hb_barrier ();
1087*2d1272b8SAndroid Build Coastguard Worker       /* OpenType kern table has 2-byte subtable lengths.  That's limiting.
1088*2d1272b8SAndroid Build Coastguard Worker        * MS implementation also only supports one subtable, of format 0,
1089*2d1272b8SAndroid Build Coastguard Worker        * anyway.  Certain versions of some fonts, like Calibry, contain
1090*2d1272b8SAndroid Build Coastguard Worker        * kern subtable that exceeds 64kb.  Looks like, the subtable length
1091*2d1272b8SAndroid Build Coastguard Worker        * is simply ignored.  Which makes sense.  It's only needed if you
1092*2d1272b8SAndroid Build Coastguard Worker        * have multiple subtables.  To handle such fonts, we just ignore
1093*2d1272b8SAndroid Build Coastguard Worker        * the length for the last subtable. */
1094*2d1272b8SAndroid Build Coastguard Worker       hb_sanitize_with_object_t with (c, i < count - 1 ? st : (const SubTable *) nullptr);
1095*2d1272b8SAndroid Build Coastguard Worker 
1096*2d1272b8SAndroid Build Coastguard Worker       if (unlikely (!st->sanitize (c)))
1097*2d1272b8SAndroid Build Coastguard Worker 	return_trace (false);
1098*2d1272b8SAndroid Build Coastguard Worker 
1099*2d1272b8SAndroid Build Coastguard Worker       st = &StructAfter<SubTable> (*st);
1100*2d1272b8SAndroid Build Coastguard Worker     }
1101*2d1272b8SAndroid Build Coastguard Worker 
1102*2d1272b8SAndroid Build Coastguard Worker     unsigned majorVersion = thiz()->version;
1103*2d1272b8SAndroid Build Coastguard Worker     if (sizeof (thiz()->version) == 4)
1104*2d1272b8SAndroid Build Coastguard Worker       majorVersion = majorVersion >> 16;
1105*2d1272b8SAndroid Build Coastguard Worker     if (majorVersion >= 3)
1106*2d1272b8SAndroid Build Coastguard Worker     {
1107*2d1272b8SAndroid Build Coastguard Worker       const SubtableGlyphCoverage *coverage = (const SubtableGlyphCoverage *) st;
1108*2d1272b8SAndroid Build Coastguard Worker       if (!coverage->sanitize (c, count))
1109*2d1272b8SAndroid Build Coastguard Worker         return_trace (false);
1110*2d1272b8SAndroid Build Coastguard Worker     }
1111*2d1272b8SAndroid Build Coastguard Worker 
1112*2d1272b8SAndroid Build Coastguard Worker     return_trace (true);
1113*2d1272b8SAndroid Build Coastguard Worker   }
1114*2d1272b8SAndroid Build Coastguard Worker 
create_accelerator_dataAAT::KerxTable1115*2d1272b8SAndroid Build Coastguard Worker   kern_accelerator_data_t create_accelerator_data (unsigned num_glyphs) const
1116*2d1272b8SAndroid Build Coastguard Worker   {
1117*2d1272b8SAndroid Build Coastguard Worker     kern_accelerator_data_t accel_data;
1118*2d1272b8SAndroid Build Coastguard Worker 
1119*2d1272b8SAndroid Build Coastguard Worker     typedef typename T::SubTable SubTable;
1120*2d1272b8SAndroid Build Coastguard Worker 
1121*2d1272b8SAndroid Build Coastguard Worker     const SubTable *st = &thiz()->firstSubTable;
1122*2d1272b8SAndroid Build Coastguard Worker     unsigned int count = thiz()->tableCount;
1123*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int i = 0; i < count; i++)
1124*2d1272b8SAndroid Build Coastguard Worker     {
1125*2d1272b8SAndroid Build Coastguard Worker       hb_set_digest_t left_set, right_set;
1126*2d1272b8SAndroid Build Coastguard Worker       st->collect_glyphs (left_set, right_set, num_glyphs);
1127*2d1272b8SAndroid Build Coastguard Worker       accel_data.push (hb_pair (left_set, right_set));
1128*2d1272b8SAndroid Build Coastguard Worker       st = &StructAfter<SubTable> (*st);
1129*2d1272b8SAndroid Build Coastguard Worker     }
1130*2d1272b8SAndroid Build Coastguard Worker 
1131*2d1272b8SAndroid Build Coastguard Worker     return accel_data;
1132*2d1272b8SAndroid Build Coastguard Worker   }
1133*2d1272b8SAndroid Build Coastguard Worker 
1134*2d1272b8SAndroid Build Coastguard Worker   struct accelerator_t
1135*2d1272b8SAndroid Build Coastguard Worker   {
accelerator_tAAT::KerxTable::accelerator_t1136*2d1272b8SAndroid Build Coastguard Worker     accelerator_t (hb_face_t *face)
1137*2d1272b8SAndroid Build Coastguard Worker     {
1138*2d1272b8SAndroid Build Coastguard Worker       hb_sanitize_context_t sc;
1139*2d1272b8SAndroid Build Coastguard Worker       this->table = sc.reference_table<T> (face);
1140*2d1272b8SAndroid Build Coastguard Worker       this->accel_data = this->table->create_accelerator_data (face->get_num_glyphs ());
1141*2d1272b8SAndroid Build Coastguard Worker     }
~accelerator_tAAT::KerxTable::accelerator_t1142*2d1272b8SAndroid Build Coastguard Worker     ~accelerator_t ()
1143*2d1272b8SAndroid Build Coastguard Worker     {
1144*2d1272b8SAndroid Build Coastguard Worker       this->table.destroy ();
1145*2d1272b8SAndroid Build Coastguard Worker     }
1146*2d1272b8SAndroid Build Coastguard Worker 
get_blobAAT::KerxTable::accelerator_t1147*2d1272b8SAndroid Build Coastguard Worker     hb_blob_t *get_blob () const { return table.get_blob (); }
1148*2d1272b8SAndroid Build Coastguard Worker 
applyAAT::KerxTable::accelerator_t1149*2d1272b8SAndroid Build Coastguard Worker     bool apply (AAT::hb_aat_apply_context_t *c) const
1150*2d1272b8SAndroid Build Coastguard Worker     {
1151*2d1272b8SAndroid Build Coastguard Worker       return table->apply (c, &accel_data);
1152*2d1272b8SAndroid Build Coastguard Worker     }
1153*2d1272b8SAndroid Build Coastguard Worker 
1154*2d1272b8SAndroid Build Coastguard Worker     hb_blob_ptr_t<T> table;
1155*2d1272b8SAndroid Build Coastguard Worker     kern_accelerator_data_t accel_data;
1156*2d1272b8SAndroid Build Coastguard Worker   };
1157*2d1272b8SAndroid Build Coastguard Worker };
1158*2d1272b8SAndroid Build Coastguard Worker 
1159*2d1272b8SAndroid Build Coastguard Worker struct kerx : KerxTable<kerx>
1160*2d1272b8SAndroid Build Coastguard Worker {
1161*2d1272b8SAndroid Build Coastguard Worker   friend struct KerxTable<kerx>;
1162*2d1272b8SAndroid Build Coastguard Worker 
1163*2d1272b8SAndroid Build Coastguard Worker   static constexpr hb_tag_t tableTag = HB_AAT_TAG_kerx;
1164*2d1272b8SAndroid Build Coastguard Worker   static constexpr unsigned minVersion = 2u;
1165*2d1272b8SAndroid Build Coastguard Worker 
1166*2d1272b8SAndroid Build Coastguard Worker   typedef KerxSubTableHeader SubTableHeader;
1167*2d1272b8SAndroid Build Coastguard Worker   typedef SubTableHeader::Types Types;
1168*2d1272b8SAndroid Build Coastguard Worker   typedef KerxSubTable SubTable;
1169*2d1272b8SAndroid Build Coastguard Worker 
has_dataAAT::kerx1170*2d1272b8SAndroid Build Coastguard Worker   bool has_data () const { return version; }
1171*2d1272b8SAndroid Build Coastguard Worker 
1172*2d1272b8SAndroid Build Coastguard Worker   protected:
1173*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	version;	/* The version number of the extended kerning table
1174*2d1272b8SAndroid Build Coastguard Worker 				 * (currently 2, 3, or 4). */
1175*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	unused;		/* Set to 0. */
1176*2d1272b8SAndroid Build Coastguard Worker   HBUINT32	tableCount;	/* The number of subtables included in the extended kerning
1177*2d1272b8SAndroid Build Coastguard Worker 				 * table. */
1178*2d1272b8SAndroid Build Coastguard Worker   SubTable	firstSubTable;	/* Subtables. */
1179*2d1272b8SAndroid Build Coastguard Worker /*subtableGlyphCoverageArray*/	/* Only if version >= 3. We don't use. */
1180*2d1272b8SAndroid Build Coastguard Worker 
1181*2d1272b8SAndroid Build Coastguard Worker   public:
1182*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_MIN (8);
1183*2d1272b8SAndroid Build Coastguard Worker };
1184*2d1272b8SAndroid Build Coastguard Worker 
1185*2d1272b8SAndroid Build Coastguard Worker struct kerx_accelerator_t : kerx::accelerator_t {
kerx_accelerator_tAAT::kerx_accelerator_t1186*2d1272b8SAndroid Build Coastguard Worker   kerx_accelerator_t (hb_face_t *face) : kerx::accelerator_t (face) {}
1187*2d1272b8SAndroid Build Coastguard Worker };
1188*2d1272b8SAndroid Build Coastguard Worker 
1189*2d1272b8SAndroid Build Coastguard Worker } /* namespace AAT */
1190*2d1272b8SAndroid Build Coastguard Worker 
1191*2d1272b8SAndroid Build Coastguard Worker #endif /* HB_AAT_LAYOUT_KERX_TABLE_HH */
1192