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