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