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 (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
78 			const Entry<EntryData> &entry)
79     {
80       return (entry.flags & Verb) && start < end;
81     }
transitionAAT::RearrangementSubtable::driver_context_t82     void transition (StateTableDriver<Types, EntryData> *driver,
83 		     const Entry<EntryData> &entry)
84     {
85       hb_buffer_t *buffer = driver->buffer;
86       unsigned int flags = entry.flags;
87 
88       if (flags & MarkFirst)
89 	start = buffer->idx;
90 
91       if (flags & MarkLast)
92 	end = hb_min (buffer->idx + 1, buffer->len);
93 
94       if ((flags & Verb) && start < end)
95       {
96 	/* The following map has two nibbles, for start-side
97 	 * and end-side. Values of 0,1,2 mean move that many
98 	 * to the other side. Value of 3 means move 2 and
99 	 * flip them. */
100 	const unsigned char map[16] =
101 	{
102 	  0x00,	/* 0	no change */
103 	  0x10,	/* 1	Ax => xA */
104 	  0x01,	/* 2	xD => Dx */
105 	  0x11,	/* 3	AxD => DxA */
106 	  0x20,	/* 4	ABx => xAB */
107 	  0x30,	/* 5	ABx => xBA */
108 	  0x02,	/* 6	xCD => CDx */
109 	  0x03,	/* 7	xCD => DCx */
110 	  0x12,	/* 8	AxCD => CDxA */
111 	  0x13,	/* 9	AxCD => DCxA */
112 	  0x21,	/* 10	ABxD => DxAB */
113 	  0x31,	/* 11	ABxD => DxBA */
114 	  0x22,	/* 12	ABxCD => CDxAB */
115 	  0x32,	/* 13	ABxCD => CDxBA */
116 	  0x23,	/* 14	ABxCD => DCxAB */
117 	  0x33,	/* 15	ABxCD => DCxBA */
118 	};
119 
120 	unsigned int m = map[flags & Verb];
121 	unsigned int l = hb_min (2u, m >> 4);
122 	unsigned int r = hb_min (2u, m & 0x0F);
123 	bool reverse_l = 3 == (m >> 4);
124 	bool reverse_r = 3 == (m & 0x0F);
125 
126 	if (end - start >= l + r)
127 	{
128 	  buffer->merge_clusters (start, hb_min (buffer->idx + 1, buffer->len));
129 	  buffer->merge_clusters (start, end);
130 
131 	  hb_glyph_info_t *info = buffer->info;
132 	  hb_glyph_info_t buf[4];
133 
134 	  memcpy (buf, info + start, l * sizeof (buf[0]));
135 	  memcpy (buf + 2, info + end - r, r * sizeof (buf[0]));
136 
137 	  if (l != r)
138 	    memmove (info + start + r, info + start + l, (end - start - l - r) * sizeof (buf[0]));
139 
140 	  memcpy (info + start, buf + 2, r * sizeof (buf[0]));
141 	  memcpy (info + end - l, buf, l * sizeof (buf[0]));
142 	  if (reverse_l)
143 	  {
144 	    buf[0] = info[end - 1];
145 	    info[end - 1] = info[end - 2];
146 	    info[end - 2] = buf[0];
147 	  }
148 	  if (reverse_r)
149 	  {
150 	    buf[0] = info[start];
151 	    info[start] = info[start + 1];
152 	    info[start + 1] = buf[0];
153 	  }
154 	}
155       }
156     }
157 
158     public:
159     bool ret;
160     private:
161     unsigned int start;
162     unsigned int end;
163   };
164 
applyAAT::RearrangementSubtable165   bool apply (hb_aat_apply_context_t *c) const
166   {
167     TRACE_APPLY (this);
168 
169     driver_context_t dc (this);
170 
171     StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
172     driver.drive (&dc);
173 
174     return_trace (dc.ret);
175   }
176 
sanitizeAAT::RearrangementSubtable177   bool sanitize (hb_sanitize_context_t *c) const
178   {
179     TRACE_SANITIZE (this);
180     return_trace (machine.sanitize (c));
181   }
182 
183   protected:
184   StateTable<Types, EntryData>	machine;
185   public:
186   DEFINE_SIZE_STATIC (16);
187 };
188 
189 template <typename Types>
190 struct ContextualSubtable
191 {
192   typedef typename Types::HBUINT HBUINT;
193 
194   struct EntryData
195   {
196     HBUINT16	markIndex;	/* Index of the substitution table for the
197 				 * marked glyph (use 0xFFFF for none). */
198     HBUINT16	currentIndex;	/* Index of the substitution table for the
199 				 * current glyph (use 0xFFFF for none). */
200     public:
201     DEFINE_SIZE_STATIC (4);
202   };
203 
204   struct driver_context_t
205   {
206     static constexpr bool in_place = true;
207     enum Flags
208     {
209       SetMark		= 0x8000,	/* If set, make the current glyph the marked glyph. */
210       DontAdvance	= 0x4000,	/* If set, don't advance to the next glyph before
211 					 * going to the new state. */
212       Reserved		= 0x3FFF,	/* These bits are reserved and should be set to 0. */
213     };
214 
driver_context_tAAT::ContextualSubtable::driver_context_t215     driver_context_t (const ContextualSubtable *table_,
216 			     hb_aat_apply_context_t *c_) :
217 	ret (false),
218 	c (c_),
219 	gdef (*c->gdef_table),
220 	mark_set (false),
221 	has_glyph_classes (gdef.has_glyph_classes ()),
222 	mark (0),
223 	table (table_),
224 	subs (table+table->substitutionTables) {}
225 
is_actionableAAT::ContextualSubtable::driver_context_t226     bool is_actionable (StateTableDriver<Types, EntryData> *driver,
227 			const Entry<EntryData> &entry)
228     {
229       hb_buffer_t *buffer = driver->buffer;
230 
231       if (buffer->idx == buffer->len && !mark_set)
232 	return false;
233 
234       return entry.data.markIndex != 0xFFFF || entry.data.currentIndex != 0xFFFF;
235     }
transitionAAT::ContextualSubtable::driver_context_t236     void transition (StateTableDriver<Types, EntryData> *driver,
237 		     const Entry<EntryData> &entry)
238     {
239       hb_buffer_t *buffer = driver->buffer;
240 
241       /* Looks like CoreText applies neither mark nor current substitution for
242        * end-of-text if mark was not explicitly set. */
243       if (buffer->idx == buffer->len && !mark_set)
244 	return;
245 
246       const HBGlyphID16 *replacement;
247 
248       replacement = nullptr;
249       if (Types::extended)
250       {
251 	if (entry.data.markIndex != 0xFFFF)
252 	{
253 	  const Lookup<HBGlyphID16> &lookup = subs[entry.data.markIndex];
254 	  replacement = lookup.get_value (buffer->info[mark].codepoint, driver->num_glyphs);
255 	}
256       }
257       else
258       {
259 	unsigned int offset = entry.data.markIndex + buffer->info[mark].codepoint;
260 	const UnsizedArrayOf<HBGlyphID16> &subs_old = (const UnsizedArrayOf<HBGlyphID16> &) subs;
261 	replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
262 	if (!replacement->sanitize (&c->sanitizer) || !*replacement)
263 	  replacement = nullptr;
264       }
265       if (replacement)
266       {
267 	buffer->unsafe_to_break (mark, hb_min (buffer->idx + 1, buffer->len));
268 	buffer->info[mark].codepoint = *replacement;
269 	if (has_glyph_classes)
270 	  _hb_glyph_info_set_glyph_props (&buffer->info[mark],
271 					  gdef.get_glyph_props (*replacement));
272 	ret = true;
273       }
274 
275       replacement = nullptr;
276       unsigned int idx = hb_min (buffer->idx, buffer->len - 1);
277       if (Types::extended)
278       {
279 	if (entry.data.currentIndex != 0xFFFF)
280 	{
281 	  const Lookup<HBGlyphID16> &lookup = subs[entry.data.currentIndex];
282 	  replacement = lookup.get_value (buffer->info[idx].codepoint, driver->num_glyphs);
283 	}
284       }
285       else
286       {
287 	unsigned int offset = entry.data.currentIndex + buffer->info[idx].codepoint;
288 	const UnsizedArrayOf<HBGlyphID16> &subs_old = (const UnsizedArrayOf<HBGlyphID16> &) subs;
289 	replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
290 	if (!replacement->sanitize (&c->sanitizer) || !*replacement)
291 	  replacement = nullptr;
292       }
293       if (replacement)
294       {
295 	buffer->info[idx].codepoint = *replacement;
296 	if (has_glyph_classes)
297 	  _hb_glyph_info_set_glyph_props (&buffer->info[idx],
298 					  gdef.get_glyph_props (*replacement));
299 	ret = true;
300       }
301 
302       if (entry.flags & SetMark)
303       {
304 	mark_set = true;
305 	mark = buffer->idx;
306       }
307     }
308 
309     public:
310     bool ret;
311     private:
312     hb_aat_apply_context_t *c;
313     const OT::GDEF &gdef;
314     bool mark_set;
315     bool has_glyph_classes;
316     unsigned int mark;
317     const ContextualSubtable *table;
318     const UnsizedListOfOffset16To<Lookup<HBGlyphID16>, HBUINT, false> &subs;
319   };
320 
applyAAT::ContextualSubtable321   bool apply (hb_aat_apply_context_t *c) const
322   {
323     TRACE_APPLY (this);
324 
325     driver_context_t dc (this, c);
326 
327     StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
328     driver.drive (&dc);
329 
330     return_trace (dc.ret);
331   }
332 
sanitizeAAT::ContextualSubtable333   bool sanitize (hb_sanitize_context_t *c) const
334   {
335     TRACE_SANITIZE (this);
336 
337     unsigned int num_entries = 0;
338     if (unlikely (!machine.sanitize (c, &num_entries))) return_trace (false);
339 
340     if (!Types::extended)
341       return_trace (substitutionTables.sanitize (c, this, 0));
342 
343     unsigned int num_lookups = 0;
344 
345     const Entry<EntryData> *entries = machine.get_entries ();
346     for (unsigned int i = 0; i < num_entries; i++)
347     {
348       const EntryData &data = entries[i].data;
349 
350       if (data.markIndex != 0xFFFF)
351 	num_lookups = hb_max (num_lookups, 1u + data.markIndex);
352       if (data.currentIndex != 0xFFFF)
353 	num_lookups = hb_max (num_lookups, 1u + data.currentIndex);
354     }
355 
356     return_trace (substitutionTables.sanitize (c, this, num_lookups));
357   }
358 
359   protected:
360   StateTable<Types, EntryData>
361 		machine;
362   NNOffsetTo<UnsizedListOfOffset16To<Lookup<HBGlyphID16>, HBUINT, false>, HBUINT>
363 		substitutionTables;
364   public:
365   DEFINE_SIZE_STATIC (20);
366 };
367 
368 
369 template <bool extended>
370 struct LigatureEntry;
371 
372 template <>
373 struct LigatureEntry<true>
374 {
375   enum Flags
376   {
377     SetComponent	= 0x8000,	/* Push this glyph onto the component stack for
378 					 * eventual processing. */
379     DontAdvance		= 0x4000,	/* Leave the glyph pointer at this glyph for the
380 					   next iteration. */
381     PerformAction	= 0x2000,	/* Use the ligActionIndex to process a ligature
382 					 * group. */
383     Reserved		= 0x1FFF,	/* These bits are reserved and should be set to 0. */
384   };
385 
386   struct EntryData
387   {
388     HBUINT16	ligActionIndex;	/* Index to the first ligActionTable entry
389 				 * for processing this group, if indicated
390 				 * by the flags. */
391     public:
392     DEFINE_SIZE_STATIC (2);
393   };
394 
performActionAAT::LigatureEntry395   static bool performAction (const Entry<EntryData> &entry)
396   { return entry.flags & PerformAction; }
397 
ligActionIndexAAT::LigatureEntry398   static unsigned int ligActionIndex (const Entry<EntryData> &entry)
399   { return entry.data.ligActionIndex; }
400 };
401 template <>
402 struct LigatureEntry<false>
403 {
404   enum Flags
405   {
406     SetComponent	= 0x8000,	/* Push this glyph onto the component stack for
407 					 * eventual processing. */
408     DontAdvance		= 0x4000,	/* Leave the glyph pointer at this glyph for the
409 					   next iteration. */
410     Offset		= 0x3FFF,	/* Byte offset from beginning of subtable to the
411 					 * ligature action list. This value must be a
412 					 * multiple of 4. */
413   };
414 
415   typedef void EntryData;
416 
performActionAAT::LigatureEntry417   static bool performAction (const Entry<EntryData> &entry)
418   { return entry.flags & Offset; }
419 
ligActionIndexAAT::LigatureEntry420   static unsigned int ligActionIndex (const Entry<EntryData> &entry)
421   { return entry.flags & Offset; }
422 };
423 
424 
425 template <typename Types>
426 struct LigatureSubtable
427 {
428   typedef typename Types::HBUINT HBUINT;
429 
430   typedef LigatureEntry<Types::extended> LigatureEntryT;
431   typedef typename LigatureEntryT::EntryData EntryData;
432 
433   struct driver_context_t
434   {
435     static constexpr bool in_place = false;
436     enum
437     {
438       DontAdvance	= LigatureEntryT::DontAdvance,
439     };
440     enum LigActionFlags
441     {
442       LigActionLast	= 0x80000000,	/* This is the last action in the list. This also
443 					 * implies storage. */
444       LigActionStore	= 0x40000000,	/* Store the ligature at the current cumulated index
445 					 * in the ligature table in place of the marked
446 					 * (i.e. currently-popped) glyph. */
447       LigActionOffset	= 0x3FFFFFFF,	/* A 30-bit value which is sign-extended to 32-bits
448 					 * and added to the glyph ID, resulting in an index
449 					 * into the component table. */
450     };
451 
driver_context_tAAT::LigatureSubtable::driver_context_t452     driver_context_t (const LigatureSubtable *table_,
453 		      hb_aat_apply_context_t *c_) :
454 	ret (false),
455 	c (c_),
456 	table (table_),
457 	ligAction (table+table->ligAction),
458 	component (table+table->component),
459 	ligature (table+table->ligature),
460 	match_length (0) {}
461 
is_actionableAAT::LigatureSubtable::driver_context_t462     bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
463 			const Entry<EntryData> &entry)
464     {
465       return LigatureEntryT::performAction (entry);
466     }
transitionAAT::LigatureSubtable::driver_context_t467     void transition (StateTableDriver<Types, EntryData> *driver,
468 		     const Entry<EntryData> &entry)
469     {
470       hb_buffer_t *buffer = driver->buffer;
471 
472       DEBUG_MSG (APPLY, nullptr, "Ligature transition at %u", buffer->idx);
473       if (entry.flags & LigatureEntryT::SetComponent)
474       {
475 	/* Never mark same index twice, in case DontAdvance was used... */
476 	if (match_length && match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] == buffer->out_len)
477 	  match_length--;
478 
479 	match_positions[match_length++ % ARRAY_LENGTH (match_positions)] = buffer->out_len;
480 	DEBUG_MSG (APPLY, nullptr, "Set component at %u", buffer->out_len);
481       }
482 
483       if (LigatureEntryT::performAction (entry))
484       {
485 	DEBUG_MSG (APPLY, nullptr, "Perform action with %u", match_length);
486 	unsigned int end = buffer->out_len;
487 
488 	if (unlikely (!match_length))
489 	  return;
490 
491 	if (buffer->idx >= buffer->len)
492 	  return; /* TODO Work on previous instead? */
493 
494 	unsigned int cursor = match_length;
495 
496 	unsigned int action_idx = LigatureEntryT::ligActionIndex (entry);
497 	action_idx = Types::offsetToIndex (action_idx, table, ligAction.arrayZ);
498 	const HBUINT32 *actionData = &ligAction[action_idx];
499 
500 	unsigned int ligature_idx = 0;
501 	unsigned int action;
502 	do
503 	{
504 	  if (unlikely (!cursor))
505 	  {
506 	    /* Stack underflow.  Clear the stack. */
507 	    DEBUG_MSG (APPLY, nullptr, "Stack underflow");
508 	    match_length = 0;
509 	    break;
510 	  }
511 
512 	  DEBUG_MSG (APPLY, nullptr, "Moving to stack position %u", cursor - 1);
513 	  if (unlikely (!buffer->move_to (match_positions[--cursor % ARRAY_LENGTH (match_positions)]))) return;
514 
515 	  if (unlikely (!actionData->sanitize (&c->sanitizer))) break;
516 	  action = *actionData;
517 
518 	  uint32_t uoffset = action & LigActionOffset;
519 	  if (uoffset & 0x20000000)
520 	    uoffset |= 0xC0000000; /* Sign-extend. */
521 	  int32_t offset = (int32_t) uoffset;
522 	  unsigned int component_idx = buffer->cur().codepoint + offset;
523 	  component_idx = Types::wordOffsetToIndex (component_idx, table, component.arrayZ);
524 	  const HBUINT16 &componentData = component[component_idx];
525 	  if (unlikely (!componentData.sanitize (&c->sanitizer))) break;
526 	  ligature_idx += componentData;
527 
528 	  DEBUG_MSG (APPLY, nullptr, "Action store %u last %u",
529 		     bool (action & LigActionStore),
530 		     bool (action & LigActionLast));
531 	  if (action & (LigActionStore | LigActionLast))
532 	  {
533 	    ligature_idx = Types::offsetToIndex (ligature_idx, table, ligature.arrayZ);
534 	    const HBGlyphID16 &ligatureData = ligature[ligature_idx];
535 	    if (unlikely (!ligatureData.sanitize (&c->sanitizer))) break;
536 	    hb_codepoint_t lig = ligatureData;
537 
538 	    DEBUG_MSG (APPLY, nullptr, "Produced ligature %u", lig);
539 	    if (unlikely (!buffer->replace_glyph (lig))) return;
540 
541 	    unsigned int lig_end = match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] + 1u;
542 	    /* Now go and delete all subsequent components. */
543 	    while (match_length - 1u > cursor)
544 	    {
545 	      DEBUG_MSG (APPLY, nullptr, "Skipping ligature component");
546 	      if (unlikely (!buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]))) return;
547 	      if (unlikely (!buffer->replace_glyph (DELETED_GLYPH))) return;
548 	    }
549 
550 	    if (unlikely (!buffer->move_to (lig_end))) return;
551 	    buffer->merge_out_clusters (match_positions[cursor % ARRAY_LENGTH (match_positions)], buffer->out_len);
552 	  }
553 
554 	  actionData++;
555 	}
556 	while (!(action & LigActionLast));
557 	if (unlikely (!buffer->move_to (end))) return;
558       }
559     }
560 
561     public:
562     bool ret;
563     private:
564     hb_aat_apply_context_t *c;
565     const LigatureSubtable *table;
566     const UnsizedArrayOf<HBUINT32> &ligAction;
567     const UnsizedArrayOf<HBUINT16> &component;
568     const UnsizedArrayOf<HBGlyphID16> &ligature;
569     unsigned int match_length;
570     unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
571   };
572 
applyAAT::LigatureSubtable573   bool apply (hb_aat_apply_context_t *c) const
574   {
575     TRACE_APPLY (this);
576 
577     driver_context_t dc (this, c);
578 
579     StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
580     driver.drive (&dc);
581 
582     return_trace (dc.ret);
583   }
584 
sanitizeAAT::LigatureSubtable585   bool sanitize (hb_sanitize_context_t *c) const
586   {
587     TRACE_SANITIZE (this);
588     /* The rest of array sanitizations are done at run-time. */
589     return_trace (c->check_struct (this) && machine.sanitize (c) &&
590 		  ligAction && component && ligature);
591   }
592 
593   protected:
594   StateTable<Types, EntryData>
595 		machine;
596   NNOffsetTo<UnsizedArrayOf<HBUINT32>, HBUINT>
597 		ligAction;	/* Offset to the ligature action table. */
598   NNOffsetTo<UnsizedArrayOf<HBUINT16>, HBUINT>
599 		component;	/* Offset to the component table. */
600   NNOffsetTo<UnsizedArrayOf<HBGlyphID16>, HBUINT>
601 		ligature;	/* Offset to the actual ligature lists. */
602   public:
603   DEFINE_SIZE_STATIC (28);
604 };
605 
606 template <typename Types>
607 struct NoncontextualSubtable
608 {
applyAAT::NoncontextualSubtable609   bool apply (hb_aat_apply_context_t *c) const
610   {
611     TRACE_APPLY (this);
612 
613     const OT::GDEF &gdef (*c->gdef_table);
614     bool has_glyph_classes = gdef.has_glyph_classes ();
615 
616     bool ret = false;
617     unsigned int num_glyphs = c->face->get_num_glyphs ();
618 
619     hb_glyph_info_t *info = c->buffer->info;
620     unsigned int count = c->buffer->len;
621     for (unsigned int i = 0; i < count; i++)
622     {
623       const HBGlyphID16 *replacement = substitute.get_value (info[i].codepoint, num_glyphs);
624       if (replacement)
625       {
626 	info[i].codepoint = *replacement;
627 	if (has_glyph_classes)
628 	  _hb_glyph_info_set_glyph_props (&info[i],
629 					  gdef.get_glyph_props (*replacement));
630 	ret = true;
631       }
632     }
633 
634     return_trace (ret);
635   }
636 
sanitizeAAT::NoncontextualSubtable637   bool sanitize (hb_sanitize_context_t *c) const
638   {
639     TRACE_SANITIZE (this);
640     return_trace (substitute.sanitize (c));
641   }
642 
643   protected:
644   Lookup<HBGlyphID16>	substitute;
645   public:
646   DEFINE_SIZE_MIN (2);
647 };
648 
649 template <typename Types>
650 struct InsertionSubtable
651 {
652   typedef typename Types::HBUINT HBUINT;
653 
654   struct EntryData
655   {
656     HBUINT16	currentInsertIndex;	/* Zero-based index into the insertion glyph table.
657 					 * The number of glyphs to be inserted is contained
658 					 * in the currentInsertCount field in the flags.
659 					 * A value of 0xFFFF indicates no insertion is to
660 					 * be done. */
661     HBUINT16	markedInsertIndex;	/* Zero-based index into the insertion glyph table.
662 					 * The number of glyphs to be inserted is contained
663 					 * in the markedInsertCount field in the flags.
664 					 * A value of 0xFFFF indicates no insertion is to
665 					 * be done. */
666     public:
667     DEFINE_SIZE_STATIC (4);
668   };
669 
670   struct driver_context_t
671   {
672     static constexpr bool in_place = false;
673     enum Flags
674     {
675       SetMark		= 0x8000,	/* If set, mark the current glyph. */
676       DontAdvance	= 0x4000,	/* If set, don't advance to the next glyph before
677 					 * going to the new state.  This does not mean
678 					 * that the glyph pointed to is the same one as
679 					 * before. If you've made insertions immediately
680 					 * downstream of the current glyph, the next glyph
681 					 * processed would in fact be the first one
682 					 * inserted. */
683       CurrentIsKashidaLike= 0x2000,	/* If set, and the currentInsertList is nonzero,
684 					 * then the specified glyph list will be inserted
685 					 * as a kashida-like insertion, either before or
686 					 * after the current glyph (depending on the state
687 					 * of the currentInsertBefore flag). If clear, and
688 					 * the currentInsertList is nonzero, then the
689 					 * specified glyph list will be inserted as a
690 					 * split-vowel-like insertion, either before or
691 					 * after the current glyph (depending on the state
692 					 * of the currentInsertBefore flag). */
693       MarkedIsKashidaLike= 0x1000,	/* If set, and the markedInsertList is nonzero,
694 					 * then the specified glyph list will be inserted
695 					 * as a kashida-like insertion, either before or
696 					 * after the marked glyph (depending on the state
697 					 * of the markedInsertBefore flag). If clear, and
698 					 * the markedInsertList is nonzero, then the
699 					 * specified glyph list will be inserted as a
700 					 * split-vowel-like insertion, either before or
701 					 * after the marked glyph (depending on the state
702 					 * of the markedInsertBefore flag). */
703       CurrentInsertBefore= 0x0800,	/* If set, specifies that insertions are to be made
704 					 * to the left of the current glyph. If clear,
705 					 * they're made to the right of the current glyph. */
706       MarkedInsertBefore= 0x0400,	/* If set, specifies that insertions are to be
707 					 * made to the left of the marked glyph. If clear,
708 					 * they're made to the right of the marked glyph. */
709       CurrentInsertCount= 0x3E0,	/* This 5-bit field is treated as a count of the
710 					 * number of glyphs to insert at the current
711 					 * position. Since zero means no insertions, the
712 					 * largest number of insertions at any given
713 					 * current location is 31 glyphs. */
714       MarkedInsertCount= 0x001F,	/* This 5-bit field is treated as a count of the
715 					 * number of glyphs to insert at the marked
716 					 * position. Since zero means no insertions, the
717 					 * largest number of insertions at any given
718 					 * marked location is 31 glyphs. */
719     };
720 
driver_context_tAAT::InsertionSubtable::driver_context_t721     driver_context_t (const InsertionSubtable *table,
722 		      hb_aat_apply_context_t *c_) :
723 	ret (false),
724 	c (c_),
725 	mark (0),
726 	insertionAction (table+table->insertionAction) {}
727 
is_actionableAAT::InsertionSubtable::driver_context_t728     bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
729 			const Entry<EntryData> &entry)
730     {
731       return (entry.flags & (CurrentInsertCount | MarkedInsertCount)) &&
732 	     (entry.data.currentInsertIndex != 0xFFFF ||entry.data.markedInsertIndex != 0xFFFF);
733     }
transitionAAT::InsertionSubtable::driver_context_t734     void transition (StateTableDriver<Types, EntryData> *driver,
735 		     const Entry<EntryData> &entry)
736     {
737       hb_buffer_t *buffer = driver->buffer;
738       unsigned int flags = entry.flags;
739 
740       unsigned mark_loc = buffer->out_len;
741 
742       if (entry.data.markedInsertIndex != 0xFFFF)
743       {
744 	unsigned int count = (flags & MarkedInsertCount);
745 	if (unlikely ((buffer->max_ops -= count) <= 0)) return;
746 	unsigned int start = entry.data.markedInsertIndex;
747 	const HBGlyphID16 *glyphs = &insertionAction[start];
748 	if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
749 
750 	bool before = flags & MarkedInsertBefore;
751 
752 	unsigned int end = buffer->out_len;
753 	if (unlikely (!buffer->move_to (mark))) return;
754 
755 	if (buffer->idx < buffer->len && !before)
756 	  if (unlikely (!buffer->copy_glyph ())) return;
757 	/* TODO We ignore KashidaLike setting. */
758 	if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return;
759 	if (buffer->idx < buffer->len && !before)
760 	  buffer->skip_glyph ();
761 
762 	if (unlikely (!buffer->move_to (end + count))) return;
763 
764 	buffer->unsafe_to_break_from_outbuffer (mark, hb_min (buffer->idx + 1, buffer->len));
765       }
766 
767       if (flags & SetMark)
768 	mark = mark_loc;
769 
770       if (entry.data.currentInsertIndex != 0xFFFF)
771       {
772 	unsigned int count = (flags & CurrentInsertCount) >> 5;
773 	if (unlikely ((buffer->max_ops -= count) <= 0)) return;
774 	unsigned int start = entry.data.currentInsertIndex;
775 	const HBGlyphID16 *glyphs = &insertionAction[start];
776 	if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
777 
778 	bool before = flags & CurrentInsertBefore;
779 
780 	unsigned int end = buffer->out_len;
781 
782 	if (buffer->idx < buffer->len && !before)
783 	  if (unlikely (!buffer->copy_glyph ())) return;
784 	/* TODO We ignore KashidaLike setting. */
785 	if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return;
786 	if (buffer->idx < buffer->len && !before)
787 	  buffer->skip_glyph ();
788 
789 	/* Humm. Not sure where to move to.  There's this wording under
790 	 * DontAdvance flag:
791 	 *
792 	 * "If set, don't update the glyph index before going to the new state.
793 	 * This does not mean that the glyph pointed to is the same one as
794 	 * before. If you've made insertions immediately downstream of the
795 	 * current glyph, the next glyph processed would in fact be the first
796 	 * one inserted."
797 	 *
798 	 * This suggests that if DontAdvance is NOT set, we should move to
799 	 * end+count.  If it *was*, then move to end, such that newly inserted
800 	 * glyphs are now visible.
801 	 *
802 	 * https://github.com/harfbuzz/harfbuzz/issues/1224#issuecomment-427691417
803 	 */
804 	if (unlikely (!buffer->move_to ((flags & DontAdvance) ? end : end + count))) return;
805       }
806     }
807 
808     public:
809     bool ret;
810     private:
811     hb_aat_apply_context_t *c;
812     unsigned int mark;
813     const UnsizedArrayOf<HBGlyphID16> &insertionAction;
814   };
815 
applyAAT::InsertionSubtable816   bool apply (hb_aat_apply_context_t *c) const
817   {
818     TRACE_APPLY (this);
819 
820     driver_context_t dc (this, c);
821 
822     StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
823     driver.drive (&dc);
824 
825     return_trace (dc.ret);
826   }
827 
sanitizeAAT::InsertionSubtable828   bool sanitize (hb_sanitize_context_t *c) const
829   {
830     TRACE_SANITIZE (this);
831     /* The rest of array sanitizations are done at run-time. */
832     return_trace (c->check_struct (this) && machine.sanitize (c) &&
833 		  insertionAction);
834   }
835 
836   protected:
837   StateTable<Types, EntryData>
838 		machine;
839   NNOffsetTo<UnsizedArrayOf<HBGlyphID16>, HBUINT>
840 		insertionAction;	/* Byte offset from stateHeader to the start of
841 					 * the insertion glyph table. */
842   public:
843   DEFINE_SIZE_STATIC (20);
844 };
845 
846 
847 struct Feature
848 {
sanitizeAAT::Feature849   bool sanitize (hb_sanitize_context_t *c) const
850   {
851     TRACE_SANITIZE (this);
852     return_trace (c->check_struct (this));
853   }
854 
855   public:
856   HBUINT16	featureType;	/* The type of feature. */
857   HBUINT16	featureSetting;	/* The feature's setting (aka selector). */
858   HBUINT32	enableFlags;	/* Flags for the settings that this feature
859 				 * and setting enables. */
860   HBUINT32	disableFlags;	/* Complement of flags for the settings that this
861 				 * feature and setting disable. */
862 
863   public:
864   DEFINE_SIZE_STATIC (12);
865 };
866 
867 template <typename Types>
868 struct ChainSubtable
869 {
870   typedef typename Types::HBUINT HBUINT;
871 
872   template <typename T>
873   friend struct Chain;
874 
get_sizeAAT::ChainSubtable875   unsigned int get_size () const     { return length; }
get_typeAAT::ChainSubtable876   unsigned int get_type () const     { return coverage & 0xFF; }
get_coverageAAT::ChainSubtable877   unsigned int get_coverage () const { return coverage >> (sizeof (HBUINT) * 8 - 8); }
878 
879   enum Coverage
880   {
881     Vertical		= 0x80,	/* If set, this subtable will only be applied
882 				 * to vertical text. If clear, this subtable
883 				 * will only be applied to horizontal text. */
884     Backwards		= 0x40,	/* If set, this subtable will process glyphs
885 				 * in descending order. If clear, it will
886 				 * process the glyphs in ascending order. */
887     AllDirections	= 0x20,	/* If set, this subtable will be applied to
888 				 * both horizontal and vertical text (i.e.
889 				 * the state of bit 0x80000000 is ignored). */
890     Logical		= 0x10,	/* If set, this subtable will process glyphs
891 				 * in logical order (or reverse logical order,
892 				 * depending on the value of bit 0x80000000). */
893   };
894   enum Type
895   {
896     Rearrangement	= 0,
897     Contextual		= 1,
898     Ligature		= 2,
899     Noncontextual	= 4,
900     Insertion		= 5
901   };
902 
903   template <typename context_t, typename ...Ts>
dispatchAAT::ChainSubtable904   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
905   {
906     unsigned int subtable_type = get_type ();
907     TRACE_DISPATCH (this, subtable_type);
908     switch (subtable_type) {
909     case Rearrangement:		return_trace (c->dispatch (u.rearrangement, std::forward<Ts> (ds)...));
910     case Contextual:		return_trace (c->dispatch (u.contextual, std::forward<Ts> (ds)...));
911     case Ligature:		return_trace (c->dispatch (u.ligature, std::forward<Ts> (ds)...));
912     case Noncontextual:		return_trace (c->dispatch (u.noncontextual, std::forward<Ts> (ds)...));
913     case Insertion:		return_trace (c->dispatch (u.insertion, std::forward<Ts> (ds)...));
914     default:			return_trace (c->default_return_value ());
915     }
916   }
917 
applyAAT::ChainSubtable918   bool apply (hb_aat_apply_context_t *c) const
919   {
920     TRACE_APPLY (this);
921     hb_sanitize_with_object_t with (&c->sanitizer, this);
922     return_trace (dispatch (c));
923   }
924 
sanitizeAAT::ChainSubtable925   bool sanitize (hb_sanitize_context_t *c) const
926   {
927     TRACE_SANITIZE (this);
928     if (!length.sanitize (c) ||
929 	length <= min_size ||
930 	!c->check_range (this, length))
931       return_trace (false);
932 
933     hb_sanitize_with_object_t with (c, this);
934     return_trace (dispatch (c));
935   }
936 
937   protected:
938   HBUINT	length;		/* Total subtable length, including this header. */
939   HBUINT	coverage;	/* Coverage flags and subtable type. */
940   HBUINT32	subFeatureFlags;/* The 32-bit mask identifying which subtable this is. */
941   union {
942   RearrangementSubtable<Types>	rearrangement;
943   ContextualSubtable<Types>	contextual;
944   LigatureSubtable<Types>	ligature;
945   NoncontextualSubtable<Types>	noncontextual;
946   InsertionSubtable<Types>	insertion;
947   } u;
948   public:
949   DEFINE_SIZE_MIN (2 * sizeof (HBUINT) + 4);
950 };
951 
952 template <typename Types>
953 struct Chain
954 {
955   typedef typename Types::HBUINT HBUINT;
956 
compile_flagsAAT::Chain957   hb_mask_t compile_flags (const hb_aat_map_builder_t *map) const
958   {
959     hb_mask_t flags = defaultFlags;
960     {
961       unsigned int count = featureCount;
962       for (unsigned i = 0; i < count; i++)
963       {
964 	const Feature &feature = featureZ[i];
965 	hb_aat_layout_feature_type_t type = (hb_aat_layout_feature_type_t) (unsigned int) feature.featureType;
966 	hb_aat_layout_feature_selector_t setting = (hb_aat_layout_feature_selector_t) (unsigned int) feature.featureSetting;
967       retry:
968 	// Check whether this type/setting pair was requested in the map, and if so, apply its flags.
969 	// (The search here only looks at the type and setting fields of feature_info_t.)
970 	hb_aat_map_builder_t::feature_info_t info = { type, setting, false, 0 };
971 	if (map->features.bsearch (info))
972 	{
973 	  flags &= feature.disableFlags;
974 	  flags |= feature.enableFlags;
975 	}
976 	else if (type == HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE && setting == HB_AAT_LAYOUT_FEATURE_SELECTOR_SMALL_CAPS)
977 	{
978 	  /* Deprecated. https://github.com/harfbuzz/harfbuzz/issues/1342 */
979 	  type = HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE;
980 	  setting = HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS;
981 	  goto retry;
982 	}
983       }
984     }
985     return flags;
986   }
987 
applyAAT::Chain988   void apply (hb_aat_apply_context_t *c,
989 	      hb_mask_t flags) const
990   {
991     const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
992     unsigned int count = subtableCount;
993     for (unsigned int i = 0; i < count; i++)
994     {
995       bool reverse;
996 
997       if (!(subtable->subFeatureFlags & flags))
998 	goto skip;
999 
1000       if (!(subtable->get_coverage() & ChainSubtable<Types>::AllDirections) &&
1001 	  HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) !=
1002 	  bool (subtable->get_coverage() & ChainSubtable<Types>::Vertical))
1003 	goto skip;
1004 
1005       /* Buffer contents is always in logical direction.  Determine if
1006        * we need to reverse before applying this subtable.  We reverse
1007        * back after if we did reverse indeed.
1008        *
1009        * Quoting the spac:
1010        * """
1011        * Bits 28 and 30 of the coverage field control the order in which
1012        * glyphs are processed when the subtable is run by the layout engine.
1013        * Bit 28 is used to indicate if the glyph processing direction is
1014        * the same as logical order or layout order. Bit 30 is used to
1015        * indicate whether glyphs are processed forwards or backwards within
1016        * that order.
1017 
1018 		Bit 30	Bit 28	Interpretation for Horizontal Text
1019 		0	0	The subtable is processed in layout order
1020 				(the same order as the glyphs, which is
1021 				always left-to-right).
1022 		1	0	The subtable is processed in reverse layout order
1023 				(the order opposite that of the glyphs, which is
1024 				always right-to-left).
1025 		0	1	The subtable is processed in logical order
1026 				(the same order as the characters, which may be
1027 				left-to-right or right-to-left).
1028 		1	1	The subtable is processed in reverse logical order
1029 				(the order opposite that of the characters, which
1030 				may be right-to-left or left-to-right).
1031        */
1032       reverse = subtable->get_coverage () & ChainSubtable<Types>::Logical ?
1033 		bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) :
1034 		bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) !=
1035 		HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
1036 
1037       if (!c->buffer->message (c->font, "start chainsubtable %d", c->lookup_index))
1038 	goto skip;
1039 
1040       if (reverse)
1041 	_hb_ot_layout_reverse_graphemes (c->buffer);
1042 
1043       subtable->apply (c);
1044 
1045       if (reverse)
1046 	_hb_ot_layout_reverse_graphemes (c->buffer);
1047 
1048       (void) c->buffer->message (c->font, "end chainsubtable %d", c->lookup_index);
1049 
1050       if (unlikely (!c->buffer->successful)) return;
1051 
1052     skip:
1053       subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
1054       c->set_lookup_index (c->lookup_index + 1);
1055     }
1056   }
1057 
get_sizeAAT::Chain1058   unsigned int get_size () const { return length; }
1059 
sanitizeAAT::Chain1060   bool sanitize (hb_sanitize_context_t *c, unsigned int version HB_UNUSED) const
1061   {
1062     TRACE_SANITIZE (this);
1063     if (!length.sanitize (c) ||
1064 	length < min_size ||
1065 	!c->check_range (this, length))
1066       return_trace (false);
1067 
1068     if (!c->check_array (featureZ.arrayZ, featureCount))
1069       return_trace (false);
1070 
1071     const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
1072     unsigned int count = subtableCount;
1073     for (unsigned int i = 0; i < count; i++)
1074     {
1075       if (!subtable->sanitize (c))
1076 	return_trace (false);
1077       subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
1078     }
1079 
1080     return_trace (true);
1081   }
1082 
1083   protected:
1084   HBUINT32	defaultFlags;	/* The default specification for subtables. */
1085   HBUINT32	length;		/* Total byte count, including this header. */
1086   HBUINT	featureCount;	/* Number of feature subtable entries. */
1087   HBUINT	subtableCount;	/* The number of subtables in the chain. */
1088 
1089   UnsizedArrayOf<Feature>	featureZ;	/* Features. */
1090 /*ChainSubtable	firstSubtable;*//* Subtables. */
1091 /*subtableGlyphCoverageArray*/	/* Only if version >= 3. We don't use. */
1092 
1093   public:
1094   DEFINE_SIZE_MIN (8 + 2 * sizeof (HBUINT));
1095 };
1096 
1097 
1098 /*
1099  * The 'mort'/'morx' Table
1100  */
1101 
1102 template <typename Types, hb_tag_t TAG>
1103 struct mortmorx
1104 {
1105   static constexpr hb_tag_t tableTag = TAG;
1106 
has_dataAAT::mortmorx1107   bool has_data () const { return version != 0; }
1108 
compile_flagsAAT::mortmorx1109   void compile_flags (const hb_aat_map_builder_t *mapper,
1110 		      hb_aat_map_t *map) const
1111   {
1112     const Chain<Types> *chain = &firstChain;
1113     unsigned int count = chainCount;
1114     for (unsigned int i = 0; i < count; i++)
1115     {
1116       map->chain_flags.push (chain->compile_flags (mapper));
1117       chain = &StructAfter<Chain<Types>> (*chain);
1118     }
1119   }
1120 
applyAAT::mortmorx1121   void apply (hb_aat_apply_context_t *c) const
1122   {
1123     if (unlikely (!c->buffer->successful)) return;
1124     c->set_lookup_index (0);
1125     const Chain<Types> *chain = &firstChain;
1126     unsigned int count = chainCount;
1127     for (unsigned int i = 0; i < count; i++)
1128     {
1129       chain->apply (c, c->plan->aat_map.chain_flags[i]);
1130       if (unlikely (!c->buffer->successful)) return;
1131       chain = &StructAfter<Chain<Types>> (*chain);
1132     }
1133   }
1134 
sanitizeAAT::mortmorx1135   bool sanitize (hb_sanitize_context_t *c) const
1136   {
1137     TRACE_SANITIZE (this);
1138     if (!version.sanitize (c) || !version || !chainCount.sanitize (c))
1139       return_trace (false);
1140 
1141     const Chain<Types> *chain = &firstChain;
1142     unsigned int count = chainCount;
1143     for (unsigned int i = 0; i < count; i++)
1144     {
1145       if (!chain->sanitize (c, version))
1146 	return_trace (false);
1147       chain = &StructAfter<Chain<Types>> (*chain);
1148     }
1149 
1150     return_trace (true);
1151   }
1152 
1153   protected:
1154   HBUINT16	version;	/* Version number of the glyph metamorphosis table.
1155 				 * 1, 2, or 3. */
1156   HBUINT16	unused;		/* Set to 0. */
1157   HBUINT32	chainCount;	/* Number of metamorphosis chains contained in this
1158 				 * table. */
1159   Chain<Types>	firstChain;	/* Chains. */
1160 
1161   public:
1162   DEFINE_SIZE_MIN (8);
1163 };
1164 
1165 struct morx : mortmorx<ExtendedTypes, HB_AAT_TAG_morx> {};
1166 struct mort : mortmorx<ObsoleteTypes, HB_AAT_TAG_mort> {};
1167 
1168 
1169 } /* namespace AAT */
1170 
1171 
1172 #endif /* HB_AAT_LAYOUT_MORX_TABLE_HH */
1173