QtBase  v6.3.1
hb-aat-layout-morx-table.hh
Go to the documentation of this file.
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"
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>
51 {
52  typedef typename Types::HBUINT HBUINT;
53 
54  typedef void EntryData;
55 
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 
74  ret (false),
75  start (0), end (0) {}
76 
78  const Entry<EntryData> &entry)
79  {
80  return (entry.flags & Verb) && start < end;
81  }
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 
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 
178  {
179  TRACE_SANITIZE (this);
180  return_trace (machine.sanitize (c));
181  }
182 
183  protected:
185  public:
187 };
188 
189 template <typename Types>
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:
202  };
203 
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 
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 
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  }
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:
313  const OT::GDEF &gdef;
314  bool mark_set;
315  bool has_glyph_classes;
316  unsigned int mark;
317  const ContextualSubtable *table;
319  };
320 
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 
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:
364  public:
366 };
367 
368 
369 template <bool extended>
371 
372 template <>
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:
393  };
394 
395  static bool performAction (const Entry<EntryData> &entry)
396  { return entry.flags & PerformAction; }
397 
398  static unsigned int ligActionIndex (const Entry<EntryData> &entry)
399  { return entry.data.ligActionIndex; }
400 };
401 template <>
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 
417  static bool performAction (const Entry<EntryData> &entry)
418  { return entry.flags & Offset; }
419 
420  static unsigned int ligActionIndex (const Entry<EntryData> &entry)
421  { return entry.flags & Offset; }
422 };
423 
424 
425 template <typename Types>
427 {
428  typedef typename Types::HBUINT HBUINT;
429 
431  typedef typename LigatureEntryT::EntryData EntryData;
432 
434  {
435  static constexpr bool in_place = false;
436  enum
437  {
438  DontAdvance = LigatureEntryT::DontAdvance,
439  };
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 
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 
463  const Entry<EntryData> &entry)
464  {
465  return LigatureEntryT::performAction (entry);
466  }
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:
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 
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 
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:
597  ligAction; /* Offset to the ligature action table. */
599  component; /* Offset to the component table. */
601  ligature; /* Offset to the actual ligature lists. */
602  public:
604 };
605 
606 template <typename Types>
608 {
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 
638  {
639  TRACE_SANITIZE (this);
640  return_trace (substitute.sanitize (c));
641  }
642 
643  protected:
645  public:
647 };
648 
649 template <typename Types>
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:
668  };
669 
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 
723  ret (false),
724  c (c_),
725  mark (0),
726  insertionAction (table+table->insertionAction) {}
727 
729  const Entry<EntryData> &entry)
730  {
731  return (entry.flags & (CurrentInsertCount | MarkedInsertCount)) &&
732  (entry.data.currentInsertIndex != 0xFFFF ||entry.data.markedInsertIndex != 0xFFFF);
733  }
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:
812  unsigned int mark;
813  const UnsizedArrayOf<HBGlyphID16> &insertionAction;
814  };
815 
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 
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:
840  insertionAction; /* Byte offset from stateHeader to the start of
841  * the insertion glyph table. */
842  public:
844 };
845 
846 
847 struct Feature
848 {
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:
865 };
866 
867 template <typename Types>
869 {
870  typedef typename Types::HBUINT HBUINT;
871 
872  template <typename T>
873  friend struct Chain;
874 
875  unsigned int get_size () const { return length; }
876  unsigned int get_type () const { return coverage & 0xFF; }
877  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>
904  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 
919  {
920  TRACE_APPLY (this);
921  hb_sanitize_with_object_t with (&c->sanitizer, this);
922  return_trace (dispatch (c));
923  }
924 
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 {
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 
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];
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  }
977  {
978  /* Deprecated. https://github.com/harfbuzz/harfbuzz/issues/1342 */
981  goto retry;
982  }
983  }
984  }
985  return flags;
986  }
987 
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  c->buffer->reverse ();
1042 
1043  subtable->apply (c);
1044 
1045  if (reverse)
1046  c->buffer->reverse ();
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 
1058  unsigned int get_size () const { return length; }
1059 
1060  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 
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 
1107  bool has_data () const { return version != 0; }
1108 
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 
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 
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:
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 */
small capitals from c petite p scientific f u
Definition: afcover.h:88
small capitals from c petite p scientific i
[1]
Definition: afcover.h:80
FT_UInt idx
Definition: cffcmap.c:135
QMap< QString, QString > map
[6]
QCursor cursor
int const char * version
Definition: zlib.h:814
#define true
Definition: ftrandom.c:51
hb_aat_layout_feature_selector_t
@ HB_AAT_LAYOUT_FEATURE_SELECTOR_SMALL_CAPS
@ HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS
hb_aat_layout_feature_type_t
Definition: hb-aat-layout.h:86
@ HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE
Definition: hb-aat-layout.h:92
@ HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE
#define TRACE_SANITIZE(this)
Definition: hb-debug.hh:414
#define DEBUG_MSG(WHAT, OBJ,...)
#define TRACE_DISPATCH(this, format)
Definition: hb-debug.hh:459
#define TRACE_APPLY(this)
Definition: hb-debug.hh:402
#define return_trace(RET)
Definition: hb-debug.hh:349
void const void *obj HB_UNUSED
Definition: hb-debug.hh:180
#define HB_MAX_CONTEXT_LENGTH
#define unlikely(expr)
Definition: hb.hh:251
backing_store_ptr info
[4]
Definition: jmemsys.h:161
@ Vertical
Definition: qnamespace.h:125
action
Definition: devices.py:78
void *PRIV() memmove(void *d, const void *s, size_t n)
void
Definition: png.h:1080
quint16 Offset
#define TAG(x)
#define ARRAY_LENGTH(a)
Definition: qkmsdevice.cpp:52
GLenum GLuint GLenum GLsizei length
Definition: qopengl.h:270
GLenum type
Definition: qopengl.h:270
const GLfloat * m
GLboolean r
[2]
GLuint GLuint end
GLenum GLenum GLsizei count
GLenum GLuint buffer
GLenum GLuint GLenum GLsizei const GLchar * buf
GLbitfield flags
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint start
GLenum GLuint GLintptr offset
const GLubyte * c
Definition: qopenglext.h:12701
GLuint entry
Definition: qopenglext.h:11002
GLenum GLenum GLsizei void * table
Definition: qopenglext.h:2745
uint32_t hb_codepoint_t
Definition: hb-common.h:106
uint32_t hb_mask_t
Definition: hb-common.h:122
#define HB_DIRECTION_IS_VERTICAL(dir)
Definition: hb-common.h:270
#define HB_DIRECTION_IS_BACKWARD(dir)
Definition: hb-common.h:288
uint32_t hb_tag_t
Definition: hb-common.h:157
QDataWidgetMapper * mapper
[0]
void apply(hb_aat_apply_context_t *c, hb_mask_t flags) const
hb_mask_t compile_flags(const hb_aat_map_builder_t *map) const
DEFINE_SIZE_MIN(8+2 *sizeof(HBUINT))
unsigned int get_size() const
bool sanitize(hb_sanitize_context_t *c, unsigned int version HB_UNUSED) const
UnsizedArrayOf< Feature > featureZ
ContextualSubtable< Types > contextual
RearrangementSubtable< Types > rearrangement
NoncontextualSubtable< Types > noncontextual
unsigned int get_coverage() const
unsigned int get_type() const
InsertionSubtable< Types > insertion
unsigned int get_size() const
bool sanitize(hb_sanitize_context_t *c) const
DEFINE_SIZE_MIN(2 *sizeof(HBUINT)+4)
context_t::return_t dispatch(context_t *c, Ts &&... ds) const
bool apply(hb_aat_apply_context_t *c) const
LigatureSubtable< Types > ligature
HBUINT16 currentIndex
DEFINE_SIZE_STATIC(4)
HBUINT16 markIndex
bool is_actionable(StateTableDriver< Types, EntryData > *driver, const Entry< EntryData > &entry)
void transition(StateTableDriver< Types, EntryData > *driver, const Entry< EntryData > &entry)
driver_context_t(const ContextualSubtable *table_, hb_aat_apply_context_t *c_)
bool sanitize(hb_sanitize_context_t *c) const
NNOffsetTo< UnsizedListOfOffset16To< Lookup< HBGlyphID16 >, HBUINT, false >, HBUINT > substitutionTables
StateTable< Types, EntryData > machine
bool apply(hb_aat_apply_context_t *c) const
T data
bool sanitize(hb_sanitize_context_t *c) const
DEFINE_SIZE_STATIC(12)
DEFINE_SIZE_STATIC(4)
HBUINT16 currentInsertIndex
HBUINT16 markedInsertIndex
void transition(StateTableDriver< Types, EntryData > *driver, const Entry< EntryData > &entry)
driver_context_t(const InsertionSubtable *table, hb_aat_apply_context_t *c_)
bool is_actionable(StateTableDriver< Types, EntryData > *driver HB_UNUSED, const Entry< EntryData > &entry)
NNOffsetTo< UnsizedArrayOf< HBGlyphID16 >, HBUINT > insertionAction
StateTable< Types, EntryData > machine
bool apply(hb_aat_apply_context_t *c) const
bool sanitize(hb_sanitize_context_t *c) const
static bool performAction(const Entry< EntryData > &entry)
static unsigned int ligActionIndex(const Entry< EntryData > &entry)
Flags
void EntryData
HBUINT16 ligActionIndex
DEFINE_SIZE_STATIC(2)
Flags
static bool performAction(const Entry< EntryData > &entry)
static unsigned int ligActionIndex(const Entry< EntryData > &entry)
bool is_actionable(StateTableDriver< Types, EntryData > *driver HB_UNUSED, const Entry< EntryData > &entry)
driver_context_t(const LigatureSubtable *table_, hb_aat_apply_context_t *c_)
void transition(StateTableDriver< Types, EntryData > *driver, const Entry< EntryData > &entry)
NNOffsetTo< UnsizedArrayOf< HBUINT32 >, HBUINT > ligAction
NNOffsetTo< UnsizedArrayOf< HBGlyphID16 >, HBUINT > ligature
bool apply(hb_aat_apply_context_t *c) const
NNOffsetTo< UnsizedArrayOf< HBUINT16 >, HBUINT > component
LigatureEntryT::EntryData EntryData
bool sanitize(hb_sanitize_context_t *c) const
StateTable< Types, EntryData > machine
LigatureEntry< Types::extended > LigatureEntryT
const T * get_value(hb_codepoint_t glyph_id, unsigned int num_glyphs) const
bool sanitize(hb_sanitize_context_t *c) const
bool apply(hb_aat_apply_context_t *c) const
driver_context_t(const RearrangementSubtable *table HB_UNUSED)
bool is_actionable(StateTableDriver< Types, EntryData > *driver HB_UNUSED, const Entry< EntryData > &entry)
void transition(StateTableDriver< Types, EntryData > *driver, const Entry< EntryData > &entry)
bool apply(hb_aat_apply_context_t *c) const
bool sanitize(hb_sanitize_context_t *c) const
StateTable< Types, EntryData > machine
bool sanitize(hb_sanitize_context_t *c) const
void apply(hb_aat_apply_context_t *c) const
void compile_flags(const hb_aat_map_builder_t *mapper, hb_aat_map_t *map) const
bool has_glyph_classes() const
unsigned int get_glyph_props(hb_codepoint_t glyph) const
bool sanitize(hb_sanitize_context_t *c) const
Type arrayZ[HB_VAR_ARRAY]
Definition: moc.h:48
hb_buffer_flags_t flags
Definition: hb-buffer.hh:95