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