xref: /aosp_15_r20/external/harfbuzz_ng/src/hb-aat-layout-morx-table.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_MORX_TABLE_HH
28*2d1272b8SAndroid Build Coastguard Worker #define HB_AAT_LAYOUT_MORX_TABLE_HH
29*2d1272b8SAndroid Build Coastguard Worker 
30*2d1272b8SAndroid Build Coastguard Worker #include "hb-open-type.hh"
31*2d1272b8SAndroid Build Coastguard Worker #include "hb-aat-layout-common.hh"
32*2d1272b8SAndroid Build Coastguard Worker #include "hb-ot-layout-common.hh"
33*2d1272b8SAndroid Build Coastguard Worker #include "hb-ot-layout-gdef-table.hh"
34*2d1272b8SAndroid Build Coastguard Worker #include "hb-aat-map.hh"
35*2d1272b8SAndroid Build Coastguard Worker 
36*2d1272b8SAndroid Build Coastguard Worker /*
37*2d1272b8SAndroid Build Coastguard Worker  * morx -- Extended Glyph Metamorphosis
38*2d1272b8SAndroid Build Coastguard Worker  * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6morx.html
39*2d1272b8SAndroid Build Coastguard Worker  * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6mort.html
40*2d1272b8SAndroid Build Coastguard Worker  */
41*2d1272b8SAndroid Build Coastguard Worker #define HB_AAT_TAG_morx HB_TAG('m','o','r','x')
42*2d1272b8SAndroid Build Coastguard Worker #define HB_AAT_TAG_mort HB_TAG('m','o','r','t')
43*2d1272b8SAndroid Build Coastguard Worker 
44*2d1272b8SAndroid Build Coastguard Worker 
45*2d1272b8SAndroid Build Coastguard Worker namespace AAT {
46*2d1272b8SAndroid Build Coastguard Worker 
47*2d1272b8SAndroid Build Coastguard Worker using namespace OT;
48*2d1272b8SAndroid Build Coastguard Worker 
49*2d1272b8SAndroid Build Coastguard Worker template <typename Types>
50*2d1272b8SAndroid Build Coastguard Worker struct RearrangementSubtable
51*2d1272b8SAndroid Build Coastguard Worker {
52*2d1272b8SAndroid Build Coastguard Worker   typedef typename Types::HBUINT HBUINT;
53*2d1272b8SAndroid Build Coastguard Worker 
54*2d1272b8SAndroid Build Coastguard Worker   typedef void EntryData;
55*2d1272b8SAndroid Build Coastguard Worker 
56*2d1272b8SAndroid Build Coastguard Worker   struct driver_context_t
57*2d1272b8SAndroid Build Coastguard Worker   {
58*2d1272b8SAndroid Build Coastguard Worker     static constexpr bool in_place = true;
59*2d1272b8SAndroid Build Coastguard Worker     enum Flags
60*2d1272b8SAndroid Build Coastguard Worker     {
61*2d1272b8SAndroid Build Coastguard Worker       MarkFirst		= 0x8000,	/* If set, make the current glyph the first
62*2d1272b8SAndroid Build Coastguard Worker 					 * glyph to be rearranged. */
63*2d1272b8SAndroid Build Coastguard Worker       DontAdvance	= 0x4000,	/* If set, don't advance to the next glyph
64*2d1272b8SAndroid Build Coastguard Worker 					 * before going to the new state. This means
65*2d1272b8SAndroid Build Coastguard Worker 					 * that the glyph index doesn't change, even
66*2d1272b8SAndroid Build Coastguard Worker 					 * if the glyph at that index has changed. */
67*2d1272b8SAndroid Build Coastguard Worker       MarkLast		= 0x2000,	/* If set, make the current glyph the last
68*2d1272b8SAndroid Build Coastguard Worker 					 * glyph to be rearranged. */
69*2d1272b8SAndroid Build Coastguard Worker       Reserved		= 0x1FF0,	/* These bits are reserved and should be set to 0. */
70*2d1272b8SAndroid Build Coastguard Worker       Verb		= 0x000F,	/* The type of rearrangement specified. */
71*2d1272b8SAndroid Build Coastguard Worker     };
72*2d1272b8SAndroid Build Coastguard Worker 
driver_context_tAAT::RearrangementSubtable::driver_context_t73*2d1272b8SAndroid Build Coastguard Worker     driver_context_t (const RearrangementSubtable *table HB_UNUSED) :
74*2d1272b8SAndroid Build Coastguard Worker 	ret (false),
75*2d1272b8SAndroid Build Coastguard Worker 	start (0), end (0) {}
76*2d1272b8SAndroid Build Coastguard Worker 
is_actionableAAT::RearrangementSubtable::driver_context_t77*2d1272b8SAndroid Build Coastguard Worker     bool is_actionable (hb_buffer_t *buffer HB_UNUSED,
78*2d1272b8SAndroid Build Coastguard Worker 			StateTableDriver<Types, EntryData> *driver HB_UNUSED,
79*2d1272b8SAndroid Build Coastguard Worker 			const Entry<EntryData> &entry) const
80*2d1272b8SAndroid Build Coastguard Worker     {
81*2d1272b8SAndroid Build Coastguard Worker       return (entry.flags & Verb) && start < end;
82*2d1272b8SAndroid Build Coastguard Worker     }
transitionAAT::RearrangementSubtable::driver_context_t83*2d1272b8SAndroid Build Coastguard Worker     void transition (hb_buffer_t *buffer,
84*2d1272b8SAndroid Build Coastguard Worker 		     StateTableDriver<Types, EntryData> *driver,
85*2d1272b8SAndroid Build Coastguard Worker 		     const Entry<EntryData> &entry)
86*2d1272b8SAndroid Build Coastguard Worker     {
87*2d1272b8SAndroid Build Coastguard Worker       unsigned int flags = entry.flags;
88*2d1272b8SAndroid Build Coastguard Worker 
89*2d1272b8SAndroid Build Coastguard Worker       if (flags & MarkFirst)
90*2d1272b8SAndroid Build Coastguard Worker 	start = buffer->idx;
91*2d1272b8SAndroid Build Coastguard Worker 
92*2d1272b8SAndroid Build Coastguard Worker       if (flags & MarkLast)
93*2d1272b8SAndroid Build Coastguard Worker 	end = hb_min (buffer->idx + 1, buffer->len);
94*2d1272b8SAndroid Build Coastguard Worker 
95*2d1272b8SAndroid Build Coastguard Worker       if ((flags & Verb) && start < end)
96*2d1272b8SAndroid Build Coastguard Worker       {
97*2d1272b8SAndroid Build Coastguard Worker 	/* The following map has two nibbles, for start-side
98*2d1272b8SAndroid Build Coastguard Worker 	 * and end-side. Values of 0,1,2 mean move that many
99*2d1272b8SAndroid Build Coastguard Worker 	 * to the other side. Value of 3 means move 2 and
100*2d1272b8SAndroid Build Coastguard Worker 	 * flip them. */
101*2d1272b8SAndroid Build Coastguard Worker 	const unsigned char map[16] =
102*2d1272b8SAndroid Build Coastguard Worker 	{
103*2d1272b8SAndroid Build Coastguard Worker 	  0x00,	/* 0	no change */
104*2d1272b8SAndroid Build Coastguard Worker 	  0x10,	/* 1	Ax => xA */
105*2d1272b8SAndroid Build Coastguard Worker 	  0x01,	/* 2	xD => Dx */
106*2d1272b8SAndroid Build Coastguard Worker 	  0x11,	/* 3	AxD => DxA */
107*2d1272b8SAndroid Build Coastguard Worker 	  0x20,	/* 4	ABx => xAB */
108*2d1272b8SAndroid Build Coastguard Worker 	  0x30,	/* 5	ABx => xBA */
109*2d1272b8SAndroid Build Coastguard Worker 	  0x02,	/* 6	xCD => CDx */
110*2d1272b8SAndroid Build Coastguard Worker 	  0x03,	/* 7	xCD => DCx */
111*2d1272b8SAndroid Build Coastguard Worker 	  0x12,	/* 8	AxCD => CDxA */
112*2d1272b8SAndroid Build Coastguard Worker 	  0x13,	/* 9	AxCD => DCxA */
113*2d1272b8SAndroid Build Coastguard Worker 	  0x21,	/* 10	ABxD => DxAB */
114*2d1272b8SAndroid Build Coastguard Worker 	  0x31,	/* 11	ABxD => DxBA */
115*2d1272b8SAndroid Build Coastguard Worker 	  0x22,	/* 12	ABxCD => CDxAB */
116*2d1272b8SAndroid Build Coastguard Worker 	  0x32,	/* 13	ABxCD => CDxBA */
117*2d1272b8SAndroid Build Coastguard Worker 	  0x23,	/* 14	ABxCD => DCxAB */
118*2d1272b8SAndroid Build Coastguard Worker 	  0x33,	/* 15	ABxCD => DCxBA */
119*2d1272b8SAndroid Build Coastguard Worker 	};
120*2d1272b8SAndroid Build Coastguard Worker 
121*2d1272b8SAndroid Build Coastguard Worker 	unsigned int m = map[flags & Verb];
122*2d1272b8SAndroid Build Coastguard Worker 	unsigned int l = hb_min (2u, m >> 4);
123*2d1272b8SAndroid Build Coastguard Worker 	unsigned int r = hb_min (2u, m & 0x0F);
124*2d1272b8SAndroid Build Coastguard Worker 	bool reverse_l = 3 == (m >> 4);
125*2d1272b8SAndroid Build Coastguard Worker 	bool reverse_r = 3 == (m & 0x0F);
126*2d1272b8SAndroid Build Coastguard Worker 
127*2d1272b8SAndroid Build Coastguard Worker 	if (end - start >= l + r && end-start <= HB_MAX_CONTEXT_LENGTH)
128*2d1272b8SAndroid Build Coastguard Worker 	{
129*2d1272b8SAndroid Build Coastguard Worker 	  buffer->merge_clusters (start, hb_min (buffer->idx + 1, buffer->len));
130*2d1272b8SAndroid Build Coastguard Worker 	  buffer->merge_clusters (start, end);
131*2d1272b8SAndroid Build Coastguard Worker 
132*2d1272b8SAndroid Build Coastguard Worker 	  hb_glyph_info_t *info = buffer->info;
133*2d1272b8SAndroid Build Coastguard Worker 	  hb_glyph_info_t buf[4];
134*2d1272b8SAndroid Build Coastguard Worker 
135*2d1272b8SAndroid Build Coastguard Worker 	  hb_memcpy (buf, info + start, l * sizeof (buf[0]));
136*2d1272b8SAndroid Build Coastguard Worker 	  hb_memcpy (buf + 2, info + end - r, r * sizeof (buf[0]));
137*2d1272b8SAndroid Build Coastguard Worker 
138*2d1272b8SAndroid Build Coastguard Worker 	  if (l != r)
139*2d1272b8SAndroid Build Coastguard Worker 	    memmove (info + start + r, info + start + l, (end - start - l - r) * sizeof (buf[0]));
140*2d1272b8SAndroid Build Coastguard Worker 
141*2d1272b8SAndroid Build Coastguard Worker 	  hb_memcpy (info + start, buf + 2, r * sizeof (buf[0]));
142*2d1272b8SAndroid Build Coastguard Worker 	  hb_memcpy (info + end - l, buf, l * sizeof (buf[0]));
143*2d1272b8SAndroid Build Coastguard Worker 	  if (reverse_l)
144*2d1272b8SAndroid Build Coastguard Worker 	  {
145*2d1272b8SAndroid Build Coastguard Worker 	    buf[0] = info[end - 1];
146*2d1272b8SAndroid Build Coastguard Worker 	    info[end - 1] = info[end - 2];
147*2d1272b8SAndroid Build Coastguard Worker 	    info[end - 2] = buf[0];
148*2d1272b8SAndroid Build Coastguard Worker 	  }
149*2d1272b8SAndroid Build Coastguard Worker 	  if (reverse_r)
150*2d1272b8SAndroid Build Coastguard Worker 	  {
151*2d1272b8SAndroid Build Coastguard Worker 	    buf[0] = info[start];
152*2d1272b8SAndroid Build Coastguard Worker 	    info[start] = info[start + 1];
153*2d1272b8SAndroid Build Coastguard Worker 	    info[start + 1] = buf[0];
154*2d1272b8SAndroid Build Coastguard Worker 	  }
155*2d1272b8SAndroid Build Coastguard Worker 	}
156*2d1272b8SAndroid Build Coastguard Worker       }
157*2d1272b8SAndroid Build Coastguard Worker     }
158*2d1272b8SAndroid Build Coastguard Worker 
159*2d1272b8SAndroid Build Coastguard Worker     public:
160*2d1272b8SAndroid Build Coastguard Worker     bool ret;
161*2d1272b8SAndroid Build Coastguard Worker     private:
162*2d1272b8SAndroid Build Coastguard Worker     unsigned int start;
163*2d1272b8SAndroid Build Coastguard Worker     unsigned int end;
164*2d1272b8SAndroid Build Coastguard Worker   };
165*2d1272b8SAndroid Build Coastguard Worker 
applyAAT::RearrangementSubtable166*2d1272b8SAndroid Build Coastguard Worker   bool apply (hb_aat_apply_context_t *c) const
167*2d1272b8SAndroid Build Coastguard Worker   {
168*2d1272b8SAndroid Build Coastguard Worker     TRACE_APPLY (this);
169*2d1272b8SAndroid Build Coastguard Worker 
170*2d1272b8SAndroid Build Coastguard Worker     driver_context_t dc (this);
171*2d1272b8SAndroid Build Coastguard Worker 
172*2d1272b8SAndroid Build Coastguard Worker     StateTableDriver<Types, EntryData> driver (machine, c->face);
173*2d1272b8SAndroid Build Coastguard Worker 
174*2d1272b8SAndroid Build Coastguard Worker     if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) &&
175*2d1272b8SAndroid Build Coastguard Worker 	!c->buffer_digest.may_have (c->machine_glyph_set))
176*2d1272b8SAndroid Build Coastguard Worker       return_trace (false);
177*2d1272b8SAndroid Build Coastguard Worker 
178*2d1272b8SAndroid Build Coastguard Worker     driver.drive (&dc, c);
179*2d1272b8SAndroid Build Coastguard Worker 
180*2d1272b8SAndroid Build Coastguard Worker     return_trace (dc.ret);
181*2d1272b8SAndroid Build Coastguard Worker   }
182*2d1272b8SAndroid Build Coastguard Worker 
sanitizeAAT::RearrangementSubtable183*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
184*2d1272b8SAndroid Build Coastguard Worker   {
185*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
186*2d1272b8SAndroid Build Coastguard Worker     return_trace (machine.sanitize (c));
187*2d1272b8SAndroid Build Coastguard Worker   }
188*2d1272b8SAndroid Build Coastguard Worker 
189*2d1272b8SAndroid Build Coastguard Worker   public:
190*2d1272b8SAndroid Build Coastguard Worker   StateTable<Types, EntryData>	machine;
191*2d1272b8SAndroid Build Coastguard Worker   public:
192*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_STATIC ((StateTable<Types, EntryData>::static_size));
193*2d1272b8SAndroid Build Coastguard Worker };
194*2d1272b8SAndroid Build Coastguard Worker 
195*2d1272b8SAndroid Build Coastguard Worker template <typename Types>
196*2d1272b8SAndroid Build Coastguard Worker struct ContextualSubtable
197*2d1272b8SAndroid Build Coastguard Worker {
198*2d1272b8SAndroid Build Coastguard Worker   typedef typename Types::HBUINT HBUINT;
199*2d1272b8SAndroid Build Coastguard Worker 
200*2d1272b8SAndroid Build Coastguard Worker   struct EntryData
201*2d1272b8SAndroid Build Coastguard Worker   {
202*2d1272b8SAndroid Build Coastguard Worker     HBUINT16	markIndex;	/* Index of the substitution table for the
203*2d1272b8SAndroid Build Coastguard Worker 				 * marked glyph (use 0xFFFF for none). */
204*2d1272b8SAndroid Build Coastguard Worker     HBUINT16	currentIndex;	/* Index of the substitution table for the
205*2d1272b8SAndroid Build Coastguard Worker 				 * current glyph (use 0xFFFF for none). */
206*2d1272b8SAndroid Build Coastguard Worker     public:
207*2d1272b8SAndroid Build Coastguard Worker     DEFINE_SIZE_STATIC (4);
208*2d1272b8SAndroid Build Coastguard Worker   };
209*2d1272b8SAndroid Build Coastguard Worker 
210*2d1272b8SAndroid Build Coastguard Worker   struct driver_context_t
211*2d1272b8SAndroid Build Coastguard Worker   {
212*2d1272b8SAndroid Build Coastguard Worker     static constexpr bool in_place = true;
213*2d1272b8SAndroid Build Coastguard Worker     enum Flags
214*2d1272b8SAndroid Build Coastguard Worker     {
215*2d1272b8SAndroid Build Coastguard Worker       SetMark		= 0x8000,	/* If set, make the current glyph the marked glyph. */
216*2d1272b8SAndroid Build Coastguard Worker       DontAdvance	= 0x4000,	/* If set, don't advance to the next glyph before
217*2d1272b8SAndroid Build Coastguard Worker 					 * going to the new state. */
218*2d1272b8SAndroid Build Coastguard Worker       Reserved		= 0x3FFF,	/* These bits are reserved and should be set to 0. */
219*2d1272b8SAndroid Build Coastguard Worker     };
220*2d1272b8SAndroid Build Coastguard Worker 
driver_context_tAAT::ContextualSubtable::driver_context_t221*2d1272b8SAndroid Build Coastguard Worker     driver_context_t (const ContextualSubtable *table_,
222*2d1272b8SAndroid Build Coastguard Worker 			     hb_aat_apply_context_t *c_) :
223*2d1272b8SAndroid Build Coastguard Worker 	ret (false),
224*2d1272b8SAndroid Build Coastguard Worker 	c (c_),
225*2d1272b8SAndroid Build Coastguard Worker 	gdef (*c->gdef_table),
226*2d1272b8SAndroid Build Coastguard Worker 	mark_set (false),
227*2d1272b8SAndroid Build Coastguard Worker 	has_glyph_classes (gdef.has_glyph_classes ()),
228*2d1272b8SAndroid Build Coastguard Worker 	mark (0),
229*2d1272b8SAndroid Build Coastguard Worker 	table (table_),
230*2d1272b8SAndroid Build Coastguard Worker 	subs (table+table->substitutionTables) {}
231*2d1272b8SAndroid Build Coastguard Worker 
is_actionableAAT::ContextualSubtable::driver_context_t232*2d1272b8SAndroid Build Coastguard Worker     bool is_actionable (hb_buffer_t *buffer,
233*2d1272b8SAndroid Build Coastguard Worker 			StateTableDriver<Types, EntryData> *driver,
234*2d1272b8SAndroid Build Coastguard Worker 			const Entry<EntryData> &entry) const
235*2d1272b8SAndroid Build Coastguard Worker     {
236*2d1272b8SAndroid Build Coastguard Worker       if (buffer->idx == buffer->len && !mark_set)
237*2d1272b8SAndroid Build Coastguard Worker 	return false;
238*2d1272b8SAndroid Build Coastguard Worker 
239*2d1272b8SAndroid Build Coastguard Worker       return entry.data.markIndex != 0xFFFF || entry.data.currentIndex != 0xFFFF;
240*2d1272b8SAndroid Build Coastguard Worker     }
transitionAAT::ContextualSubtable::driver_context_t241*2d1272b8SAndroid Build Coastguard Worker     void transition (hb_buffer_t *buffer,
242*2d1272b8SAndroid Build Coastguard Worker 		     StateTableDriver<Types, EntryData> *driver,
243*2d1272b8SAndroid Build Coastguard Worker 		     const Entry<EntryData> &entry)
244*2d1272b8SAndroid Build Coastguard Worker     {
245*2d1272b8SAndroid Build Coastguard Worker       /* Looks like CoreText applies neither mark nor current substitution for
246*2d1272b8SAndroid Build Coastguard Worker        * end-of-text if mark was not explicitly set. */
247*2d1272b8SAndroid Build Coastguard Worker       if (buffer->idx == buffer->len && !mark_set)
248*2d1272b8SAndroid Build Coastguard Worker 	return;
249*2d1272b8SAndroid Build Coastguard Worker 
250*2d1272b8SAndroid Build Coastguard Worker       const HBGlyphID16 *replacement;
251*2d1272b8SAndroid Build Coastguard Worker 
252*2d1272b8SAndroid Build Coastguard Worker       replacement = nullptr;
253*2d1272b8SAndroid Build Coastguard Worker       if (Types::extended)
254*2d1272b8SAndroid Build Coastguard Worker       {
255*2d1272b8SAndroid Build Coastguard Worker 	if (entry.data.markIndex != 0xFFFF)
256*2d1272b8SAndroid Build Coastguard Worker 	{
257*2d1272b8SAndroid Build Coastguard Worker 	  const Lookup<HBGlyphID16> &lookup = subs[entry.data.markIndex];
258*2d1272b8SAndroid Build Coastguard Worker 	  replacement = lookup.get_value (buffer->info[mark].codepoint, driver->num_glyphs);
259*2d1272b8SAndroid Build Coastguard Worker 	}
260*2d1272b8SAndroid Build Coastguard Worker       }
261*2d1272b8SAndroid Build Coastguard Worker       else
262*2d1272b8SAndroid Build Coastguard Worker       {
263*2d1272b8SAndroid Build Coastguard Worker 	unsigned int offset = entry.data.markIndex + buffer->info[mark].codepoint;
264*2d1272b8SAndroid Build Coastguard Worker 	const UnsizedArrayOf<HBGlyphID16> &subs_old = (const UnsizedArrayOf<HBGlyphID16> &) subs;
265*2d1272b8SAndroid Build Coastguard Worker 	replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
266*2d1272b8SAndroid Build Coastguard Worker 	if (!(replacement->sanitize (&c->sanitizer) &&
267*2d1272b8SAndroid Build Coastguard Worker 	      hb_barrier () &&
268*2d1272b8SAndroid Build Coastguard Worker 	      *replacement))
269*2d1272b8SAndroid Build Coastguard Worker 	  replacement = nullptr;
270*2d1272b8SAndroid Build Coastguard Worker       }
271*2d1272b8SAndroid Build Coastguard Worker       if (replacement)
272*2d1272b8SAndroid Build Coastguard Worker       {
273*2d1272b8SAndroid Build Coastguard Worker 	buffer->unsafe_to_break (mark, hb_min (buffer->idx + 1, buffer->len));
274*2d1272b8SAndroid Build Coastguard Worker 	buffer->info[mark].codepoint = *replacement;
275*2d1272b8SAndroid Build Coastguard Worker 	c->buffer_digest.add (*replacement);
276*2d1272b8SAndroid Build Coastguard Worker 	if (has_glyph_classes)
277*2d1272b8SAndroid Build Coastguard Worker 	  _hb_glyph_info_set_glyph_props (&buffer->info[mark],
278*2d1272b8SAndroid Build Coastguard Worker 					  gdef.get_glyph_props (*replacement));
279*2d1272b8SAndroid Build Coastguard Worker 	ret = true;
280*2d1272b8SAndroid Build Coastguard Worker       }
281*2d1272b8SAndroid Build Coastguard Worker 
282*2d1272b8SAndroid Build Coastguard Worker       replacement = nullptr;
283*2d1272b8SAndroid Build Coastguard Worker       unsigned int idx = hb_min (buffer->idx, buffer->len - 1);
284*2d1272b8SAndroid Build Coastguard Worker       if (Types::extended)
285*2d1272b8SAndroid Build Coastguard Worker       {
286*2d1272b8SAndroid Build Coastguard Worker 	if (entry.data.currentIndex != 0xFFFF)
287*2d1272b8SAndroid Build Coastguard Worker 	{
288*2d1272b8SAndroid Build Coastguard Worker 	  const Lookup<HBGlyphID16> &lookup = subs[entry.data.currentIndex];
289*2d1272b8SAndroid Build Coastguard Worker 	  replacement = lookup.get_value (buffer->info[idx].codepoint, driver->num_glyphs);
290*2d1272b8SAndroid Build Coastguard Worker 	}
291*2d1272b8SAndroid Build Coastguard Worker       }
292*2d1272b8SAndroid Build Coastguard Worker       else
293*2d1272b8SAndroid Build Coastguard Worker       {
294*2d1272b8SAndroid Build Coastguard Worker 	unsigned int offset = entry.data.currentIndex + buffer->info[idx].codepoint;
295*2d1272b8SAndroid Build Coastguard Worker 	const UnsizedArrayOf<HBGlyphID16> &subs_old = (const UnsizedArrayOf<HBGlyphID16> &) subs;
296*2d1272b8SAndroid Build Coastguard Worker 	replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
297*2d1272b8SAndroid Build Coastguard Worker 	if (!(replacement->sanitize (&c->sanitizer) &&
298*2d1272b8SAndroid Build Coastguard Worker 	      hb_barrier () &&
299*2d1272b8SAndroid Build Coastguard Worker 	      *replacement))
300*2d1272b8SAndroid Build Coastguard Worker 	  replacement = nullptr;
301*2d1272b8SAndroid Build Coastguard Worker       }
302*2d1272b8SAndroid Build Coastguard Worker       if (replacement)
303*2d1272b8SAndroid Build Coastguard Worker       {
304*2d1272b8SAndroid Build Coastguard Worker 	buffer->info[idx].codepoint = *replacement;
305*2d1272b8SAndroid Build Coastguard Worker 	c->buffer_digest.add (*replacement);
306*2d1272b8SAndroid Build Coastguard Worker 	if (has_glyph_classes)
307*2d1272b8SAndroid Build Coastguard Worker 	  _hb_glyph_info_set_glyph_props (&buffer->info[idx],
308*2d1272b8SAndroid Build Coastguard Worker 					  gdef.get_glyph_props (*replacement));
309*2d1272b8SAndroid Build Coastguard Worker 	ret = true;
310*2d1272b8SAndroid Build Coastguard Worker       }
311*2d1272b8SAndroid Build Coastguard Worker 
312*2d1272b8SAndroid Build Coastguard Worker       if (entry.flags & SetMark)
313*2d1272b8SAndroid Build Coastguard Worker       {
314*2d1272b8SAndroid Build Coastguard Worker 	mark_set = true;
315*2d1272b8SAndroid Build Coastguard Worker 	mark = buffer->idx;
316*2d1272b8SAndroid Build Coastguard Worker       }
317*2d1272b8SAndroid Build Coastguard Worker     }
318*2d1272b8SAndroid Build Coastguard Worker 
319*2d1272b8SAndroid Build Coastguard Worker     public:
320*2d1272b8SAndroid Build Coastguard Worker     bool ret;
321*2d1272b8SAndroid Build Coastguard Worker     private:
322*2d1272b8SAndroid Build Coastguard Worker     hb_aat_apply_context_t *c;
323*2d1272b8SAndroid Build Coastguard Worker     const OT::GDEF &gdef;
324*2d1272b8SAndroid Build Coastguard Worker     bool mark_set;
325*2d1272b8SAndroid Build Coastguard Worker     bool has_glyph_classes;
326*2d1272b8SAndroid Build Coastguard Worker     unsigned int mark;
327*2d1272b8SAndroid Build Coastguard Worker     const ContextualSubtable *table;
328*2d1272b8SAndroid Build Coastguard Worker     const UnsizedListOfOffset16To<Lookup<HBGlyphID16>, HBUINT, void, false> &subs;
329*2d1272b8SAndroid Build Coastguard Worker   };
330*2d1272b8SAndroid Build Coastguard Worker 
applyAAT::ContextualSubtable331*2d1272b8SAndroid Build Coastguard Worker   bool apply (hb_aat_apply_context_t *c) const
332*2d1272b8SAndroid Build Coastguard Worker   {
333*2d1272b8SAndroid Build Coastguard Worker     TRACE_APPLY (this);
334*2d1272b8SAndroid Build Coastguard Worker 
335*2d1272b8SAndroid Build Coastguard Worker     driver_context_t dc (this, c);
336*2d1272b8SAndroid Build Coastguard Worker 
337*2d1272b8SAndroid Build Coastguard Worker     StateTableDriver<Types, EntryData> driver (machine, c->face);
338*2d1272b8SAndroid Build Coastguard Worker 
339*2d1272b8SAndroid Build Coastguard Worker     if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) &&
340*2d1272b8SAndroid Build Coastguard Worker 	!c->buffer_digest.may_have (c->machine_glyph_set))
341*2d1272b8SAndroid Build Coastguard Worker       return_trace (false);
342*2d1272b8SAndroid Build Coastguard Worker 
343*2d1272b8SAndroid Build Coastguard Worker     driver.drive (&dc, c);
344*2d1272b8SAndroid Build Coastguard Worker 
345*2d1272b8SAndroid Build Coastguard Worker     return_trace (dc.ret);
346*2d1272b8SAndroid Build Coastguard Worker   }
347*2d1272b8SAndroid Build Coastguard Worker 
sanitizeAAT::ContextualSubtable348*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 
352*2d1272b8SAndroid Build Coastguard Worker     unsigned int num_entries = 0;
353*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!machine.sanitize (c, &num_entries))) return_trace (false);
354*2d1272b8SAndroid Build Coastguard Worker     hb_barrier ();
355*2d1272b8SAndroid Build Coastguard Worker 
356*2d1272b8SAndroid Build Coastguard Worker     if (!Types::extended)
357*2d1272b8SAndroid Build Coastguard Worker       return_trace (substitutionTables.sanitize (c, this, 0));
358*2d1272b8SAndroid Build Coastguard Worker 
359*2d1272b8SAndroid Build Coastguard Worker     unsigned int num_lookups = 0;
360*2d1272b8SAndroid Build Coastguard Worker 
361*2d1272b8SAndroid Build Coastguard Worker     const Entry<EntryData> *entries = machine.get_entries ();
362*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int i = 0; i < num_entries; i++)
363*2d1272b8SAndroid Build Coastguard Worker     {
364*2d1272b8SAndroid Build Coastguard Worker       const EntryData &data = entries[i].data;
365*2d1272b8SAndroid Build Coastguard Worker 
366*2d1272b8SAndroid Build Coastguard Worker       if (data.markIndex != 0xFFFF)
367*2d1272b8SAndroid Build Coastguard Worker 	num_lookups = hb_max (num_lookups, 1u + data.markIndex);
368*2d1272b8SAndroid Build Coastguard Worker       if (data.currentIndex != 0xFFFF)
369*2d1272b8SAndroid Build Coastguard Worker 	num_lookups = hb_max (num_lookups, 1u + data.currentIndex);
370*2d1272b8SAndroid Build Coastguard Worker     }
371*2d1272b8SAndroid Build Coastguard Worker 
372*2d1272b8SAndroid Build Coastguard Worker     return_trace (substitutionTables.sanitize (c, this, num_lookups));
373*2d1272b8SAndroid Build Coastguard Worker   }
374*2d1272b8SAndroid Build Coastguard Worker 
375*2d1272b8SAndroid Build Coastguard Worker   public:
376*2d1272b8SAndroid Build Coastguard Worker   StateTable<Types, EntryData>
377*2d1272b8SAndroid Build Coastguard Worker 		machine;
378*2d1272b8SAndroid Build Coastguard Worker   protected:
379*2d1272b8SAndroid Build Coastguard Worker   NNOffsetTo<UnsizedListOfOffset16To<Lookup<HBGlyphID16>, HBUINT, void, false>, HBUINT>
380*2d1272b8SAndroid Build Coastguard Worker 		substitutionTables;
381*2d1272b8SAndroid Build Coastguard Worker   public:
382*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_STATIC ((StateTable<Types, EntryData>::static_size + HBUINT::static_size));
383*2d1272b8SAndroid Build Coastguard Worker };
384*2d1272b8SAndroid Build Coastguard Worker 
385*2d1272b8SAndroid Build Coastguard Worker 
386*2d1272b8SAndroid Build Coastguard Worker template <bool extended>
387*2d1272b8SAndroid Build Coastguard Worker struct LigatureEntry;
388*2d1272b8SAndroid Build Coastguard Worker 
389*2d1272b8SAndroid Build Coastguard Worker template <>
390*2d1272b8SAndroid Build Coastguard Worker struct LigatureEntry<true>
391*2d1272b8SAndroid Build Coastguard Worker {
392*2d1272b8SAndroid Build Coastguard Worker   enum Flags
393*2d1272b8SAndroid Build Coastguard Worker   {
394*2d1272b8SAndroid Build Coastguard Worker     SetComponent	= 0x8000,	/* Push this glyph onto the component stack for
395*2d1272b8SAndroid Build Coastguard Worker 					 * eventual processing. */
396*2d1272b8SAndroid Build Coastguard Worker     DontAdvance		= 0x4000,	/* Leave the glyph pointer at this glyph for the
397*2d1272b8SAndroid Build Coastguard Worker 					   next iteration. */
398*2d1272b8SAndroid Build Coastguard Worker     PerformAction	= 0x2000,	/* Use the ligActionIndex to process a ligature
399*2d1272b8SAndroid Build Coastguard Worker 					 * group. */
400*2d1272b8SAndroid Build Coastguard Worker     Reserved		= 0x1FFF,	/* These bits are reserved and should be set to 0. */
401*2d1272b8SAndroid Build Coastguard Worker   };
402*2d1272b8SAndroid Build Coastguard Worker 
403*2d1272b8SAndroid Build Coastguard Worker   struct EntryData
404*2d1272b8SAndroid Build Coastguard Worker   {
405*2d1272b8SAndroid Build Coastguard Worker     HBUINT16	ligActionIndex;	/* Index to the first ligActionTable entry
406*2d1272b8SAndroid Build Coastguard Worker 				 * for processing this group, if indicated
407*2d1272b8SAndroid Build Coastguard Worker 				 * by the flags. */
408*2d1272b8SAndroid Build Coastguard Worker     public:
409*2d1272b8SAndroid Build Coastguard Worker     DEFINE_SIZE_STATIC (2);
410*2d1272b8SAndroid Build Coastguard Worker   };
411*2d1272b8SAndroid Build Coastguard Worker 
performActionAAT::LigatureEntry412*2d1272b8SAndroid Build Coastguard Worker   static bool performAction (const Entry<EntryData> &entry)
413*2d1272b8SAndroid Build Coastguard Worker   { return entry.flags & PerformAction; }
414*2d1272b8SAndroid Build Coastguard Worker 
ligActionIndexAAT::LigatureEntry415*2d1272b8SAndroid Build Coastguard Worker   static unsigned int ligActionIndex (const Entry<EntryData> &entry)
416*2d1272b8SAndroid Build Coastguard Worker   { return entry.data.ligActionIndex; }
417*2d1272b8SAndroid Build Coastguard Worker };
418*2d1272b8SAndroid Build Coastguard Worker template <>
419*2d1272b8SAndroid Build Coastguard Worker struct LigatureEntry<false>
420*2d1272b8SAndroid Build Coastguard Worker {
421*2d1272b8SAndroid Build Coastguard Worker   enum Flags
422*2d1272b8SAndroid Build Coastguard Worker   {
423*2d1272b8SAndroid Build Coastguard Worker     SetComponent	= 0x8000,	/* Push this glyph onto the component stack for
424*2d1272b8SAndroid Build Coastguard Worker 					 * eventual processing. */
425*2d1272b8SAndroid Build Coastguard Worker     DontAdvance		= 0x4000,	/* Leave the glyph pointer at this glyph for the
426*2d1272b8SAndroid Build Coastguard Worker 					   next iteration. */
427*2d1272b8SAndroid Build Coastguard Worker     Offset		= 0x3FFF,	/* Byte offset from beginning of subtable to the
428*2d1272b8SAndroid Build Coastguard Worker 					 * ligature action list. This value must be a
429*2d1272b8SAndroid Build Coastguard Worker 					 * multiple of 4. */
430*2d1272b8SAndroid Build Coastguard Worker   };
431*2d1272b8SAndroid Build Coastguard Worker 
432*2d1272b8SAndroid Build Coastguard Worker   typedef void EntryData;
433*2d1272b8SAndroid Build Coastguard Worker 
performActionAAT::LigatureEntry434*2d1272b8SAndroid Build Coastguard Worker   static bool performAction (const Entry<EntryData> &entry)
435*2d1272b8SAndroid Build Coastguard Worker   { return entry.flags & Offset; }
436*2d1272b8SAndroid Build Coastguard Worker 
ligActionIndexAAT::LigatureEntry437*2d1272b8SAndroid Build Coastguard Worker   static unsigned int ligActionIndex (const Entry<EntryData> &entry)
438*2d1272b8SAndroid Build Coastguard Worker   { return entry.flags & Offset; }
439*2d1272b8SAndroid Build Coastguard Worker };
440*2d1272b8SAndroid Build Coastguard Worker 
441*2d1272b8SAndroid Build Coastguard Worker 
442*2d1272b8SAndroid Build Coastguard Worker template <typename Types>
443*2d1272b8SAndroid Build Coastguard Worker struct LigatureSubtable
444*2d1272b8SAndroid Build Coastguard Worker {
445*2d1272b8SAndroid Build Coastguard Worker   typedef typename Types::HBUINT HBUINT;
446*2d1272b8SAndroid Build Coastguard Worker 
447*2d1272b8SAndroid Build Coastguard Worker   typedef LigatureEntry<Types::extended> LigatureEntryT;
448*2d1272b8SAndroid Build Coastguard Worker   typedef typename LigatureEntryT::EntryData EntryData;
449*2d1272b8SAndroid Build Coastguard Worker 
450*2d1272b8SAndroid Build Coastguard Worker   struct driver_context_t
451*2d1272b8SAndroid Build Coastguard Worker   {
452*2d1272b8SAndroid Build Coastguard Worker     static constexpr bool in_place = false;
453*2d1272b8SAndroid Build Coastguard Worker     enum
454*2d1272b8SAndroid Build Coastguard Worker     {
455*2d1272b8SAndroid Build Coastguard Worker       DontAdvance	= LigatureEntryT::DontAdvance,
456*2d1272b8SAndroid Build Coastguard Worker     };
457*2d1272b8SAndroid Build Coastguard Worker     enum LigActionFlags
458*2d1272b8SAndroid Build Coastguard Worker     {
459*2d1272b8SAndroid Build Coastguard Worker       LigActionLast	= 0x80000000,	/* This is the last action in the list. This also
460*2d1272b8SAndroid Build Coastguard Worker 					 * implies storage. */
461*2d1272b8SAndroid Build Coastguard Worker       LigActionStore	= 0x40000000,	/* Store the ligature at the current cumulated index
462*2d1272b8SAndroid Build Coastguard Worker 					 * in the ligature table in place of the marked
463*2d1272b8SAndroid Build Coastguard Worker 					 * (i.e. currently-popped) glyph. */
464*2d1272b8SAndroid Build Coastguard Worker       LigActionOffset	= 0x3FFFFFFF,	/* A 30-bit value which is sign-extended to 32-bits
465*2d1272b8SAndroid Build Coastguard Worker 					 * and added to the glyph ID, resulting in an index
466*2d1272b8SAndroid Build Coastguard Worker 					 * into the component table. */
467*2d1272b8SAndroid Build Coastguard Worker     };
468*2d1272b8SAndroid Build Coastguard Worker 
driver_context_tAAT::LigatureSubtable::driver_context_t469*2d1272b8SAndroid Build Coastguard Worker     driver_context_t (const LigatureSubtable *table_,
470*2d1272b8SAndroid Build Coastguard Worker 		      hb_aat_apply_context_t *c_) :
471*2d1272b8SAndroid Build Coastguard Worker 	ret (false),
472*2d1272b8SAndroid Build Coastguard Worker 	c (c_),
473*2d1272b8SAndroid Build Coastguard Worker 	table (table_),
474*2d1272b8SAndroid Build Coastguard Worker 	ligAction (table+table->ligAction),
475*2d1272b8SAndroid Build Coastguard Worker 	component (table+table->component),
476*2d1272b8SAndroid Build Coastguard Worker 	ligature (table+table->ligature),
477*2d1272b8SAndroid Build Coastguard Worker 	match_length (0) {}
478*2d1272b8SAndroid Build Coastguard Worker 
is_actionableAAT::LigatureSubtable::driver_context_t479*2d1272b8SAndroid Build Coastguard Worker     bool is_actionable (hb_buffer_t *buffer HB_UNUSED,
480*2d1272b8SAndroid Build Coastguard Worker 			StateTableDriver<Types, EntryData> *driver HB_UNUSED,
481*2d1272b8SAndroid Build Coastguard Worker 			const Entry<EntryData> &entry) const
482*2d1272b8SAndroid Build Coastguard Worker     {
483*2d1272b8SAndroid Build Coastguard Worker       return LigatureEntryT::performAction (entry);
484*2d1272b8SAndroid Build Coastguard Worker     }
transitionAAT::LigatureSubtable::driver_context_t485*2d1272b8SAndroid Build Coastguard Worker     void transition (hb_buffer_t *buffer,
486*2d1272b8SAndroid Build Coastguard Worker 		     StateTableDriver<Types, EntryData> *driver,
487*2d1272b8SAndroid Build Coastguard Worker 		     const Entry<EntryData> &entry)
488*2d1272b8SAndroid Build Coastguard Worker     {
489*2d1272b8SAndroid Build Coastguard Worker       DEBUG_MSG (APPLY, nullptr, "Ligature transition at %u", buffer->idx);
490*2d1272b8SAndroid Build Coastguard Worker       if (entry.flags & LigatureEntryT::SetComponent)
491*2d1272b8SAndroid Build Coastguard Worker       {
492*2d1272b8SAndroid Build Coastguard Worker 	/* Never mark same index twice, in case DontAdvance was used... */
493*2d1272b8SAndroid Build Coastguard Worker 	if (match_length && match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] == buffer->out_len)
494*2d1272b8SAndroid Build Coastguard Worker 	  match_length--;
495*2d1272b8SAndroid Build Coastguard Worker 
496*2d1272b8SAndroid Build Coastguard Worker 	match_positions[match_length++ % ARRAY_LENGTH (match_positions)] = buffer->out_len;
497*2d1272b8SAndroid Build Coastguard Worker 	DEBUG_MSG (APPLY, nullptr, "Set component at %u", buffer->out_len);
498*2d1272b8SAndroid Build Coastguard Worker       }
499*2d1272b8SAndroid Build Coastguard Worker 
500*2d1272b8SAndroid Build Coastguard Worker       if (LigatureEntryT::performAction (entry))
501*2d1272b8SAndroid Build Coastguard Worker       {
502*2d1272b8SAndroid Build Coastguard Worker 	DEBUG_MSG (APPLY, nullptr, "Perform action with %u", match_length);
503*2d1272b8SAndroid Build Coastguard Worker 	unsigned int end = buffer->out_len;
504*2d1272b8SAndroid Build Coastguard Worker 
505*2d1272b8SAndroid Build Coastguard Worker 	if (unlikely (!match_length))
506*2d1272b8SAndroid Build Coastguard Worker 	  return;
507*2d1272b8SAndroid Build Coastguard Worker 
508*2d1272b8SAndroid Build Coastguard Worker 	if (buffer->idx >= buffer->len)
509*2d1272b8SAndroid Build Coastguard Worker 	  return; /* TODO Work on previous instead? */
510*2d1272b8SAndroid Build Coastguard Worker 
511*2d1272b8SAndroid Build Coastguard Worker 	unsigned int cursor = match_length;
512*2d1272b8SAndroid Build Coastguard Worker 
513*2d1272b8SAndroid Build Coastguard Worker 	unsigned int action_idx = LigatureEntryT::ligActionIndex (entry);
514*2d1272b8SAndroid Build Coastguard Worker 	action_idx = Types::offsetToIndex (action_idx, table, ligAction.arrayZ);
515*2d1272b8SAndroid Build Coastguard Worker 	const HBUINT32 *actionData = &ligAction[action_idx];
516*2d1272b8SAndroid Build Coastguard Worker 
517*2d1272b8SAndroid Build Coastguard Worker 	unsigned int ligature_idx = 0;
518*2d1272b8SAndroid Build Coastguard Worker 	unsigned int action;
519*2d1272b8SAndroid Build Coastguard Worker 	do
520*2d1272b8SAndroid Build Coastguard Worker 	{
521*2d1272b8SAndroid Build Coastguard Worker 	  if (unlikely (!cursor))
522*2d1272b8SAndroid Build Coastguard Worker 	  {
523*2d1272b8SAndroid Build Coastguard Worker 	    /* Stack underflow.  Clear the stack. */
524*2d1272b8SAndroid Build Coastguard Worker 	    DEBUG_MSG (APPLY, nullptr, "Stack underflow");
525*2d1272b8SAndroid Build Coastguard Worker 	    match_length = 0;
526*2d1272b8SAndroid Build Coastguard Worker 	    break;
527*2d1272b8SAndroid Build Coastguard Worker 	  }
528*2d1272b8SAndroid Build Coastguard Worker 
529*2d1272b8SAndroid Build Coastguard Worker 	  DEBUG_MSG (APPLY, nullptr, "Moving to stack position %u", cursor - 1);
530*2d1272b8SAndroid Build Coastguard Worker 	  if (unlikely (!buffer->move_to (match_positions[--cursor % ARRAY_LENGTH (match_positions)]))) return;
531*2d1272b8SAndroid Build Coastguard Worker 
532*2d1272b8SAndroid Build Coastguard Worker 	  if (unlikely (!actionData->sanitize (&c->sanitizer))) break;
533*2d1272b8SAndroid Build Coastguard Worker 	  hb_barrier ();
534*2d1272b8SAndroid Build Coastguard Worker 	  action = *actionData;
535*2d1272b8SAndroid Build Coastguard Worker 
536*2d1272b8SAndroid Build Coastguard Worker 	  uint32_t uoffset = action & LigActionOffset;
537*2d1272b8SAndroid Build Coastguard Worker 	  if (uoffset & 0x20000000)
538*2d1272b8SAndroid Build Coastguard Worker 	    uoffset |= 0xC0000000; /* Sign-extend. */
539*2d1272b8SAndroid Build Coastguard Worker 	  int32_t offset = (int32_t) uoffset;
540*2d1272b8SAndroid Build Coastguard Worker 	  unsigned int component_idx = buffer->cur().codepoint + offset;
541*2d1272b8SAndroid Build Coastguard Worker 	  component_idx = Types::wordOffsetToIndex (component_idx, table, component.arrayZ);
542*2d1272b8SAndroid Build Coastguard Worker 	  const HBUINT16 &componentData = component[component_idx];
543*2d1272b8SAndroid Build Coastguard Worker 	  if (unlikely (!componentData.sanitize (&c->sanitizer))) break;
544*2d1272b8SAndroid Build Coastguard Worker 	  hb_barrier ();
545*2d1272b8SAndroid Build Coastguard Worker 	  ligature_idx += componentData;
546*2d1272b8SAndroid Build Coastguard Worker 
547*2d1272b8SAndroid Build Coastguard Worker 	  DEBUG_MSG (APPLY, nullptr, "Action store %d last %d",
548*2d1272b8SAndroid Build Coastguard Worker 		     bool (action & LigActionStore),
549*2d1272b8SAndroid Build Coastguard Worker 		     bool (action & LigActionLast));
550*2d1272b8SAndroid Build Coastguard Worker 	  if (action & (LigActionStore | LigActionLast))
551*2d1272b8SAndroid Build Coastguard Worker 	  {
552*2d1272b8SAndroid Build Coastguard Worker 	    ligature_idx = Types::offsetToIndex (ligature_idx, table, ligature.arrayZ);
553*2d1272b8SAndroid Build Coastguard Worker 	    const HBGlyphID16 &ligatureData = ligature[ligature_idx];
554*2d1272b8SAndroid Build Coastguard Worker 	    if (unlikely (!ligatureData.sanitize (&c->sanitizer))) break;
555*2d1272b8SAndroid Build Coastguard Worker 	    hb_barrier ();
556*2d1272b8SAndroid Build Coastguard Worker 	    hb_codepoint_t lig = ligatureData;
557*2d1272b8SAndroid Build Coastguard Worker 
558*2d1272b8SAndroid Build Coastguard Worker 	    DEBUG_MSG (APPLY, nullptr, "Produced ligature %u", lig);
559*2d1272b8SAndroid Build Coastguard Worker 	    if (unlikely (!buffer->replace_glyph (lig))) return;
560*2d1272b8SAndroid Build Coastguard Worker 
561*2d1272b8SAndroid Build Coastguard Worker 	    unsigned int lig_end = match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] + 1u;
562*2d1272b8SAndroid Build Coastguard Worker 	    /* Now go and delete all subsequent components. */
563*2d1272b8SAndroid Build Coastguard Worker 	    while (match_length - 1u > cursor)
564*2d1272b8SAndroid Build Coastguard Worker 	    {
565*2d1272b8SAndroid Build Coastguard Worker 	      DEBUG_MSG (APPLY, nullptr, "Skipping ligature component");
566*2d1272b8SAndroid Build Coastguard Worker 	      if (unlikely (!buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]))) return;
567*2d1272b8SAndroid Build Coastguard Worker 	      buffer->cur().unicode_props() |= UPROPS_MASK_IGNORABLE;
568*2d1272b8SAndroid Build Coastguard Worker 	      if (unlikely (!buffer->replace_glyph (DELETED_GLYPH))) return;
569*2d1272b8SAndroid Build Coastguard Worker 	    }
570*2d1272b8SAndroid Build Coastguard Worker 
571*2d1272b8SAndroid Build Coastguard Worker 	    if (unlikely (!buffer->move_to (lig_end))) return;
572*2d1272b8SAndroid Build Coastguard Worker 	    buffer->merge_out_clusters (match_positions[cursor % ARRAY_LENGTH (match_positions)], buffer->out_len);
573*2d1272b8SAndroid Build Coastguard Worker 	  }
574*2d1272b8SAndroid Build Coastguard Worker 
575*2d1272b8SAndroid Build Coastguard Worker 	  actionData++;
576*2d1272b8SAndroid Build Coastguard Worker 	}
577*2d1272b8SAndroid Build Coastguard Worker 	while (!(action & LigActionLast));
578*2d1272b8SAndroid Build Coastguard Worker 	if (unlikely (!buffer->move_to (end))) return;
579*2d1272b8SAndroid Build Coastguard Worker       }
580*2d1272b8SAndroid Build Coastguard Worker     }
581*2d1272b8SAndroid Build Coastguard Worker 
582*2d1272b8SAndroid Build Coastguard Worker     public:
583*2d1272b8SAndroid Build Coastguard Worker     bool ret;
584*2d1272b8SAndroid Build Coastguard Worker     private:
585*2d1272b8SAndroid Build Coastguard Worker     hb_aat_apply_context_t *c;
586*2d1272b8SAndroid Build Coastguard Worker     const LigatureSubtable *table;
587*2d1272b8SAndroid Build Coastguard Worker     const UnsizedArrayOf<HBUINT32> &ligAction;
588*2d1272b8SAndroid Build Coastguard Worker     const UnsizedArrayOf<HBUINT16> &component;
589*2d1272b8SAndroid Build Coastguard Worker     const UnsizedArrayOf<HBGlyphID16> &ligature;
590*2d1272b8SAndroid Build Coastguard Worker     unsigned int match_length;
591*2d1272b8SAndroid Build Coastguard Worker     unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
592*2d1272b8SAndroid Build Coastguard Worker   };
593*2d1272b8SAndroid Build Coastguard Worker 
applyAAT::LigatureSubtable594*2d1272b8SAndroid Build Coastguard Worker   bool apply (hb_aat_apply_context_t *c) const
595*2d1272b8SAndroid Build Coastguard Worker   {
596*2d1272b8SAndroid Build Coastguard Worker     TRACE_APPLY (this);
597*2d1272b8SAndroid Build Coastguard Worker 
598*2d1272b8SAndroid Build Coastguard Worker     driver_context_t dc (this, c);
599*2d1272b8SAndroid Build Coastguard Worker 
600*2d1272b8SAndroid Build Coastguard Worker     StateTableDriver<Types, EntryData> driver (machine, c->face);
601*2d1272b8SAndroid Build Coastguard Worker 
602*2d1272b8SAndroid Build Coastguard Worker     if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) &&
603*2d1272b8SAndroid Build Coastguard Worker 	!c->buffer_digest.may_have (c->machine_glyph_set))
604*2d1272b8SAndroid Build Coastguard Worker       return_trace (false);
605*2d1272b8SAndroid Build Coastguard Worker 
606*2d1272b8SAndroid Build Coastguard Worker     driver.drive (&dc, c);
607*2d1272b8SAndroid Build Coastguard Worker 
608*2d1272b8SAndroid Build Coastguard Worker     return_trace (dc.ret);
609*2d1272b8SAndroid Build Coastguard Worker   }
610*2d1272b8SAndroid Build Coastguard Worker 
sanitizeAAT::LigatureSubtable611*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
612*2d1272b8SAndroid Build Coastguard Worker   {
613*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
614*2d1272b8SAndroid Build Coastguard Worker     /* The rest of array sanitizations are done at run-time. */
615*2d1272b8SAndroid Build Coastguard Worker     return_trace (c->check_struct (this) && machine.sanitize (c) &&
616*2d1272b8SAndroid Build Coastguard Worker 		  hb_barrier () &&
617*2d1272b8SAndroid Build Coastguard Worker 		  ligAction && component && ligature);
618*2d1272b8SAndroid Build Coastguard Worker   }
619*2d1272b8SAndroid Build Coastguard Worker 
620*2d1272b8SAndroid Build Coastguard Worker   public:
621*2d1272b8SAndroid Build Coastguard Worker   StateTable<Types, EntryData>
622*2d1272b8SAndroid Build Coastguard Worker 		machine;
623*2d1272b8SAndroid Build Coastguard Worker   protected:
624*2d1272b8SAndroid Build Coastguard Worker   NNOffsetTo<UnsizedArrayOf<HBUINT32>, HBUINT>
625*2d1272b8SAndroid Build Coastguard Worker 		ligAction;	/* Offset to the ligature action table. */
626*2d1272b8SAndroid Build Coastguard Worker   NNOffsetTo<UnsizedArrayOf<HBUINT16>, HBUINT>
627*2d1272b8SAndroid Build Coastguard Worker 		component;	/* Offset to the component table. */
628*2d1272b8SAndroid Build Coastguard Worker   NNOffsetTo<UnsizedArrayOf<HBGlyphID16>, HBUINT>
629*2d1272b8SAndroid Build Coastguard Worker 		ligature;	/* Offset to the actual ligature lists. */
630*2d1272b8SAndroid Build Coastguard Worker   public:
631*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_STATIC ((StateTable<Types, EntryData>::static_size + 3 * HBUINT::static_size));
632*2d1272b8SAndroid Build Coastguard Worker };
633*2d1272b8SAndroid Build Coastguard Worker 
634*2d1272b8SAndroid Build Coastguard Worker template <typename Types>
635*2d1272b8SAndroid Build Coastguard Worker struct NoncontextualSubtable
636*2d1272b8SAndroid Build Coastguard Worker {
applyAAT::NoncontextualSubtable637*2d1272b8SAndroid Build Coastguard Worker   bool apply (hb_aat_apply_context_t *c) const
638*2d1272b8SAndroid Build Coastguard Worker   {
639*2d1272b8SAndroid Build Coastguard Worker     TRACE_APPLY (this);
640*2d1272b8SAndroid Build Coastguard Worker 
641*2d1272b8SAndroid Build Coastguard Worker     const OT::GDEF &gdef (*c->gdef_table);
642*2d1272b8SAndroid Build Coastguard Worker     bool has_glyph_classes = gdef.has_glyph_classes ();
643*2d1272b8SAndroid Build Coastguard Worker 
644*2d1272b8SAndroid Build Coastguard Worker     bool ret = false;
645*2d1272b8SAndroid Build Coastguard Worker     unsigned int num_glyphs = c->face->get_num_glyphs ();
646*2d1272b8SAndroid Build Coastguard Worker 
647*2d1272b8SAndroid Build Coastguard Worker     hb_glyph_info_t *info = c->buffer->info;
648*2d1272b8SAndroid Build Coastguard Worker     unsigned int count = c->buffer->len;
649*2d1272b8SAndroid Build Coastguard Worker     // If there's only one range, we already checked the flag.
650*2d1272b8SAndroid Build Coastguard Worker     auto *last_range = c->range_flags && (c->range_flags->length > 1) ? &(*c->range_flags)[0] : nullptr;
651*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int i = 0; i < count; i++)
652*2d1272b8SAndroid Build Coastguard Worker     {
653*2d1272b8SAndroid Build Coastguard Worker       /* This block copied from StateTableDriver::drive. Keep in sync. */
654*2d1272b8SAndroid Build Coastguard Worker       if (last_range)
655*2d1272b8SAndroid Build Coastguard Worker       {
656*2d1272b8SAndroid Build Coastguard Worker 	auto *range = last_range;
657*2d1272b8SAndroid Build Coastguard Worker 	{
658*2d1272b8SAndroid Build Coastguard Worker 	  unsigned cluster = info[i].cluster;
659*2d1272b8SAndroid Build Coastguard Worker 	  while (cluster < range->cluster_first)
660*2d1272b8SAndroid Build Coastguard Worker 	    range--;
661*2d1272b8SAndroid Build Coastguard Worker 	  while (cluster > range->cluster_last)
662*2d1272b8SAndroid Build Coastguard Worker 	    range++;
663*2d1272b8SAndroid Build Coastguard Worker 
664*2d1272b8SAndroid Build Coastguard Worker 	  last_range = range;
665*2d1272b8SAndroid Build Coastguard Worker 	}
666*2d1272b8SAndroid Build Coastguard Worker 	if (!(range->flags & c->subtable_flags))
667*2d1272b8SAndroid Build Coastguard Worker 	  continue;
668*2d1272b8SAndroid Build Coastguard Worker       }
669*2d1272b8SAndroid Build Coastguard Worker 
670*2d1272b8SAndroid Build Coastguard Worker       const HBGlyphID16 *replacement = substitute.get_value (info[i].codepoint, num_glyphs);
671*2d1272b8SAndroid Build Coastguard Worker       if (replacement)
672*2d1272b8SAndroid Build Coastguard Worker       {
673*2d1272b8SAndroid Build Coastguard Worker 	info[i].codepoint = *replacement;
674*2d1272b8SAndroid Build Coastguard Worker 	c->buffer_digest.add (*replacement);
675*2d1272b8SAndroid Build Coastguard Worker 	if (has_glyph_classes)
676*2d1272b8SAndroid Build Coastguard Worker 	  _hb_glyph_info_set_glyph_props (&info[i],
677*2d1272b8SAndroid Build Coastguard Worker 					  gdef.get_glyph_props (*replacement));
678*2d1272b8SAndroid Build Coastguard Worker 	ret = true;
679*2d1272b8SAndroid Build Coastguard Worker       }
680*2d1272b8SAndroid Build Coastguard Worker     }
681*2d1272b8SAndroid Build Coastguard Worker 
682*2d1272b8SAndroid Build Coastguard Worker     return_trace (ret);
683*2d1272b8SAndroid Build Coastguard Worker   }
684*2d1272b8SAndroid Build Coastguard Worker 
sanitizeAAT::NoncontextualSubtable685*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
686*2d1272b8SAndroid Build Coastguard Worker   {
687*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
688*2d1272b8SAndroid Build Coastguard Worker     return_trace (substitute.sanitize (c));
689*2d1272b8SAndroid Build Coastguard Worker   }
690*2d1272b8SAndroid Build Coastguard Worker 
691*2d1272b8SAndroid Build Coastguard Worker   protected:
692*2d1272b8SAndroid Build Coastguard Worker   Lookup<HBGlyphID16>	substitute;
693*2d1272b8SAndroid Build Coastguard Worker   public:
694*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_MIN (2);
695*2d1272b8SAndroid Build Coastguard Worker };
696*2d1272b8SAndroid Build Coastguard Worker 
697*2d1272b8SAndroid Build Coastguard Worker template <typename Types>
698*2d1272b8SAndroid Build Coastguard Worker struct InsertionSubtable
699*2d1272b8SAndroid Build Coastguard Worker {
700*2d1272b8SAndroid Build Coastguard Worker   typedef typename Types::HBUINT HBUINT;
701*2d1272b8SAndroid Build Coastguard Worker 
702*2d1272b8SAndroid Build Coastguard Worker   struct EntryData
703*2d1272b8SAndroid Build Coastguard Worker   {
704*2d1272b8SAndroid Build Coastguard Worker     HBUINT16	currentInsertIndex;	/* Zero-based index into the insertion glyph table.
705*2d1272b8SAndroid Build Coastguard Worker 					 * The number of glyphs to be inserted is contained
706*2d1272b8SAndroid Build Coastguard Worker 					 * in the currentInsertCount field in the flags.
707*2d1272b8SAndroid Build Coastguard Worker 					 * A value of 0xFFFF indicates no insertion is to
708*2d1272b8SAndroid Build Coastguard Worker 					 * be done. */
709*2d1272b8SAndroid Build Coastguard Worker     HBUINT16	markedInsertIndex;	/* Zero-based index into the insertion glyph table.
710*2d1272b8SAndroid Build Coastguard Worker 					 * The number of glyphs to be inserted is contained
711*2d1272b8SAndroid Build Coastguard Worker 					 * in the markedInsertCount field in the flags.
712*2d1272b8SAndroid Build Coastguard Worker 					 * A value of 0xFFFF indicates no insertion is to
713*2d1272b8SAndroid Build Coastguard Worker 					 * be done. */
714*2d1272b8SAndroid Build Coastguard Worker     public:
715*2d1272b8SAndroid Build Coastguard Worker     DEFINE_SIZE_STATIC (4);
716*2d1272b8SAndroid Build Coastguard Worker   };
717*2d1272b8SAndroid Build Coastguard Worker 
718*2d1272b8SAndroid Build Coastguard Worker   struct driver_context_t
719*2d1272b8SAndroid Build Coastguard Worker   {
720*2d1272b8SAndroid Build Coastguard Worker     static constexpr bool in_place = false;
721*2d1272b8SAndroid Build Coastguard Worker     enum Flags
722*2d1272b8SAndroid Build Coastguard Worker     {
723*2d1272b8SAndroid Build Coastguard Worker       SetMark		= 0x8000,	/* If set, mark the current glyph. */
724*2d1272b8SAndroid Build Coastguard Worker       DontAdvance	= 0x4000,	/* If set, don't advance to the next glyph before
725*2d1272b8SAndroid Build Coastguard Worker 					 * going to the new state.  This does not mean
726*2d1272b8SAndroid Build Coastguard Worker 					 * that the glyph pointed to is the same one as
727*2d1272b8SAndroid Build Coastguard Worker 					 * before. If you've made insertions immediately
728*2d1272b8SAndroid Build Coastguard Worker 					 * downstream of the current glyph, the next glyph
729*2d1272b8SAndroid Build Coastguard Worker 					 * processed would in fact be the first one
730*2d1272b8SAndroid Build Coastguard Worker 					 * inserted. */
731*2d1272b8SAndroid Build Coastguard Worker       CurrentIsKashidaLike= 0x2000,	/* If set, and the currentInsertList is nonzero,
732*2d1272b8SAndroid Build Coastguard Worker 					 * then the specified glyph list will be inserted
733*2d1272b8SAndroid Build Coastguard Worker 					 * as a kashida-like insertion, either before or
734*2d1272b8SAndroid Build Coastguard Worker 					 * after the current glyph (depending on the state
735*2d1272b8SAndroid Build Coastguard Worker 					 * of the currentInsertBefore flag). If clear, and
736*2d1272b8SAndroid Build Coastguard Worker 					 * the currentInsertList is nonzero, then the
737*2d1272b8SAndroid Build Coastguard Worker 					 * specified glyph list will be inserted as a
738*2d1272b8SAndroid Build Coastguard Worker 					 * split-vowel-like insertion, either before or
739*2d1272b8SAndroid Build Coastguard Worker 					 * after the current glyph (depending on the state
740*2d1272b8SAndroid Build Coastguard Worker 					 * of the currentInsertBefore flag). */
741*2d1272b8SAndroid Build Coastguard Worker       MarkedIsKashidaLike= 0x1000,	/* If set, and the markedInsertList is nonzero,
742*2d1272b8SAndroid Build Coastguard Worker 					 * then the specified glyph list will be inserted
743*2d1272b8SAndroid Build Coastguard Worker 					 * as a kashida-like insertion, either before or
744*2d1272b8SAndroid Build Coastguard Worker 					 * after the marked glyph (depending on the state
745*2d1272b8SAndroid Build Coastguard Worker 					 * of the markedInsertBefore flag). If clear, and
746*2d1272b8SAndroid Build Coastguard Worker 					 * the markedInsertList is nonzero, then the
747*2d1272b8SAndroid Build Coastguard Worker 					 * specified glyph list will be inserted as a
748*2d1272b8SAndroid Build Coastguard Worker 					 * split-vowel-like insertion, either before or
749*2d1272b8SAndroid Build Coastguard Worker 					 * after the marked glyph (depending on the state
750*2d1272b8SAndroid Build Coastguard Worker 					 * of the markedInsertBefore flag). */
751*2d1272b8SAndroid Build Coastguard Worker       CurrentInsertBefore= 0x0800,	/* If set, specifies that insertions are to be made
752*2d1272b8SAndroid Build Coastguard Worker 					 * to the left of the current glyph. If clear,
753*2d1272b8SAndroid Build Coastguard Worker 					 * they're made to the right of the current glyph. */
754*2d1272b8SAndroid Build Coastguard Worker       MarkedInsertBefore= 0x0400,	/* If set, specifies that insertions are to be
755*2d1272b8SAndroid Build Coastguard Worker 					 * made to the left of the marked glyph. If clear,
756*2d1272b8SAndroid Build Coastguard Worker 					 * they're made to the right of the marked glyph. */
757*2d1272b8SAndroid Build Coastguard Worker       CurrentInsertCount= 0x3E0,	/* This 5-bit field is treated as a count of the
758*2d1272b8SAndroid Build Coastguard Worker 					 * number of glyphs to insert at the current
759*2d1272b8SAndroid Build Coastguard Worker 					 * position. Since zero means no insertions, the
760*2d1272b8SAndroid Build Coastguard Worker 					 * largest number of insertions at any given
761*2d1272b8SAndroid Build Coastguard Worker 					 * current location is 31 glyphs. */
762*2d1272b8SAndroid Build Coastguard Worker       MarkedInsertCount= 0x001F,	/* This 5-bit field is treated as a count of the
763*2d1272b8SAndroid Build Coastguard Worker 					 * number of glyphs to insert at the marked
764*2d1272b8SAndroid Build Coastguard Worker 					 * position. Since zero means no insertions, the
765*2d1272b8SAndroid Build Coastguard Worker 					 * largest number of insertions at any given
766*2d1272b8SAndroid Build Coastguard Worker 					 * marked location is 31 glyphs. */
767*2d1272b8SAndroid Build Coastguard Worker     };
768*2d1272b8SAndroid Build Coastguard Worker 
driver_context_tAAT::InsertionSubtable::driver_context_t769*2d1272b8SAndroid Build Coastguard Worker     driver_context_t (const InsertionSubtable *table,
770*2d1272b8SAndroid Build Coastguard Worker 		      hb_aat_apply_context_t *c_) :
771*2d1272b8SAndroid Build Coastguard Worker 	ret (false),
772*2d1272b8SAndroid Build Coastguard Worker 	c (c_),
773*2d1272b8SAndroid Build Coastguard Worker 	mark (0),
774*2d1272b8SAndroid Build Coastguard Worker 	insertionAction (table+table->insertionAction) {}
775*2d1272b8SAndroid Build Coastguard Worker 
is_actionableAAT::InsertionSubtable::driver_context_t776*2d1272b8SAndroid Build Coastguard Worker     bool is_actionable (hb_buffer_t *buffer HB_UNUSED,
777*2d1272b8SAndroid Build Coastguard Worker 			StateTableDriver<Types, EntryData> *driver HB_UNUSED,
778*2d1272b8SAndroid Build Coastguard Worker 			const Entry<EntryData> &entry) const
779*2d1272b8SAndroid Build Coastguard Worker     {
780*2d1272b8SAndroid Build Coastguard Worker       return (entry.flags & (CurrentInsertCount | MarkedInsertCount)) &&
781*2d1272b8SAndroid Build Coastguard Worker 	     (entry.data.currentInsertIndex != 0xFFFF ||entry.data.markedInsertIndex != 0xFFFF);
782*2d1272b8SAndroid Build Coastguard Worker     }
transitionAAT::InsertionSubtable::driver_context_t783*2d1272b8SAndroid Build Coastguard Worker     void transition (hb_buffer_t *buffer,
784*2d1272b8SAndroid Build Coastguard Worker 		     StateTableDriver<Types, EntryData> *driver,
785*2d1272b8SAndroid Build Coastguard Worker 		     const Entry<EntryData> &entry)
786*2d1272b8SAndroid Build Coastguard Worker     {
787*2d1272b8SAndroid Build Coastguard Worker       unsigned int flags = entry.flags;
788*2d1272b8SAndroid Build Coastguard Worker 
789*2d1272b8SAndroid Build Coastguard Worker       unsigned mark_loc = buffer->out_len;
790*2d1272b8SAndroid Build Coastguard Worker 
791*2d1272b8SAndroid Build Coastguard Worker       if (entry.data.markedInsertIndex != 0xFFFF)
792*2d1272b8SAndroid Build Coastguard Worker       {
793*2d1272b8SAndroid Build Coastguard Worker 	unsigned int count = (flags & MarkedInsertCount);
794*2d1272b8SAndroid Build Coastguard Worker 	if (unlikely ((buffer->max_ops -= count) <= 0)) return;
795*2d1272b8SAndroid Build Coastguard Worker 	unsigned int start = entry.data.markedInsertIndex;
796*2d1272b8SAndroid Build Coastguard Worker 	const HBGlyphID16 *glyphs = &insertionAction[start];
797*2d1272b8SAndroid Build Coastguard Worker 	if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
798*2d1272b8SAndroid Build Coastguard Worker 	hb_barrier ();
799*2d1272b8SAndroid Build Coastguard Worker 
800*2d1272b8SAndroid Build Coastguard Worker 	bool before = flags & MarkedInsertBefore;
801*2d1272b8SAndroid Build Coastguard Worker 
802*2d1272b8SAndroid Build Coastguard Worker 	unsigned int end = buffer->out_len;
803*2d1272b8SAndroid Build Coastguard Worker 	if (unlikely (!buffer->move_to (mark))) return;
804*2d1272b8SAndroid Build Coastguard Worker 
805*2d1272b8SAndroid Build Coastguard Worker 	if (buffer->idx < buffer->len && !before)
806*2d1272b8SAndroid Build Coastguard Worker 	  if (unlikely (!buffer->copy_glyph ())) return;
807*2d1272b8SAndroid Build Coastguard Worker 	/* TODO We ignore KashidaLike setting. */
808*2d1272b8SAndroid Build Coastguard Worker 	if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return;
809*2d1272b8SAndroid Build Coastguard Worker 	for (unsigned int i = 0; i < count; i++)
810*2d1272b8SAndroid Build Coastguard Worker 	  c->buffer_digest.add (glyphs[i]);
811*2d1272b8SAndroid Build Coastguard Worker 	ret = true;
812*2d1272b8SAndroid Build Coastguard Worker 	if (buffer->idx < buffer->len && !before)
813*2d1272b8SAndroid Build Coastguard Worker 	  buffer->skip_glyph ();
814*2d1272b8SAndroid Build Coastguard Worker 
815*2d1272b8SAndroid Build Coastguard Worker 	if (unlikely (!buffer->move_to (end + count))) return;
816*2d1272b8SAndroid Build Coastguard Worker 
817*2d1272b8SAndroid Build Coastguard Worker 	buffer->unsafe_to_break_from_outbuffer (mark, hb_min (buffer->idx + 1, buffer->len));
818*2d1272b8SAndroid Build Coastguard Worker       }
819*2d1272b8SAndroid Build Coastguard Worker 
820*2d1272b8SAndroid Build Coastguard Worker       if (flags & SetMark)
821*2d1272b8SAndroid Build Coastguard Worker 	mark = mark_loc;
822*2d1272b8SAndroid Build Coastguard Worker 
823*2d1272b8SAndroid Build Coastguard Worker       if (entry.data.currentInsertIndex != 0xFFFF)
824*2d1272b8SAndroid Build Coastguard Worker       {
825*2d1272b8SAndroid Build Coastguard Worker 	unsigned int count = (flags & CurrentInsertCount) >> 5;
826*2d1272b8SAndroid Build Coastguard Worker 	if (unlikely ((buffer->max_ops -= count) <= 0)) return;
827*2d1272b8SAndroid Build Coastguard Worker 	unsigned int start = entry.data.currentInsertIndex;
828*2d1272b8SAndroid Build Coastguard Worker 	const HBGlyphID16 *glyphs = &insertionAction[start];
829*2d1272b8SAndroid Build Coastguard Worker 	if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
830*2d1272b8SAndroid Build Coastguard Worker 	hb_barrier ();
831*2d1272b8SAndroid Build Coastguard Worker 
832*2d1272b8SAndroid Build Coastguard Worker 	bool before = flags & CurrentInsertBefore;
833*2d1272b8SAndroid Build Coastguard Worker 
834*2d1272b8SAndroid Build Coastguard Worker 	unsigned int end = buffer->out_len;
835*2d1272b8SAndroid Build Coastguard Worker 
836*2d1272b8SAndroid Build Coastguard Worker 	if (buffer->idx < buffer->len && !before)
837*2d1272b8SAndroid Build Coastguard Worker 	  if (unlikely (!buffer->copy_glyph ())) return;
838*2d1272b8SAndroid Build Coastguard Worker 	/* TODO We ignore KashidaLike setting. */
839*2d1272b8SAndroid Build Coastguard Worker 	if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return;
840*2d1272b8SAndroid Build Coastguard Worker 	if (buffer->idx < buffer->len && !before)
841*2d1272b8SAndroid Build Coastguard Worker 	  buffer->skip_glyph ();
842*2d1272b8SAndroid Build Coastguard Worker 
843*2d1272b8SAndroid Build Coastguard Worker 	/* Humm. Not sure where to move to.  There's this wording under
844*2d1272b8SAndroid Build Coastguard Worker 	 * DontAdvance flag:
845*2d1272b8SAndroid Build Coastguard Worker 	 *
846*2d1272b8SAndroid Build Coastguard Worker 	 * "If set, don't update the glyph index before going to the new state.
847*2d1272b8SAndroid Build Coastguard Worker 	 * This does not mean that the glyph pointed to is the same one as
848*2d1272b8SAndroid Build Coastguard Worker 	 * before. If you've made insertions immediately downstream of the
849*2d1272b8SAndroid Build Coastguard Worker 	 * current glyph, the next glyph processed would in fact be the first
850*2d1272b8SAndroid Build Coastguard Worker 	 * one inserted."
851*2d1272b8SAndroid Build Coastguard Worker 	 *
852*2d1272b8SAndroid Build Coastguard Worker 	 * This suggests that if DontAdvance is NOT set, we should move to
853*2d1272b8SAndroid Build Coastguard Worker 	 * end+count.  If it *was*, then move to end, such that newly inserted
854*2d1272b8SAndroid Build Coastguard Worker 	 * glyphs are now visible.
855*2d1272b8SAndroid Build Coastguard Worker 	 *
856*2d1272b8SAndroid Build Coastguard Worker 	 * https://github.com/harfbuzz/harfbuzz/issues/1224#issuecomment-427691417
857*2d1272b8SAndroid Build Coastguard Worker 	 */
858*2d1272b8SAndroid Build Coastguard Worker 	if (unlikely (!buffer->move_to ((flags & DontAdvance) ? end : end + count))) return;
859*2d1272b8SAndroid Build Coastguard Worker       }
860*2d1272b8SAndroid Build Coastguard Worker     }
861*2d1272b8SAndroid Build Coastguard Worker 
862*2d1272b8SAndroid Build Coastguard Worker     public:
863*2d1272b8SAndroid Build Coastguard Worker     bool ret;
864*2d1272b8SAndroid Build Coastguard Worker     private:
865*2d1272b8SAndroid Build Coastguard Worker     hb_aat_apply_context_t *c;
866*2d1272b8SAndroid Build Coastguard Worker     unsigned int mark;
867*2d1272b8SAndroid Build Coastguard Worker     const UnsizedArrayOf<HBGlyphID16> &insertionAction;
868*2d1272b8SAndroid Build Coastguard Worker   };
869*2d1272b8SAndroid Build Coastguard Worker 
applyAAT::InsertionSubtable870*2d1272b8SAndroid Build Coastguard Worker   bool apply (hb_aat_apply_context_t *c) const
871*2d1272b8SAndroid Build Coastguard Worker   {
872*2d1272b8SAndroid Build Coastguard Worker     TRACE_APPLY (this);
873*2d1272b8SAndroid Build Coastguard Worker 
874*2d1272b8SAndroid Build Coastguard Worker     driver_context_t dc (this, c);
875*2d1272b8SAndroid Build Coastguard Worker 
876*2d1272b8SAndroid Build Coastguard Worker     StateTableDriver<Types, EntryData> driver (machine, c->face);
877*2d1272b8SAndroid Build Coastguard Worker 
878*2d1272b8SAndroid Build Coastguard Worker     if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) &&
879*2d1272b8SAndroid Build Coastguard Worker 	!c->buffer_digest.may_have (c->machine_glyph_set))
880*2d1272b8SAndroid Build Coastguard Worker       return_trace (false);
881*2d1272b8SAndroid Build Coastguard Worker 
882*2d1272b8SAndroid Build Coastguard Worker     driver.drive (&dc, c);
883*2d1272b8SAndroid Build Coastguard Worker 
884*2d1272b8SAndroid Build Coastguard Worker     return_trace (dc.ret);
885*2d1272b8SAndroid Build Coastguard Worker   }
886*2d1272b8SAndroid Build Coastguard Worker 
sanitizeAAT::InsertionSubtable887*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
888*2d1272b8SAndroid Build Coastguard Worker   {
889*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
890*2d1272b8SAndroid Build Coastguard Worker     /* The rest of array sanitizations are done at run-time. */
891*2d1272b8SAndroid Build Coastguard Worker     return_trace (c->check_struct (this) && machine.sanitize (c) &&
892*2d1272b8SAndroid Build Coastguard Worker 		  hb_barrier () &&
893*2d1272b8SAndroid Build Coastguard Worker 		  insertionAction);
894*2d1272b8SAndroid Build Coastguard Worker   }
895*2d1272b8SAndroid Build Coastguard Worker 
896*2d1272b8SAndroid Build Coastguard Worker   public:
897*2d1272b8SAndroid Build Coastguard Worker   StateTable<Types, EntryData>
898*2d1272b8SAndroid Build Coastguard Worker 		machine;
899*2d1272b8SAndroid Build Coastguard Worker   protected:
900*2d1272b8SAndroid Build Coastguard Worker   NNOffsetTo<UnsizedArrayOf<HBGlyphID16>, HBUINT>
901*2d1272b8SAndroid Build Coastguard Worker 		insertionAction;	/* Byte offset from stateHeader to the start of
902*2d1272b8SAndroid Build Coastguard Worker 					 * the insertion glyph table. */
903*2d1272b8SAndroid Build Coastguard Worker   public:
904*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_STATIC ((StateTable<Types, EntryData>::static_size + HBUINT::static_size));
905*2d1272b8SAndroid Build Coastguard Worker };
906*2d1272b8SAndroid Build Coastguard Worker 
907*2d1272b8SAndroid Build Coastguard Worker 
908*2d1272b8SAndroid Build Coastguard Worker struct Feature
909*2d1272b8SAndroid Build Coastguard Worker {
sanitizeAAT::Feature910*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
911*2d1272b8SAndroid Build Coastguard Worker   {
912*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
913*2d1272b8SAndroid Build Coastguard Worker     return_trace (c->check_struct (this));
914*2d1272b8SAndroid Build Coastguard Worker   }
915*2d1272b8SAndroid Build Coastguard Worker 
916*2d1272b8SAndroid Build Coastguard Worker   public:
917*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	featureType;	/* The type of feature. */
918*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	featureSetting;	/* The feature's setting (aka selector). */
919*2d1272b8SAndroid Build Coastguard Worker   HBUINT32	enableFlags;	/* Flags for the settings that this feature
920*2d1272b8SAndroid Build Coastguard Worker 				 * and setting enables. */
921*2d1272b8SAndroid Build Coastguard Worker   HBUINT32	disableFlags;	/* Complement of flags for the settings that this
922*2d1272b8SAndroid Build Coastguard Worker 				 * feature and setting disable. */
923*2d1272b8SAndroid Build Coastguard Worker 
924*2d1272b8SAndroid Build Coastguard Worker   public:
925*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_STATIC (12);
926*2d1272b8SAndroid Build Coastguard Worker };
927*2d1272b8SAndroid Build Coastguard Worker 
928*2d1272b8SAndroid Build Coastguard Worker 
929*2d1272b8SAndroid Build Coastguard Worker struct hb_accelerate_subtables_context_t :
930*2d1272b8SAndroid Build Coastguard Worker        hb_dispatch_context_t<hb_accelerate_subtables_context_t>
931*2d1272b8SAndroid Build Coastguard Worker {
932*2d1272b8SAndroid Build Coastguard Worker   struct hb_applicable_t
933*2d1272b8SAndroid Build Coastguard Worker   {
934*2d1272b8SAndroid Build Coastguard Worker     friend struct hb_accelerate_subtables_context_t;
935*2d1272b8SAndroid Build Coastguard Worker     friend struct hb_aat_layout_lookup_accelerator_t;
936*2d1272b8SAndroid Build Coastguard Worker 
937*2d1272b8SAndroid Build Coastguard Worker     public:
938*2d1272b8SAndroid Build Coastguard Worker     hb_set_digest_t digest;
939*2d1272b8SAndroid Build Coastguard Worker 
940*2d1272b8SAndroid Build Coastguard Worker     template <typename T>
init_AAT::hb_accelerate_subtables_context_t::hb_applicable_t941*2d1272b8SAndroid Build Coastguard Worker     auto init_ (const T &obj_, unsigned num_glyphs, hb_priority<1>) HB_AUTO_RETURN
942*2d1272b8SAndroid Build Coastguard Worker     (
943*2d1272b8SAndroid Build Coastguard Worker       obj_.machine.collect_glyphs (this->digest, num_glyphs)
944*2d1272b8SAndroid Build Coastguard Worker     )
945*2d1272b8SAndroid Build Coastguard Worker 
946*2d1272b8SAndroid Build Coastguard Worker     template <typename T>
947*2d1272b8SAndroid Build Coastguard Worker     void init_ (const T &obj_, unsigned num_glyphs, hb_priority<0>)
948*2d1272b8SAndroid Build Coastguard Worker     {
949*2d1272b8SAndroid Build Coastguard Worker       digest = digest.full ();
950*2d1272b8SAndroid Build Coastguard Worker     }
951*2d1272b8SAndroid Build Coastguard Worker 
952*2d1272b8SAndroid Build Coastguard Worker     template <typename T>
initAAT::hb_accelerate_subtables_context_t::hb_applicable_t953*2d1272b8SAndroid Build Coastguard Worker     void init (const T &obj_, unsigned num_glyphs)
954*2d1272b8SAndroid Build Coastguard Worker     {
955*2d1272b8SAndroid Build Coastguard Worker       init_ (obj_, num_glyphs, hb_prioritize);
956*2d1272b8SAndroid Build Coastguard Worker     }
957*2d1272b8SAndroid Build Coastguard Worker   };
958*2d1272b8SAndroid Build Coastguard Worker 
959*2d1272b8SAndroid Build Coastguard Worker   /* Dispatch interface. */
960*2d1272b8SAndroid Build Coastguard Worker   template <typename T>
dispatchAAT::hb_accelerate_subtables_context_t961*2d1272b8SAndroid Build Coastguard Worker   return_t dispatch (const T &obj)
962*2d1272b8SAndroid Build Coastguard Worker   {
963*2d1272b8SAndroid Build Coastguard Worker     hb_applicable_t *entry = &array[i++];
964*2d1272b8SAndroid Build Coastguard Worker 
965*2d1272b8SAndroid Build Coastguard Worker     entry->init (obj, num_glyphs);
966*2d1272b8SAndroid Build Coastguard Worker 
967*2d1272b8SAndroid Build Coastguard Worker     return hb_empty_t ();
968*2d1272b8SAndroid Build Coastguard Worker   }
default_return_valueAAT::hb_accelerate_subtables_context_t969*2d1272b8SAndroid Build Coastguard Worker   static return_t default_return_value () { return hb_empty_t (); }
970*2d1272b8SAndroid Build Coastguard Worker 
stop_sublookup_iterationAAT::hb_accelerate_subtables_context_t971*2d1272b8SAndroid Build Coastguard Worker   bool stop_sublookup_iteration (return_t r) const { return false; }
972*2d1272b8SAndroid Build Coastguard Worker 
hb_accelerate_subtables_context_tAAT::hb_accelerate_subtables_context_t973*2d1272b8SAndroid Build Coastguard Worker   hb_accelerate_subtables_context_t (hb_applicable_t *array_, unsigned num_glyphs_) :
974*2d1272b8SAndroid Build Coastguard Worker 				     hb_dispatch_context_t<hb_accelerate_subtables_context_t> (),
975*2d1272b8SAndroid Build Coastguard Worker 				     array (array_), num_glyphs (num_glyphs_) {}
976*2d1272b8SAndroid Build Coastguard Worker 
977*2d1272b8SAndroid Build Coastguard Worker   hb_applicable_t *array;
978*2d1272b8SAndroid Build Coastguard Worker   unsigned num_glyphs;
979*2d1272b8SAndroid Build Coastguard Worker   unsigned i = 0;
980*2d1272b8SAndroid Build Coastguard Worker };
981*2d1272b8SAndroid Build Coastguard Worker 
982*2d1272b8SAndroid Build Coastguard Worker struct hb_aat_layout_chain_accelerator_t
983*2d1272b8SAndroid Build Coastguard Worker {
984*2d1272b8SAndroid Build Coastguard Worker   template <typename TChain>
createAAT::hb_aat_layout_chain_accelerator_t985*2d1272b8SAndroid Build Coastguard Worker   static hb_aat_layout_chain_accelerator_t *create (const TChain &chain, unsigned num_glyphs)
986*2d1272b8SAndroid Build Coastguard Worker   {
987*2d1272b8SAndroid Build Coastguard Worker     unsigned count = chain.get_subtable_count ();
988*2d1272b8SAndroid Build Coastguard Worker 
989*2d1272b8SAndroid Build Coastguard Worker     unsigned size = sizeof (hb_aat_layout_chain_accelerator_t) -
990*2d1272b8SAndroid Build Coastguard Worker 		    HB_VAR_ARRAY * sizeof (hb_accelerate_subtables_context_t::hb_applicable_t) +
991*2d1272b8SAndroid Build Coastguard Worker 		    count * sizeof (hb_accelerate_subtables_context_t::hb_applicable_t);
992*2d1272b8SAndroid Build Coastguard Worker 
993*2d1272b8SAndroid Build Coastguard Worker     /* The following is a calloc because when we are collecting subtables,
994*2d1272b8SAndroid Build Coastguard Worker      * some of them might be invalid and hence not collect; as a result,
995*2d1272b8SAndroid Build Coastguard Worker      * we might not fill in all the count entries of the subtables array.
996*2d1272b8SAndroid Build Coastguard Worker      * Zeroing it allows the set digest to gatekeep it without having to
997*2d1272b8SAndroid Build Coastguard Worker      * initialize it further. */
998*2d1272b8SAndroid Build Coastguard Worker     auto *thiz = (hb_aat_layout_chain_accelerator_t *) hb_calloc (1, size);
999*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!thiz))
1000*2d1272b8SAndroid Build Coastguard Worker       return nullptr;
1001*2d1272b8SAndroid Build Coastguard Worker 
1002*2d1272b8SAndroid Build Coastguard Worker     hb_accelerate_subtables_context_t c_accelerate_subtables (thiz->subtables, num_glyphs);
1003*2d1272b8SAndroid Build Coastguard Worker     chain.dispatch (&c_accelerate_subtables);
1004*2d1272b8SAndroid Build Coastguard Worker 
1005*2d1272b8SAndroid Build Coastguard Worker     return thiz;
1006*2d1272b8SAndroid Build Coastguard Worker   }
1007*2d1272b8SAndroid Build Coastguard Worker 
1008*2d1272b8SAndroid Build Coastguard Worker   hb_accelerate_subtables_context_t::hb_applicable_t subtables[HB_VAR_ARRAY];
1009*2d1272b8SAndroid Build Coastguard Worker };
1010*2d1272b8SAndroid Build Coastguard Worker 
1011*2d1272b8SAndroid Build Coastguard Worker template <typename Types>
1012*2d1272b8SAndroid Build Coastguard Worker struct ChainSubtable
1013*2d1272b8SAndroid Build Coastguard Worker {
1014*2d1272b8SAndroid Build Coastguard Worker   typedef typename Types::HBUINT HBUINT;
1015*2d1272b8SAndroid Build Coastguard Worker 
1016*2d1272b8SAndroid Build Coastguard Worker   template <typename T>
1017*2d1272b8SAndroid Build Coastguard Worker   friend struct Chain;
1018*2d1272b8SAndroid Build Coastguard Worker 
get_sizeAAT::ChainSubtable1019*2d1272b8SAndroid Build Coastguard Worker   unsigned int get_size () const     { return length; }
get_typeAAT::ChainSubtable1020*2d1272b8SAndroid Build Coastguard Worker   unsigned int get_type () const     { return coverage & 0xFF; }
get_coverageAAT::ChainSubtable1021*2d1272b8SAndroid Build Coastguard Worker   unsigned int get_coverage () const { return coverage >> (sizeof (HBUINT) * 8 - 8); }
1022*2d1272b8SAndroid Build Coastguard Worker 
1023*2d1272b8SAndroid Build Coastguard Worker   enum Coverage
1024*2d1272b8SAndroid Build Coastguard Worker   {
1025*2d1272b8SAndroid Build Coastguard Worker     Vertical		= 0x80,	/* If set, this subtable will only be applied
1026*2d1272b8SAndroid Build Coastguard Worker 				 * to vertical text. If clear, this subtable
1027*2d1272b8SAndroid Build Coastguard Worker 				 * will only be applied to horizontal text. */
1028*2d1272b8SAndroid Build Coastguard Worker     Backwards		= 0x40,	/* If set, this subtable will process glyphs
1029*2d1272b8SAndroid Build Coastguard Worker 				 * in descending order. If clear, it will
1030*2d1272b8SAndroid Build Coastguard Worker 				 * process the glyphs in ascending order. */
1031*2d1272b8SAndroid Build Coastguard Worker     AllDirections	= 0x20,	/* If set, this subtable will be applied to
1032*2d1272b8SAndroid Build Coastguard Worker 				 * both horizontal and vertical text (i.e.
1033*2d1272b8SAndroid Build Coastguard Worker 				 * the state of bit 0x80000000 is ignored). */
1034*2d1272b8SAndroid Build Coastguard Worker     Logical		= 0x10,	/* If set, this subtable will process glyphs
1035*2d1272b8SAndroid Build Coastguard Worker 				 * in logical order (or reverse logical order,
1036*2d1272b8SAndroid Build Coastguard Worker 				 * depending on the value of bit 0x80000000). */
1037*2d1272b8SAndroid Build Coastguard Worker   };
1038*2d1272b8SAndroid Build Coastguard Worker   enum Type
1039*2d1272b8SAndroid Build Coastguard Worker   {
1040*2d1272b8SAndroid Build Coastguard Worker     Rearrangement	= 0,
1041*2d1272b8SAndroid Build Coastguard Worker     Contextual		= 1,
1042*2d1272b8SAndroid Build Coastguard Worker     Ligature		= 2,
1043*2d1272b8SAndroid Build Coastguard Worker     Noncontextual	= 4,
1044*2d1272b8SAndroid Build Coastguard Worker     Insertion		= 5
1045*2d1272b8SAndroid Build Coastguard Worker   };
1046*2d1272b8SAndroid Build Coastguard Worker 
1047*2d1272b8SAndroid Build Coastguard Worker   template <typename context_t, typename ...Ts>
dispatchAAT::ChainSubtable1048*2d1272b8SAndroid Build Coastguard Worker   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
1049*2d1272b8SAndroid Build Coastguard Worker   {
1050*2d1272b8SAndroid Build Coastguard Worker     unsigned int subtable_type = get_type ();
1051*2d1272b8SAndroid Build Coastguard Worker     TRACE_DISPATCH (this, subtable_type);
1052*2d1272b8SAndroid Build Coastguard Worker     switch (subtable_type) {
1053*2d1272b8SAndroid Build Coastguard Worker     case Rearrangement:		return_trace (c->dispatch (u.rearrangement, std::forward<Ts> (ds)...));
1054*2d1272b8SAndroid Build Coastguard Worker     case Contextual:		return_trace (c->dispatch (u.contextual, std::forward<Ts> (ds)...));
1055*2d1272b8SAndroid Build Coastguard Worker     case Ligature:		return_trace (c->dispatch (u.ligature, std::forward<Ts> (ds)...));
1056*2d1272b8SAndroid Build Coastguard Worker     case Noncontextual:		return_trace (c->dispatch (u.noncontextual, std::forward<Ts> (ds)...));
1057*2d1272b8SAndroid Build Coastguard Worker     case Insertion:		return_trace (c->dispatch (u.insertion, std::forward<Ts> (ds)...));
1058*2d1272b8SAndroid Build Coastguard Worker     default:			return_trace (c->default_return_value ());
1059*2d1272b8SAndroid Build Coastguard Worker     }
1060*2d1272b8SAndroid Build Coastguard Worker   }
1061*2d1272b8SAndroid Build Coastguard Worker 
applyAAT::ChainSubtable1062*2d1272b8SAndroid Build Coastguard Worker   bool apply (hb_aat_apply_context_t *c) const
1063*2d1272b8SAndroid Build Coastguard Worker   {
1064*2d1272b8SAndroid Build Coastguard Worker     TRACE_APPLY (this);
1065*2d1272b8SAndroid Build Coastguard Worker     // Disabled for https://github.com/harfbuzz/harfbuzz/issues/4873
1066*2d1272b8SAndroid Build Coastguard Worker     //hb_sanitize_with_object_t with (&c->sanitizer, this);
1067*2d1272b8SAndroid Build Coastguard Worker     return_trace (dispatch (c));
1068*2d1272b8SAndroid Build Coastguard Worker   }
1069*2d1272b8SAndroid Build Coastguard Worker 
sanitizeAAT::ChainSubtable1070*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
1071*2d1272b8SAndroid Build Coastguard Worker   {
1072*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
1073*2d1272b8SAndroid Build Coastguard Worker     if (!(length.sanitize (c) &&
1074*2d1272b8SAndroid Build Coastguard Worker 	  hb_barrier () &&
1075*2d1272b8SAndroid Build Coastguard Worker 	  length >= min_size &&
1076*2d1272b8SAndroid Build Coastguard Worker 	  c->check_range (this, length)))
1077*2d1272b8SAndroid Build Coastguard Worker       return_trace (false);
1078*2d1272b8SAndroid Build Coastguard Worker 
1079*2d1272b8SAndroid Build Coastguard Worker     // Disabled for https://github.com/harfbuzz/harfbuzz/issues/4873
1080*2d1272b8SAndroid Build Coastguard Worker     //hb_sanitize_with_object_t with (c, this);
1081*2d1272b8SAndroid Build Coastguard Worker     return_trace (dispatch (c));
1082*2d1272b8SAndroid Build Coastguard Worker   }
1083*2d1272b8SAndroid Build Coastguard Worker 
1084*2d1272b8SAndroid Build Coastguard Worker   protected:
1085*2d1272b8SAndroid Build Coastguard Worker   HBUINT	length;		/* Total subtable length, including this header. */
1086*2d1272b8SAndroid Build Coastguard Worker   HBUINT	coverage;	/* Coverage flags and subtable type. */
1087*2d1272b8SAndroid Build Coastguard Worker   HBUINT32	subFeatureFlags;/* The 32-bit mask identifying which subtable this is. */
1088*2d1272b8SAndroid Build Coastguard Worker   union {
1089*2d1272b8SAndroid Build Coastguard Worker   RearrangementSubtable<Types>	rearrangement;
1090*2d1272b8SAndroid Build Coastguard Worker   ContextualSubtable<Types>	contextual;
1091*2d1272b8SAndroid Build Coastguard Worker   LigatureSubtable<Types>	ligature;
1092*2d1272b8SAndroid Build Coastguard Worker   NoncontextualSubtable<Types>	noncontextual;
1093*2d1272b8SAndroid Build Coastguard Worker   InsertionSubtable<Types>	insertion;
1094*2d1272b8SAndroid Build Coastguard Worker   } u;
1095*2d1272b8SAndroid Build Coastguard Worker   public:
1096*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_MIN (2 * sizeof (HBUINT) + 4);
1097*2d1272b8SAndroid Build Coastguard Worker };
1098*2d1272b8SAndroid Build Coastguard Worker 
1099*2d1272b8SAndroid Build Coastguard Worker template <typename Types>
1100*2d1272b8SAndroid Build Coastguard Worker struct Chain
1101*2d1272b8SAndroid Build Coastguard Worker {
1102*2d1272b8SAndroid Build Coastguard Worker   typedef typename Types::HBUINT HBUINT;
1103*2d1272b8SAndroid Build Coastguard Worker 
get_subtable_countAAT::Chain1104*2d1272b8SAndroid Build Coastguard Worker   unsigned get_subtable_count () const { return subtableCount; }
1105*2d1272b8SAndroid Build Coastguard Worker 
compile_flagsAAT::Chain1106*2d1272b8SAndroid Build Coastguard Worker   hb_mask_t compile_flags (const hb_aat_map_builder_t *map) const
1107*2d1272b8SAndroid Build Coastguard Worker   {
1108*2d1272b8SAndroid Build Coastguard Worker     hb_mask_t flags = defaultFlags;
1109*2d1272b8SAndroid Build Coastguard Worker     {
1110*2d1272b8SAndroid Build Coastguard Worker       unsigned int count = featureCount;
1111*2d1272b8SAndroid Build Coastguard Worker       for (unsigned i = 0; i < count; i++)
1112*2d1272b8SAndroid Build Coastguard Worker       {
1113*2d1272b8SAndroid Build Coastguard Worker 	const Feature &feature = featureZ[i];
1114*2d1272b8SAndroid Build Coastguard Worker 	hb_aat_layout_feature_type_t type = (hb_aat_layout_feature_type_t) (unsigned int) feature.featureType;
1115*2d1272b8SAndroid Build Coastguard Worker 	hb_aat_layout_feature_selector_t setting = (hb_aat_layout_feature_selector_t) (unsigned int) feature.featureSetting;
1116*2d1272b8SAndroid Build Coastguard Worker       retry:
1117*2d1272b8SAndroid Build Coastguard Worker 	// Check whether this type/setting pair was requested in the map, and if so, apply its flags.
1118*2d1272b8SAndroid Build Coastguard Worker 	// (The search here only looks at the type and setting fields of feature_info_t.)
1119*2d1272b8SAndroid Build Coastguard Worker 	hb_aat_map_builder_t::feature_info_t info = { type, setting, false, 0 };
1120*2d1272b8SAndroid Build Coastguard Worker 	if (map->current_features.bsearch (info))
1121*2d1272b8SAndroid Build Coastguard Worker 	{
1122*2d1272b8SAndroid Build Coastguard Worker 	  flags &= feature.disableFlags;
1123*2d1272b8SAndroid Build Coastguard Worker 	  flags |= feature.enableFlags;
1124*2d1272b8SAndroid Build Coastguard Worker 	}
1125*2d1272b8SAndroid Build Coastguard Worker 	else if (type == HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE && setting == HB_AAT_LAYOUT_FEATURE_SELECTOR_SMALL_CAPS)
1126*2d1272b8SAndroid Build Coastguard Worker 	{
1127*2d1272b8SAndroid Build Coastguard Worker 	  /* Deprecated. https://github.com/harfbuzz/harfbuzz/issues/1342 */
1128*2d1272b8SAndroid Build Coastguard Worker 	  type = HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE;
1129*2d1272b8SAndroid Build Coastguard Worker 	  setting = HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS;
1130*2d1272b8SAndroid Build Coastguard Worker 	  goto retry;
1131*2d1272b8SAndroid Build Coastguard Worker 	}
1132*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_NO_AAT
1133*2d1272b8SAndroid Build Coastguard Worker 	else if (type == HB_AAT_LAYOUT_FEATURE_TYPE_LANGUAGE_TAG_TYPE && setting &&
1134*2d1272b8SAndroid Build Coastguard Worker 		 /* TODO: Rudimentary language matching. */
1135*2d1272b8SAndroid Build Coastguard Worker 		 hb_language_matches (map->face->table.ltag->get_language (setting - 1), map->props.language))
1136*2d1272b8SAndroid Build Coastguard Worker 	{
1137*2d1272b8SAndroid Build Coastguard Worker 	  flags &= feature.disableFlags;
1138*2d1272b8SAndroid Build Coastguard Worker 	  flags |= feature.enableFlags;
1139*2d1272b8SAndroid Build Coastguard Worker 	}
1140*2d1272b8SAndroid Build Coastguard Worker #endif
1141*2d1272b8SAndroid Build Coastguard Worker       }
1142*2d1272b8SAndroid Build Coastguard Worker     }
1143*2d1272b8SAndroid Build Coastguard Worker     return flags;
1144*2d1272b8SAndroid Build Coastguard Worker   }
1145*2d1272b8SAndroid Build Coastguard Worker 
applyAAT::Chain1146*2d1272b8SAndroid Build Coastguard Worker   void apply (hb_aat_apply_context_t *c,
1147*2d1272b8SAndroid Build Coastguard Worker 	      const hb_aat_layout_chain_accelerator_t *accel) const
1148*2d1272b8SAndroid Build Coastguard Worker   {
1149*2d1272b8SAndroid Build Coastguard Worker     const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
1150*2d1272b8SAndroid Build Coastguard Worker     unsigned int count = subtableCount;
1151*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int i = 0; i < count; i++)
1152*2d1272b8SAndroid Build Coastguard Worker     {
1153*2d1272b8SAndroid Build Coastguard Worker       bool reverse;
1154*2d1272b8SAndroid Build Coastguard Worker 
1155*2d1272b8SAndroid Build Coastguard Worker       if (hb_none (hb_iter (c->range_flags) |
1156*2d1272b8SAndroid Build Coastguard Worker 		   hb_map ([&subtable] (const hb_aat_map_t::range_flags_t _) -> bool { return subtable->subFeatureFlags & (_.flags); })))
1157*2d1272b8SAndroid Build Coastguard Worker 	goto skip;
1158*2d1272b8SAndroid Build Coastguard Worker       c->subtable_flags = subtable->subFeatureFlags;
1159*2d1272b8SAndroid Build Coastguard Worker       c->machine_glyph_set = accel ? accel->subtables[i].digest : hb_set_digest_t::full ();
1160*2d1272b8SAndroid Build Coastguard Worker 
1161*2d1272b8SAndroid Build Coastguard Worker       if (!(subtable->get_coverage() & ChainSubtable<Types>::AllDirections) &&
1162*2d1272b8SAndroid Build Coastguard Worker 	  HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) !=
1163*2d1272b8SAndroid Build Coastguard Worker 	  bool (subtable->get_coverage() & ChainSubtable<Types>::Vertical))
1164*2d1272b8SAndroid Build Coastguard Worker 	goto skip;
1165*2d1272b8SAndroid Build Coastguard Worker 
1166*2d1272b8SAndroid Build Coastguard Worker       /* Buffer contents is always in logical direction.  Determine if
1167*2d1272b8SAndroid Build Coastguard Worker        * we need to reverse before applying this subtable.  We reverse
1168*2d1272b8SAndroid Build Coastguard Worker        * back after if we did reverse indeed.
1169*2d1272b8SAndroid Build Coastguard Worker        *
1170*2d1272b8SAndroid Build Coastguard Worker        * Quoting the spac:
1171*2d1272b8SAndroid Build Coastguard Worker        * """
1172*2d1272b8SAndroid Build Coastguard Worker        * Bits 28 and 30 of the coverage field control the order in which
1173*2d1272b8SAndroid Build Coastguard Worker        * glyphs are processed when the subtable is run by the layout engine.
1174*2d1272b8SAndroid Build Coastguard Worker        * Bit 28 is used to indicate if the glyph processing direction is
1175*2d1272b8SAndroid Build Coastguard Worker        * the same as logical order or layout order. Bit 30 is used to
1176*2d1272b8SAndroid Build Coastguard Worker        * indicate whether glyphs are processed forwards or backwards within
1177*2d1272b8SAndroid Build Coastguard Worker        * that order.
1178*2d1272b8SAndroid Build Coastguard Worker 
1179*2d1272b8SAndroid Build Coastguard Worker 		Bit 30	Bit 28	Interpretation for Horizontal Text
1180*2d1272b8SAndroid Build Coastguard Worker 		0	0	The subtable is processed in layout order
1181*2d1272b8SAndroid Build Coastguard Worker 				(the same order as the glyphs, which is
1182*2d1272b8SAndroid Build Coastguard Worker 				always left-to-right).
1183*2d1272b8SAndroid Build Coastguard Worker 		1	0	The subtable is processed in reverse layout order
1184*2d1272b8SAndroid Build Coastguard Worker 				(the order opposite that of the glyphs, which is
1185*2d1272b8SAndroid Build Coastguard Worker 				always right-to-left).
1186*2d1272b8SAndroid Build Coastguard Worker 		0	1	The subtable is processed in logical order
1187*2d1272b8SAndroid Build Coastguard Worker 				(the same order as the characters, which may be
1188*2d1272b8SAndroid Build Coastguard Worker 				left-to-right or right-to-left).
1189*2d1272b8SAndroid Build Coastguard Worker 		1	1	The subtable is processed in reverse logical order
1190*2d1272b8SAndroid Build Coastguard Worker 				(the order opposite that of the characters, which
1191*2d1272b8SAndroid Build Coastguard Worker 				may be right-to-left or left-to-right).
1192*2d1272b8SAndroid Build Coastguard Worker        */
1193*2d1272b8SAndroid Build Coastguard Worker       reverse = subtable->get_coverage () & ChainSubtable<Types>::Logical ?
1194*2d1272b8SAndroid Build Coastguard Worker 		bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) :
1195*2d1272b8SAndroid Build Coastguard Worker 		bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) !=
1196*2d1272b8SAndroid Build Coastguard Worker 		HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
1197*2d1272b8SAndroid Build Coastguard Worker 
1198*2d1272b8SAndroid Build Coastguard Worker       if (!c->buffer->message (c->font, "start chainsubtable %u", c->lookup_index))
1199*2d1272b8SAndroid Build Coastguard Worker 	goto skip;
1200*2d1272b8SAndroid Build Coastguard Worker 
1201*2d1272b8SAndroid Build Coastguard Worker       if (reverse)
1202*2d1272b8SAndroid Build Coastguard Worker 	c->buffer->reverse ();
1203*2d1272b8SAndroid Build Coastguard Worker 
1204*2d1272b8SAndroid Build Coastguard Worker       subtable->apply (c);
1205*2d1272b8SAndroid Build Coastguard Worker 
1206*2d1272b8SAndroid Build Coastguard Worker       if (reverse)
1207*2d1272b8SAndroid Build Coastguard Worker 	c->buffer->reverse ();
1208*2d1272b8SAndroid Build Coastguard Worker 
1209*2d1272b8SAndroid Build Coastguard Worker       (void) c->buffer->message (c->font, "end chainsubtable %u", c->lookup_index);
1210*2d1272b8SAndroid Build Coastguard Worker 
1211*2d1272b8SAndroid Build Coastguard Worker       if (unlikely (!c->buffer->successful)) return;
1212*2d1272b8SAndroid Build Coastguard Worker 
1213*2d1272b8SAndroid Build Coastguard Worker     skip:
1214*2d1272b8SAndroid Build Coastguard Worker       subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
1215*2d1272b8SAndroid Build Coastguard Worker       c->set_lookup_index (c->lookup_index + 1);
1216*2d1272b8SAndroid Build Coastguard Worker     }
1217*2d1272b8SAndroid Build Coastguard Worker   }
1218*2d1272b8SAndroid Build Coastguard Worker 
get_sizeAAT::Chain1219*2d1272b8SAndroid Build Coastguard Worker   unsigned int get_size () const { return length; }
1220*2d1272b8SAndroid Build Coastguard Worker 
1221*2d1272b8SAndroid Build Coastguard Worker   template <typename context_t, typename ...Ts>
dispatchAAT::Chain1222*2d1272b8SAndroid Build Coastguard Worker   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
1223*2d1272b8SAndroid Build Coastguard Worker   {
1224*2d1272b8SAndroid Build Coastguard Worker     const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
1225*2d1272b8SAndroid Build Coastguard Worker     unsigned int count = subtableCount;
1226*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int i = 0; i < count; i++)
1227*2d1272b8SAndroid Build Coastguard Worker     {
1228*2d1272b8SAndroid Build Coastguard Worker       typename context_t::return_t ret = subtable->dispatch (c, std::forward<Ts> (ds)...);
1229*2d1272b8SAndroid Build Coastguard Worker       if (c->stop_sublookup_iteration (ret))
1230*2d1272b8SAndroid Build Coastguard Worker 	return ret;
1231*2d1272b8SAndroid Build Coastguard Worker       subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
1232*2d1272b8SAndroid Build Coastguard Worker     }
1233*2d1272b8SAndroid Build Coastguard Worker     return c->default_return_value ();
1234*2d1272b8SAndroid Build Coastguard Worker   }
1235*2d1272b8SAndroid Build Coastguard Worker 
sanitizeAAT::Chain1236*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c, unsigned int version) const
1237*2d1272b8SAndroid Build Coastguard Worker   {
1238*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
1239*2d1272b8SAndroid Build Coastguard Worker     if (!(length.sanitize (c) &&
1240*2d1272b8SAndroid Build Coastguard Worker 	  hb_barrier () &&
1241*2d1272b8SAndroid Build Coastguard Worker 	  length >= min_size &&
1242*2d1272b8SAndroid Build Coastguard Worker 	  c->check_range (this, length)))
1243*2d1272b8SAndroid Build Coastguard Worker       return_trace (false);
1244*2d1272b8SAndroid Build Coastguard Worker 
1245*2d1272b8SAndroid Build Coastguard Worker     if (!c->check_array (featureZ.arrayZ, featureCount))
1246*2d1272b8SAndroid Build Coastguard Worker       return_trace (false);
1247*2d1272b8SAndroid Build Coastguard Worker 
1248*2d1272b8SAndroid Build Coastguard Worker     const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
1249*2d1272b8SAndroid Build Coastguard Worker     unsigned int count = subtableCount;
1250*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int i = 0; i < count; i++)
1251*2d1272b8SAndroid Build Coastguard Worker     {
1252*2d1272b8SAndroid Build Coastguard Worker       if (!subtable->sanitize (c))
1253*2d1272b8SAndroid Build Coastguard Worker 	return_trace (false);
1254*2d1272b8SAndroid Build Coastguard Worker       hb_barrier ();
1255*2d1272b8SAndroid Build Coastguard Worker       subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
1256*2d1272b8SAndroid Build Coastguard Worker     }
1257*2d1272b8SAndroid Build Coastguard Worker 
1258*2d1272b8SAndroid Build Coastguard Worker     if (version >= 3)
1259*2d1272b8SAndroid Build Coastguard Worker     {
1260*2d1272b8SAndroid Build Coastguard Worker       const SubtableGlyphCoverage *coverage = (const SubtableGlyphCoverage *) subtable;
1261*2d1272b8SAndroid Build Coastguard Worker       if (!coverage->sanitize (c, count))
1262*2d1272b8SAndroid Build Coastguard Worker         return_trace (false);
1263*2d1272b8SAndroid Build Coastguard Worker     }
1264*2d1272b8SAndroid Build Coastguard Worker 
1265*2d1272b8SAndroid Build Coastguard Worker     return_trace (true);
1266*2d1272b8SAndroid Build Coastguard Worker   }
1267*2d1272b8SAndroid Build Coastguard Worker 
1268*2d1272b8SAndroid Build Coastguard Worker   protected:
1269*2d1272b8SAndroid Build Coastguard Worker   HBUINT32	defaultFlags;	/* The default specification for subtables. */
1270*2d1272b8SAndroid Build Coastguard Worker   HBUINT32	length;		/* Total byte count, including this header. */
1271*2d1272b8SAndroid Build Coastguard Worker   HBUINT	featureCount;	/* Number of feature subtable entries. */
1272*2d1272b8SAndroid Build Coastguard Worker   HBUINT	subtableCount;	/* The number of subtables in the chain. */
1273*2d1272b8SAndroid Build Coastguard Worker 
1274*2d1272b8SAndroid Build Coastguard Worker   UnsizedArrayOf<Feature>	featureZ;	/* Features. */
1275*2d1272b8SAndroid Build Coastguard Worker /*ChainSubtable	firstSubtable;*//* Subtables. */
1276*2d1272b8SAndroid Build Coastguard Worker /*SubtableGlyphCoverage coverages*//* Only if version >= 3. */
1277*2d1272b8SAndroid Build Coastguard Worker 
1278*2d1272b8SAndroid Build Coastguard Worker   public:
1279*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_MIN (8 + 2 * sizeof (HBUINT));
1280*2d1272b8SAndroid Build Coastguard Worker };
1281*2d1272b8SAndroid Build Coastguard Worker 
1282*2d1272b8SAndroid Build Coastguard Worker 
1283*2d1272b8SAndroid Build Coastguard Worker /*
1284*2d1272b8SAndroid Build Coastguard Worker  * The 'mort'/'morx' Table
1285*2d1272b8SAndroid Build Coastguard Worker  */
1286*2d1272b8SAndroid Build Coastguard Worker 
1287*2d1272b8SAndroid Build Coastguard Worker template <typename T, typename Types, hb_tag_t TAG>
1288*2d1272b8SAndroid Build Coastguard Worker struct mortmorx
1289*2d1272b8SAndroid Build Coastguard Worker {
1290*2d1272b8SAndroid Build Coastguard Worker   static constexpr hb_tag_t tableTag = TAG;
1291*2d1272b8SAndroid Build Coastguard Worker 
has_dataAAT::mortmorx1292*2d1272b8SAndroid Build Coastguard Worker   bool has_data () const { return version != 0; }
1293*2d1272b8SAndroid Build Coastguard Worker 
1294*2d1272b8SAndroid Build Coastguard Worker   struct accelerator_t
1295*2d1272b8SAndroid Build Coastguard Worker   {
accelerator_tAAT::mortmorx::accelerator_t1296*2d1272b8SAndroid Build Coastguard Worker     accelerator_t (hb_face_t *face)
1297*2d1272b8SAndroid Build Coastguard Worker     {
1298*2d1272b8SAndroid Build Coastguard Worker       hb_sanitize_context_t sc;
1299*2d1272b8SAndroid Build Coastguard Worker       this->table = sc.reference_table<T> (face);
1300*2d1272b8SAndroid Build Coastguard Worker 
1301*2d1272b8SAndroid Build Coastguard Worker       this->chain_count = table->get_chain_count ();
1302*2d1272b8SAndroid Build Coastguard Worker 
1303*2d1272b8SAndroid Build Coastguard Worker       this->accels = (hb_atomic_ptr_t<hb_aat_layout_chain_accelerator_t> *) hb_calloc (this->chain_count, sizeof (*accels));
1304*2d1272b8SAndroid Build Coastguard Worker       if (unlikely (!this->accels))
1305*2d1272b8SAndroid Build Coastguard Worker       {
1306*2d1272b8SAndroid Build Coastguard Worker 	this->chain_count = 0;
1307*2d1272b8SAndroid Build Coastguard Worker 	this->table.destroy ();
1308*2d1272b8SAndroid Build Coastguard Worker 	this->table = hb_blob_get_empty ();
1309*2d1272b8SAndroid Build Coastguard Worker       }
1310*2d1272b8SAndroid Build Coastguard Worker     }
~accelerator_tAAT::mortmorx::accelerator_t1311*2d1272b8SAndroid Build Coastguard Worker     ~accelerator_t ()
1312*2d1272b8SAndroid Build Coastguard Worker     {
1313*2d1272b8SAndroid Build Coastguard Worker       for (unsigned int i = 0; i < this->chain_count; i++)
1314*2d1272b8SAndroid Build Coastguard Worker 	hb_free (this->accels[i]);
1315*2d1272b8SAndroid Build Coastguard Worker       hb_free (this->accels);
1316*2d1272b8SAndroid Build Coastguard Worker       this->table.destroy ();
1317*2d1272b8SAndroid Build Coastguard Worker     }
1318*2d1272b8SAndroid Build Coastguard Worker 
get_blobAAT::mortmorx::accelerator_t1319*2d1272b8SAndroid Build Coastguard Worker     hb_blob_t *get_blob () const { return table.get_blob (); }
1320*2d1272b8SAndroid Build Coastguard Worker 
1321*2d1272b8SAndroid Build Coastguard Worker     template <typename Chain>
get_accelAAT::mortmorx::accelerator_t1322*2d1272b8SAndroid Build Coastguard Worker     hb_aat_layout_chain_accelerator_t *get_accel (unsigned chain_index, const Chain &chain, unsigned num_glyphs) const
1323*2d1272b8SAndroid Build Coastguard Worker     {
1324*2d1272b8SAndroid Build Coastguard Worker       if (unlikely (chain_index >= chain_count)) return nullptr;
1325*2d1272b8SAndroid Build Coastguard Worker 
1326*2d1272b8SAndroid Build Coastguard Worker     retry:
1327*2d1272b8SAndroid Build Coastguard Worker       auto *accel = accels[chain_index].get_acquire ();
1328*2d1272b8SAndroid Build Coastguard Worker       if (unlikely (!accel))
1329*2d1272b8SAndroid Build Coastguard Worker       {
1330*2d1272b8SAndroid Build Coastguard Worker 	accel = hb_aat_layout_chain_accelerator_t::create (chain, num_glyphs);
1331*2d1272b8SAndroid Build Coastguard Worker 	if (unlikely (!accel))
1332*2d1272b8SAndroid Build Coastguard Worker 	  return nullptr;
1333*2d1272b8SAndroid Build Coastguard Worker 
1334*2d1272b8SAndroid Build Coastguard Worker 	if (unlikely (!accels[chain_index].cmpexch (nullptr, accel)))
1335*2d1272b8SAndroid Build Coastguard Worker 	{
1336*2d1272b8SAndroid Build Coastguard Worker 	  hb_free (accel);
1337*2d1272b8SAndroid Build Coastguard Worker 	  goto retry;
1338*2d1272b8SAndroid Build Coastguard Worker 	}
1339*2d1272b8SAndroid Build Coastguard Worker       }
1340*2d1272b8SAndroid Build Coastguard Worker 
1341*2d1272b8SAndroid Build Coastguard Worker       return accel;
1342*2d1272b8SAndroid Build Coastguard Worker     }
1343*2d1272b8SAndroid Build Coastguard Worker 
1344*2d1272b8SAndroid Build Coastguard Worker     hb_blob_ptr_t<T> table;
1345*2d1272b8SAndroid Build Coastguard Worker     unsigned int chain_count;
1346*2d1272b8SAndroid Build Coastguard Worker     hb_atomic_ptr_t<hb_aat_layout_chain_accelerator_t> *accels;
1347*2d1272b8SAndroid Build Coastguard Worker   };
1348*2d1272b8SAndroid Build Coastguard Worker 
1349*2d1272b8SAndroid Build Coastguard Worker 
compile_flagsAAT::mortmorx1350*2d1272b8SAndroid Build Coastguard Worker   void compile_flags (const hb_aat_map_builder_t *mapper,
1351*2d1272b8SAndroid Build Coastguard Worker 		      hb_aat_map_t *map) const
1352*2d1272b8SAndroid Build Coastguard Worker   {
1353*2d1272b8SAndroid Build Coastguard Worker     const Chain<Types> *chain = &firstChain;
1354*2d1272b8SAndroid Build Coastguard Worker     unsigned int count = chainCount;
1355*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!map->chain_flags.resize (count)))
1356*2d1272b8SAndroid Build Coastguard Worker       return;
1357*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int i = 0; i < count; i++)
1358*2d1272b8SAndroid Build Coastguard Worker     {
1359*2d1272b8SAndroid Build Coastguard Worker       map->chain_flags[i].push (hb_aat_map_t::range_flags_t {chain->compile_flags (mapper),
1360*2d1272b8SAndroid Build Coastguard Worker 							     mapper->range_first,
1361*2d1272b8SAndroid Build Coastguard Worker 							     mapper->range_last});
1362*2d1272b8SAndroid Build Coastguard Worker       chain = &StructAfter<Chain<Types>> (*chain);
1363*2d1272b8SAndroid Build Coastguard Worker     }
1364*2d1272b8SAndroid Build Coastguard Worker   }
1365*2d1272b8SAndroid Build Coastguard Worker 
get_chain_countAAT::mortmorx1366*2d1272b8SAndroid Build Coastguard Worker   unsigned get_chain_count () const
1367*2d1272b8SAndroid Build Coastguard Worker   {
1368*2d1272b8SAndroid Build Coastguard Worker 	  return chainCount;
1369*2d1272b8SAndroid Build Coastguard Worker   }
1370*2d1272b8SAndroid Build Coastguard Worker 
applyAAT::mortmorx1371*2d1272b8SAndroid Build Coastguard Worker   void apply (hb_aat_apply_context_t *c,
1372*2d1272b8SAndroid Build Coastguard Worker 	      const hb_aat_map_t &map,
1373*2d1272b8SAndroid Build Coastguard Worker 	      const accelerator_t &accel) const
1374*2d1272b8SAndroid Build Coastguard Worker   {
1375*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!c->buffer->successful)) return;
1376*2d1272b8SAndroid Build Coastguard Worker 
1377*2d1272b8SAndroid Build Coastguard Worker     c->buffer->unsafe_to_concat ();
1378*2d1272b8SAndroid Build Coastguard Worker 
1379*2d1272b8SAndroid Build Coastguard Worker     if (c->buffer->len < HB_AAT_BUFFER_DIGEST_THRESHOLD)
1380*2d1272b8SAndroid Build Coastguard Worker       c->buffer_digest = c->buffer->digest ();
1381*2d1272b8SAndroid Build Coastguard Worker     else
1382*2d1272b8SAndroid Build Coastguard Worker       c->buffer_digest = hb_set_digest_t::full ();
1383*2d1272b8SAndroid Build Coastguard Worker 
1384*2d1272b8SAndroid Build Coastguard Worker     c->set_lookup_index (0);
1385*2d1272b8SAndroid Build Coastguard Worker     const Chain<Types> *chain = &firstChain;
1386*2d1272b8SAndroid Build Coastguard Worker     unsigned int count = chainCount;
1387*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int i = 0; i < count; i++)
1388*2d1272b8SAndroid Build Coastguard Worker     {
1389*2d1272b8SAndroid Build Coastguard Worker       auto *chain_accel = accel.get_accel (i, *chain, c->face->get_num_glyphs ());
1390*2d1272b8SAndroid Build Coastguard Worker       c->range_flags = &map.chain_flags[i];
1391*2d1272b8SAndroid Build Coastguard Worker       chain->apply (c, chain_accel);
1392*2d1272b8SAndroid Build Coastguard Worker       if (unlikely (!c->buffer->successful)) return;
1393*2d1272b8SAndroid Build Coastguard Worker       chain = &StructAfter<Chain<Types>> (*chain);
1394*2d1272b8SAndroid Build Coastguard Worker     }
1395*2d1272b8SAndroid Build Coastguard Worker   }
1396*2d1272b8SAndroid Build Coastguard Worker 
sanitizeAAT::mortmorx1397*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
1398*2d1272b8SAndroid Build Coastguard Worker   {
1399*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
1400*2d1272b8SAndroid Build Coastguard Worker     if (!(version.sanitize (c) &&
1401*2d1272b8SAndroid Build Coastguard Worker 	  hb_barrier () &&
1402*2d1272b8SAndroid Build Coastguard Worker 	  version &&
1403*2d1272b8SAndroid Build Coastguard Worker 	  chainCount.sanitize (c)))
1404*2d1272b8SAndroid Build Coastguard Worker       return_trace (false);
1405*2d1272b8SAndroid Build Coastguard Worker 
1406*2d1272b8SAndroid Build Coastguard Worker     const Chain<Types> *chain = &firstChain;
1407*2d1272b8SAndroid Build Coastguard Worker     unsigned int count = chainCount;
1408*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int i = 0; i < count; i++)
1409*2d1272b8SAndroid Build Coastguard Worker     {
1410*2d1272b8SAndroid Build Coastguard Worker       if (!chain->sanitize (c, version))
1411*2d1272b8SAndroid Build Coastguard Worker 	return_trace (false);
1412*2d1272b8SAndroid Build Coastguard Worker       hb_barrier ();
1413*2d1272b8SAndroid Build Coastguard Worker       chain = &StructAfter<Chain<Types>> (*chain);
1414*2d1272b8SAndroid Build Coastguard Worker     }
1415*2d1272b8SAndroid Build Coastguard Worker 
1416*2d1272b8SAndroid Build Coastguard Worker     return_trace (true);
1417*2d1272b8SAndroid Build Coastguard Worker   }
1418*2d1272b8SAndroid Build Coastguard Worker 
1419*2d1272b8SAndroid Build Coastguard Worker   protected:
1420*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	version;	/* Version number of the glyph metamorphosis table.
1421*2d1272b8SAndroid Build Coastguard Worker 				 * 1, 2, or 3. */
1422*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	unused;		/* Set to 0. */
1423*2d1272b8SAndroid Build Coastguard Worker   HBUINT32	chainCount;	/* Number of metamorphosis chains contained in this
1424*2d1272b8SAndroid Build Coastguard Worker 				 * table. */
1425*2d1272b8SAndroid Build Coastguard Worker   Chain<Types>	firstChain;	/* Chains. */
1426*2d1272b8SAndroid Build Coastguard Worker 
1427*2d1272b8SAndroid Build Coastguard Worker   public:
1428*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_MIN (8);
1429*2d1272b8SAndroid Build Coastguard Worker };
1430*2d1272b8SAndroid Build Coastguard Worker 
1431*2d1272b8SAndroid Build Coastguard Worker struct morx : mortmorx<morx, ExtendedTypes, HB_AAT_TAG_morx> {};
1432*2d1272b8SAndroid Build Coastguard Worker struct mort : mortmorx<mort, ObsoleteTypes, HB_AAT_TAG_mort> {};
1433*2d1272b8SAndroid Build Coastguard Worker 
1434*2d1272b8SAndroid Build Coastguard Worker struct morx_accelerator_t : morx::accelerator_t {
morx_accelerator_tAAT::morx_accelerator_t1435*2d1272b8SAndroid Build Coastguard Worker   morx_accelerator_t (hb_face_t *face) : morx::accelerator_t (face) {}
1436*2d1272b8SAndroid Build Coastguard Worker };
1437*2d1272b8SAndroid Build Coastguard Worker struct mort_accelerator_t : mort::accelerator_t {
mort_accelerator_tAAT::mort_accelerator_t1438*2d1272b8SAndroid Build Coastguard Worker   mort_accelerator_t (hb_face_t *face) : mort::accelerator_t (face) {}
1439*2d1272b8SAndroid Build Coastguard Worker };
1440*2d1272b8SAndroid Build Coastguard Worker 
1441*2d1272b8SAndroid Build Coastguard Worker 
1442*2d1272b8SAndroid Build Coastguard Worker } /* namespace AAT */
1443*2d1272b8SAndroid Build Coastguard Worker 
1444*2d1272b8SAndroid Build Coastguard Worker 
1445*2d1272b8SAndroid Build Coastguard Worker #endif /* HB_AAT_LAYOUT_MORX_TABLE_HH */
1446