Imported Upstream version 3.4.0
[platform/upstream/harfbuzz.git] / src / hb-aat-layout-common.hh
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_COMMON_HH
28 #define HB_AAT_LAYOUT_COMMON_HH
29
30 #include "hb-aat-layout.hh"
31 #include "hb-open-type.hh"
32
33 namespace OT {
34 struct GDEF;
35 };
36
37 namespace AAT {
38
39 using namespace OT;
40
41
42 /*
43  * Lookup Table
44  */
45
46 template <typename T> struct Lookup;
47
48 template <typename T>
49 struct LookupFormat0
50 {
51   friend struct Lookup<T>;
52
53   private:
54   const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
55   {
56     if (unlikely (glyph_id >= num_glyphs)) return nullptr;
57     return &arrayZ[glyph_id];
58   }
59
60   bool sanitize (hb_sanitize_context_t *c) const
61   {
62     TRACE_SANITIZE (this);
63     return_trace (arrayZ.sanitize (c, c->get_num_glyphs ()));
64   }
65   bool sanitize (hb_sanitize_context_t *c, const void *base) const
66   {
67     TRACE_SANITIZE (this);
68     return_trace (arrayZ.sanitize (c, c->get_num_glyphs (), base));
69   }
70
71   protected:
72   HBUINT16      format;         /* Format identifier--format = 0 */
73   UnsizedArrayOf<T>
74                 arrayZ;         /* Array of lookup values, indexed by glyph index. */
75   public:
76   DEFINE_SIZE_UNBOUNDED (2);
77 };
78
79
80 template <typename T>
81 struct LookupSegmentSingle
82 {
83   static constexpr unsigned TerminationWordCount = 2u;
84
85   int cmp (hb_codepoint_t g) const
86   { return g < first ? -1 : g <= last ? 0 : +1 ; }
87
88   bool sanitize (hb_sanitize_context_t *c) const
89   {
90     TRACE_SANITIZE (this);
91     return_trace (c->check_struct (this) && value.sanitize (c));
92   }
93   bool sanitize (hb_sanitize_context_t *c, const void *base) const
94   {
95     TRACE_SANITIZE (this);
96     return_trace (c->check_struct (this) && value.sanitize (c, base));
97   }
98
99   HBGlyphID16   last;           /* Last GlyphID in this segment */
100   HBGlyphID16   first;          /* First GlyphID in this segment */
101   T             value;          /* The lookup value (only one) */
102   public:
103   DEFINE_SIZE_STATIC (4 + T::static_size);
104 };
105
106 template <typename T>
107 struct LookupFormat2
108 {
109   friend struct Lookup<T>;
110
111   private:
112   const T* get_value (hb_codepoint_t glyph_id) const
113   {
114     const LookupSegmentSingle<T> *v = segments.bsearch (glyph_id);
115     return v ? &v->value : nullptr;
116   }
117
118   bool sanitize (hb_sanitize_context_t *c) const
119   {
120     TRACE_SANITIZE (this);
121     return_trace (segments.sanitize (c));
122   }
123   bool sanitize (hb_sanitize_context_t *c, const void *base) const
124   {
125     TRACE_SANITIZE (this);
126     return_trace (segments.sanitize (c, base));
127   }
128
129   protected:
130   HBUINT16      format;         /* Format identifier--format = 2 */
131   VarSizedBinSearchArrayOf<LookupSegmentSingle<T>>
132                 segments;       /* The actual segments. These must already be sorted,
133                                  * according to the first word in each one (the last
134                                  * glyph in each segment). */
135   public:
136   DEFINE_SIZE_ARRAY (8, segments);
137 };
138
139 template <typename T>
140 struct LookupSegmentArray
141 {
142   static constexpr unsigned TerminationWordCount = 2u;
143
144   const T* get_value (hb_codepoint_t glyph_id, const void *base) const
145   {
146     return first <= glyph_id && glyph_id <= last ? &(base+valuesZ)[glyph_id - first] : nullptr;
147   }
148
149   int cmp (hb_codepoint_t g) const
150   { return g < first ? -1 : g <= last ? 0 : +1; }
151
152   bool sanitize (hb_sanitize_context_t *c, const void *base) const
153   {
154     TRACE_SANITIZE (this);
155     return_trace (c->check_struct (this) &&
156                   first <= last &&
157                   valuesZ.sanitize (c, base, last - first + 1));
158   }
159   template <typename ...Ts>
160   bool sanitize (hb_sanitize_context_t *c, const void *base, Ts&&... ds) const
161   {
162     TRACE_SANITIZE (this);
163     return_trace (c->check_struct (this) &&
164                   first <= last &&
165                   valuesZ.sanitize (c, base, last - first + 1, std::forward<Ts> (ds)...));
166   }
167
168   HBGlyphID16   last;           /* Last GlyphID in this segment */
169   HBGlyphID16   first;          /* First GlyphID in this segment */
170   NNOffset16To<UnsizedArrayOf<T>>
171                 valuesZ;        /* A 16-bit offset from the start of
172                                  * the table to the data. */
173   public:
174   DEFINE_SIZE_STATIC (6);
175 };
176
177 template <typename T>
178 struct LookupFormat4
179 {
180   friend struct Lookup<T>;
181
182   private:
183   const T* get_value (hb_codepoint_t glyph_id) const
184   {
185     const LookupSegmentArray<T> *v = segments.bsearch (glyph_id);
186     return v ? v->get_value (glyph_id, this) : nullptr;
187   }
188
189   bool sanitize (hb_sanitize_context_t *c) const
190   {
191     TRACE_SANITIZE (this);
192     return_trace (segments.sanitize (c, this));
193   }
194   bool sanitize (hb_sanitize_context_t *c, const void *base) const
195   {
196     TRACE_SANITIZE (this);
197     return_trace (segments.sanitize (c, this, base));
198   }
199
200   protected:
201   HBUINT16      format;         /* Format identifier--format = 4 */
202   VarSizedBinSearchArrayOf<LookupSegmentArray<T>>
203                 segments;       /* The actual segments. These must already be sorted,
204                                  * according to the first word in each one (the last
205                                  * glyph in each segment). */
206   public:
207   DEFINE_SIZE_ARRAY (8, segments);
208 };
209
210 template <typename T>
211 struct LookupSingle
212 {
213   static constexpr unsigned TerminationWordCount = 1u;
214
215   int cmp (hb_codepoint_t g) const { return glyph.cmp (g); }
216
217   bool sanitize (hb_sanitize_context_t *c) const
218   {
219     TRACE_SANITIZE (this);
220     return_trace (c->check_struct (this) && value.sanitize (c));
221   }
222   bool sanitize (hb_sanitize_context_t *c, const void *base) const
223   {
224     TRACE_SANITIZE (this);
225     return_trace (c->check_struct (this) && value.sanitize (c, base));
226   }
227
228   HBGlyphID16   glyph;          /* Last GlyphID */
229   T             value;          /* The lookup value (only one) */
230   public:
231   DEFINE_SIZE_STATIC (2 + T::static_size);
232 };
233
234 template <typename T>
235 struct LookupFormat6
236 {
237   friend struct Lookup<T>;
238
239   private:
240   const T* get_value (hb_codepoint_t glyph_id) const
241   {
242     const LookupSingle<T> *v = entries.bsearch (glyph_id);
243     return v ? &v->value : nullptr;
244   }
245
246   bool sanitize (hb_sanitize_context_t *c) const
247   {
248     TRACE_SANITIZE (this);
249     return_trace (entries.sanitize (c));
250   }
251   bool sanitize (hb_sanitize_context_t *c, const void *base) const
252   {
253     TRACE_SANITIZE (this);
254     return_trace (entries.sanitize (c, base));
255   }
256
257   protected:
258   HBUINT16      format;         /* Format identifier--format = 6 */
259   VarSizedBinSearchArrayOf<LookupSingle<T>>
260                 entries;        /* The actual entries, sorted by glyph index. */
261   public:
262   DEFINE_SIZE_ARRAY (8, entries);
263 };
264
265 template <typename T>
266 struct LookupFormat8
267 {
268   friend struct Lookup<T>;
269
270   private:
271   const T* get_value (hb_codepoint_t glyph_id) const
272   {
273     return firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount ?
274            &valueArrayZ[glyph_id - firstGlyph] : nullptr;
275   }
276
277   bool sanitize (hb_sanitize_context_t *c) const
278   {
279     TRACE_SANITIZE (this);
280     return_trace (c->check_struct (this) && valueArrayZ.sanitize (c, glyphCount));
281   }
282   bool sanitize (hb_sanitize_context_t *c, const void *base) const
283   {
284     TRACE_SANITIZE (this);
285     return_trace (c->check_struct (this) && valueArrayZ.sanitize (c, glyphCount, base));
286   }
287
288   protected:
289   HBUINT16      format;         /* Format identifier--format = 8 */
290   HBGlyphID16   firstGlyph;     /* First glyph index included in the trimmed array. */
291   HBUINT16      glyphCount;     /* Total number of glyphs (equivalent to the last
292                                  * glyph minus the value of firstGlyph plus 1). */
293   UnsizedArrayOf<T>
294                 valueArrayZ;    /* The lookup values (indexed by the glyph index
295                                  * minus the value of firstGlyph). */
296   public:
297   DEFINE_SIZE_ARRAY (6, valueArrayZ);
298 };
299
300 template <typename T>
301 struct LookupFormat10
302 {
303   friend struct Lookup<T>;
304
305   private:
306   const typename T::type get_value_or_null (hb_codepoint_t glyph_id) const
307   {
308     if (!(firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount))
309       return Null (T);
310
311     const HBUINT8 *p = &valueArrayZ[(glyph_id - firstGlyph) * valueSize];
312
313     unsigned int v = 0;
314     unsigned int count = valueSize;
315     for (unsigned int i = 0; i < count; i++)
316       v = (v << 8) | *p++;
317
318     return v;
319   }
320
321   bool sanitize (hb_sanitize_context_t *c) const
322   {
323     TRACE_SANITIZE (this);
324     return_trace (c->check_struct (this) &&
325                   valueSize <= 4 &&
326                   valueArrayZ.sanitize (c, glyphCount * valueSize));
327   }
328
329   protected:
330   HBUINT16      format;         /* Format identifier--format = 8 */
331   HBUINT16      valueSize;      /* Byte size of each value. */
332   HBGlyphID16   firstGlyph;     /* First glyph index included in the trimmed array. */
333   HBUINT16      glyphCount;     /* Total number of glyphs (equivalent to the last
334                                  * glyph minus the value of firstGlyph plus 1). */
335   UnsizedArrayOf<HBUINT8>
336                 valueArrayZ;    /* The lookup values (indexed by the glyph index
337                                  * minus the value of firstGlyph). */
338   public:
339   DEFINE_SIZE_ARRAY (8, valueArrayZ);
340 };
341
342 template <typename T>
343 struct Lookup
344 {
345   const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
346   {
347     switch (u.format) {
348     case 0: return u.format0.get_value (glyph_id, num_glyphs);
349     case 2: return u.format2.get_value (glyph_id);
350     case 4: return u.format4.get_value (glyph_id);
351     case 6: return u.format6.get_value (glyph_id);
352     case 8: return u.format8.get_value (glyph_id);
353     default:return nullptr;
354     }
355   }
356
357   const typename T::type get_value_or_null (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
358   {
359     switch (u.format) {
360       /* Format 10 cannot return a pointer. */
361       case 10: return u.format10.get_value_or_null (glyph_id);
362       default:
363       const T *v = get_value (glyph_id, num_glyphs);
364       return v ? *v : Null (T);
365     }
366   }
367
368   typename T::type get_class (hb_codepoint_t glyph_id,
369                               unsigned int num_glyphs,
370                               unsigned int outOfRange) const
371   {
372     const T *v = get_value (glyph_id, num_glyphs);
373     return v ? *v : outOfRange;
374   }
375
376   bool sanitize (hb_sanitize_context_t *c) const
377   {
378     TRACE_SANITIZE (this);
379     if (!u.format.sanitize (c)) return_trace (false);
380     switch (u.format) {
381     case 0: return_trace (u.format0.sanitize (c));
382     case 2: return_trace (u.format2.sanitize (c));
383     case 4: return_trace (u.format4.sanitize (c));
384     case 6: return_trace (u.format6.sanitize (c));
385     case 8: return_trace (u.format8.sanitize (c));
386     case 10: return_trace (u.format10.sanitize (c));
387     default:return_trace (true);
388     }
389   }
390   bool sanitize (hb_sanitize_context_t *c, const void *base) const
391   {
392     TRACE_SANITIZE (this);
393     if (!u.format.sanitize (c)) return_trace (false);
394     switch (u.format) {
395     case 0: return_trace (u.format0.sanitize (c, base));
396     case 2: return_trace (u.format2.sanitize (c, base));
397     case 4: return_trace (u.format4.sanitize (c, base));
398     case 6: return_trace (u.format6.sanitize (c, base));
399     case 8: return_trace (u.format8.sanitize (c, base));
400     case 10: return_trace (false); /* We don't support format10 here currently. */
401     default:return_trace (true);
402     }
403   }
404
405   protected:
406   union {
407   HBUINT16              format;         /* Format identifier */
408   LookupFormat0<T>      format0;
409   LookupFormat2<T>      format2;
410   LookupFormat4<T>      format4;
411   LookupFormat6<T>      format6;
412   LookupFormat8<T>      format8;
413   LookupFormat10<T>     format10;
414   } u;
415   public:
416   DEFINE_SIZE_UNION (2, format);
417 };
418 /* Lookup 0 has unbounded size (dependant on num_glyphs).  So we need to defined
419  * special NULL objects for Lookup<> objects, but since it's template our macros
420  * don't work.  So we have to hand-code them here.  UGLY. */
421 } /* Close namespace. */
422 /* Ugly hand-coded null objects for template Lookup<> :(. */
423 extern HB_INTERNAL const unsigned char _hb_Null_AAT_Lookup[2];
424 template <typename T>
425 struct Null<AAT::Lookup<T>> {
426   static AAT::Lookup<T> const & get_null ()
427   { return *reinterpret_cast<const AAT::Lookup<T> *> (_hb_Null_AAT_Lookup); }
428 };
429 namespace AAT {
430
431 enum { DELETED_GLYPH = 0xFFFF };
432
433 /*
434  * (Extended) State Table
435  */
436
437 template <typename T>
438 struct Entry
439 {
440   bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
441   {
442     TRACE_SANITIZE (this);
443     /* Note, we don't recurse-sanitize data because we don't access it.
444      * That said, in our DEFINE_SIZE_STATIC we access T::static_size,
445      * which ensures that data has a simple sanitize(). To be determined
446      * if I need to remove that as well.
447      *
448      * HOWEVER! Because we are a template, our DEFINE_SIZE_STATIC
449      * assertion wouldn't be checked, hence the line below. */
450     static_assert (T::static_size, "");
451
452     return_trace (c->check_struct (this));
453   }
454
455   public:
456   HBUINT16      newState;       /* Byte offset from beginning of state table
457                                  * to the new state. Really?!?! Or just state
458                                  * number?  The latter in morx for sure. */
459   HBUINT16      flags;          /* Table specific. */
460   T             data;           /* Optional offsets to per-glyph tables. */
461   public:
462   DEFINE_SIZE_STATIC (4 + T::static_size);
463 };
464
465 template <>
466 struct Entry<void>
467 {
468   bool sanitize (hb_sanitize_context_t *c, unsigned int count /*XXX Unused?*/) const
469   {
470     TRACE_SANITIZE (this);
471     return_trace (c->check_struct (this));
472   }
473
474   public:
475   HBUINT16      newState;       /* Byte offset from beginning of state table to the new state. */
476   HBUINT16      flags;          /* Table specific. */
477   public:
478   DEFINE_SIZE_STATIC (4);
479 };
480
481 template <typename Types, typename Extra>
482 struct StateTable
483 {
484   typedef typename Types::HBUINT HBUINT;
485   typedef typename Types::HBUSHORT HBUSHORT;
486   typedef typename Types::ClassTypeNarrow ClassType;
487
488   enum State
489   {
490     STATE_START_OF_TEXT = 0,
491     STATE_START_OF_LINE = 1,
492   };
493   enum Class
494   {
495     CLASS_END_OF_TEXT = 0,
496     CLASS_OUT_OF_BOUNDS = 1,
497     CLASS_DELETED_GLYPH = 2,
498     CLASS_END_OF_LINE = 3,
499   };
500
501   int new_state (unsigned int newState) const
502   { return Types::extended ? newState : ((int) newState - (int) stateArrayTable) / (int) nClasses; }
503
504   unsigned int get_class (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
505   {
506     if (unlikely (glyph_id == DELETED_GLYPH)) return CLASS_DELETED_GLYPH;
507     return (this+classTable).get_class (glyph_id, num_glyphs, 1);
508   }
509
510   const Entry<Extra> *get_entries () const
511   { return (this+entryTable).arrayZ; }
512
513   const Entry<Extra> &get_entry (int state, unsigned int klass) const
514   {
515     if (unlikely (klass >= nClasses))
516       klass = StateTable::CLASS_OUT_OF_BOUNDS;
517
518     const HBUSHORT *states = (this+stateArrayTable).arrayZ;
519     const Entry<Extra> *entries = (this+entryTable).arrayZ;
520
521     unsigned int entry = states[state * nClasses + klass];
522     DEBUG_MSG (APPLY, nullptr, "e%u", entry);
523
524     return entries[entry];
525   }
526
527   bool sanitize (hb_sanitize_context_t *c,
528                  unsigned int *num_entries_out = nullptr) const
529   {
530     TRACE_SANITIZE (this);
531     if (unlikely (!(c->check_struct (this) &&
532                     nClasses >= 4 /* Ensure pre-defined classes fit.  */ &&
533                     classTable.sanitize (c, this)))) return_trace (false);
534
535     const HBUSHORT *states = (this+stateArrayTable).arrayZ;
536     const Entry<Extra> *entries = (this+entryTable).arrayZ;
537
538     unsigned int num_classes = nClasses;
539     if (unlikely (hb_unsigned_mul_overflows (num_classes, states[0].static_size)))
540       return_trace (false);
541     unsigned int row_stride = num_classes * states[0].static_size;
542
543     /* Apple 'kern' table has this peculiarity:
544      *
545      * "Because the stateTableOffset in the state table header is (strictly
546      * speaking) redundant, some 'kern' tables use it to record an initial
547      * state where that should not be StartOfText. To determine if this is
548      * done, calculate what the stateTableOffset should be. If it's different
549      * from the actual stateTableOffset, use it as the initial state."
550      *
551      * We implement this by calling the initial state zero, but allow *negative*
552      * states if the start state indeed was not the first state.  Since the code
553      * is shared, this will also apply to 'mort' table.  The 'kerx' / 'morx'
554      * tables are not affected since those address states by index, not offset.
555      */
556
557     int min_state = 0;
558     int max_state = 0;
559     unsigned int num_entries = 0;
560
561     int state_pos = 0;
562     int state_neg = 0;
563     unsigned int entry = 0;
564     while (min_state < state_neg || state_pos <= max_state)
565     {
566       if (min_state < state_neg)
567       {
568         /* Negative states. */
569         if (unlikely (hb_unsigned_mul_overflows (min_state, num_classes)))
570           return_trace (false);
571         if (unlikely (!c->check_range (&states[min_state * num_classes],
572                                        -min_state,
573                                        row_stride)))
574           return_trace (false);
575         if ((c->max_ops -= state_neg - min_state) <= 0)
576           return_trace (false);
577         { /* Sweep new states. */
578           const HBUSHORT *stop = &states[min_state * num_classes];
579           if (unlikely (stop > states))
580             return_trace (false);
581           for (const HBUSHORT *p = states; stop < p; p--)
582             num_entries = hb_max (num_entries, *(p - 1) + 1u);
583           state_neg = min_state;
584         }
585       }
586
587       if (state_pos <= max_state)
588       {
589         /* Positive states. */
590         if (unlikely (!c->check_range (states,
591                                        max_state + 1,
592                                        row_stride)))
593           return_trace (false);
594         if ((c->max_ops -= max_state - state_pos + 1) <= 0)
595           return_trace (false);
596         { /* Sweep new states. */
597           if (unlikely (hb_unsigned_mul_overflows ((max_state + 1), num_classes)))
598             return_trace (false);
599           const HBUSHORT *stop = &states[(max_state + 1) * num_classes];
600           if (unlikely (stop < states))
601             return_trace (false);
602           for (const HBUSHORT *p = &states[state_pos * num_classes]; p < stop; p++)
603             num_entries = hb_max (num_entries, *p + 1u);
604           state_pos = max_state + 1;
605         }
606       }
607
608       if (unlikely (!c->check_array (entries, num_entries)))
609         return_trace (false);
610       if ((c->max_ops -= num_entries - entry) <= 0)
611         return_trace (false);
612       { /* Sweep new entries. */
613         const Entry<Extra> *stop = &entries[num_entries];
614         for (const Entry<Extra> *p = &entries[entry]; p < stop; p++)
615         {
616           int newState = new_state (p->newState);
617           min_state = hb_min (min_state, newState);
618           max_state = hb_max (max_state, newState);
619         }
620         entry = num_entries;
621       }
622     }
623
624     if (num_entries_out)
625       *num_entries_out = num_entries;
626
627     return_trace (true);
628   }
629
630   protected:
631   HBUINT        nClasses;       /* Number of classes, which is the number of indices
632                                  * in a single line in the state array. */
633   NNOffsetTo<ClassType, HBUINT>
634                 classTable;     /* Offset to the class table. */
635   NNOffsetTo<UnsizedArrayOf<HBUSHORT>, HBUINT>
636                 stateArrayTable;/* Offset to the state array. */
637   NNOffsetTo<UnsizedArrayOf<Entry<Extra>>, HBUINT>
638                 entryTable;     /* Offset to the entry array. */
639
640   public:
641   DEFINE_SIZE_STATIC (4 * sizeof (HBUINT));
642 };
643
644 template <typename HBUCHAR>
645 struct ClassTable
646 {
647   unsigned int get_class (hb_codepoint_t glyph_id, unsigned int outOfRange) const
648   {
649     unsigned int i = glyph_id - firstGlyph;
650     return i >= classArray.len ? outOfRange : classArray.arrayZ[i];
651   }
652   unsigned int get_class (hb_codepoint_t glyph_id,
653                           unsigned int num_glyphs HB_UNUSED,
654                           unsigned int outOfRange) const
655   {
656     return get_class (glyph_id, outOfRange);
657   }
658   bool sanitize (hb_sanitize_context_t *c) const
659   {
660     TRACE_SANITIZE (this);
661     return_trace (c->check_struct (this) && classArray.sanitize (c));
662   }
663   protected:
664   HBGlyphID16           firstGlyph;     /* First glyph index included in the trimmed array. */
665   Array16Of<HBUCHAR>    classArray;     /* The class codes (indexed by glyph index minus
666                                          * firstGlyph). */
667   public:
668   DEFINE_SIZE_ARRAY (4, classArray);
669 };
670
671 struct ObsoleteTypes
672 {
673   static constexpr bool extended = false;
674   typedef HBUINT16 HBUINT;
675   typedef HBUINT8 HBUSHORT;
676   typedef ClassTable<HBUINT8> ClassTypeNarrow;
677   typedef ClassTable<HBUINT16> ClassTypeWide;
678
679   template <typename T>
680   static unsigned int offsetToIndex (unsigned int offset,
681                                      const void *base,
682                                      const T *array)
683   {
684     /* https://github.com/harfbuzz/harfbuzz/issues/2816 */
685     return (offset - unsigned ((const char *) array - (const char *) base)) / T::static_size;
686   }
687   template <typename T>
688   static unsigned int byteOffsetToIndex (unsigned int offset,
689                                          const void *base,
690                                          const T *array)
691   {
692     return offsetToIndex (offset, base, array);
693   }
694   template <typename T>
695   static unsigned int wordOffsetToIndex (unsigned int offset,
696                                          const void *base,
697                                          const T *array)
698   {
699     return offsetToIndex (2 * offset, base, array);
700   }
701 };
702 struct ExtendedTypes
703 {
704   static constexpr bool extended = true;
705   typedef HBUINT32 HBUINT;
706   typedef HBUINT16 HBUSHORT;
707   typedef Lookup<HBUINT16> ClassTypeNarrow;
708   typedef Lookup<HBUINT16> ClassTypeWide;
709
710   template <typename T>
711   static unsigned int offsetToIndex (unsigned int offset,
712                                      const void *base HB_UNUSED,
713                                      const T *array HB_UNUSED)
714   {
715     return offset;
716   }
717   template <typename T>
718   static unsigned int byteOffsetToIndex (unsigned int offset,
719                                          const void *base HB_UNUSED,
720                                          const T *array HB_UNUSED)
721   {
722     return offset / 2;
723   }
724   template <typename T>
725   static unsigned int wordOffsetToIndex (unsigned int offset,
726                                          const void *base HB_UNUSED,
727                                          const T *array HB_UNUSED)
728   {
729     return offset;
730   }
731 };
732
733 template <typename Types, typename EntryData>
734 struct StateTableDriver
735 {
736   using StateTableT = StateTable<Types, EntryData>;
737   using EntryT = Entry<EntryData>;
738
739   StateTableDriver (const StateTableT &machine_,
740                     hb_buffer_t *buffer_,
741                     hb_face_t *face_) :
742               machine (machine_),
743               buffer (buffer_),
744               num_glyphs (face_->get_num_glyphs ()) {}
745
746   template <typename context_t>
747   void drive (context_t *c)
748   {
749     if (!c->in_place)
750       buffer->clear_output ();
751
752     int state = StateTableT::STATE_START_OF_TEXT;
753     for (buffer->idx = 0; buffer->successful;)
754     {
755       unsigned int klass = buffer->idx < buffer->len ?
756                            machine.get_class (buffer->info[buffer->idx].codepoint, num_glyphs) :
757                            (unsigned) StateTableT::CLASS_END_OF_TEXT;
758       DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx);
759       const EntryT &entry = machine.get_entry (state, klass);
760       const int next_state = machine.new_state (entry.newState);
761
762       /* Conditions under which it's guaranteed safe-to-break before current glyph:
763        *
764        * 1. There was no action in this transition; and
765        *
766        * 2. If we break before current glyph, the results will be the same. That
767        *    is guaranteed if:
768        *
769        *    2a. We were already in start-of-text state; or
770        *
771        *    2b. We are epsilon-transitioning to start-of-text state; or
772        *
773        *    2c. Starting from start-of-text state seeing current glyph:
774        *
775        *        2c'. There won't be any actions; and
776        *
777        *        2c". We would end up in the same state that we were going to end up
778        *             in now, including whether epsilon-transitioning.
779        *
780        *    and
781        *
782        * 3. If we break before current glyph, there won't be any end-of-text action
783        *    after previous glyph.
784        *
785        * This triples the transitions we need to look up, but is worth returning
786        * granular unsafe-to-break results. See eg.:
787        *
788        *   https://github.com/harfbuzz/harfbuzz/issues/2860
789        */
790       const EntryT *wouldbe_entry;
791       bool safe_to_break =
792         /* 1. */
793         !c->is_actionable (this, entry)
794       &&
795         /* 2. */
796         (
797           /* 2a. */
798           state == StateTableT::STATE_START_OF_TEXT
799         ||
800           /* 2b. */
801           (
802             (entry.flags & context_t::DontAdvance) &&
803             next_state == StateTableT::STATE_START_OF_TEXT
804           )
805         ||
806           /* 2c. */
807           (
808             wouldbe_entry = &machine.get_entry (StateTableT::STATE_START_OF_TEXT, klass)
809           ,
810             /* 2c'. */
811             !c->is_actionable (this, *wouldbe_entry)
812           &&
813             /* 2c". */
814             (
815               next_state == machine.new_state (wouldbe_entry->newState)
816             &&
817               (entry.flags & context_t::DontAdvance) == (wouldbe_entry->flags & context_t::DontAdvance)
818             )
819           )
820         )
821       &&
822         /* 3. */
823         !c->is_actionable (this, machine.get_entry (state, StateTableT::CLASS_END_OF_TEXT))
824       ;
825
826       if (!safe_to_break && buffer->backtrack_len () && buffer->idx < buffer->len)
827         buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1);
828
829       c->transition (this, entry);
830
831       state = next_state;
832       DEBUG_MSG (APPLY, nullptr, "s%d", state);
833
834       if (buffer->idx == buffer->len || unlikely (!buffer->successful))
835         break;
836
837       if (!(entry.flags & context_t::DontAdvance) || buffer->max_ops-- <= 0)
838         (void) buffer->next_glyph ();
839     }
840
841     if (!c->in_place)
842       buffer->sync ();
843   }
844
845   public:
846   const StateTableT &machine;
847   hb_buffer_t *buffer;
848   unsigned int num_glyphs;
849 };
850
851
852 struct ankr;
853
854 struct hb_aat_apply_context_t :
855        hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY>
856 {
857   const char *get_name () { return "APPLY"; }
858   template <typename T>
859   return_t dispatch (const T &obj) { return obj.apply (this); }
860   static return_t default_return_value () { return false; }
861   bool stop_sublookup_iteration (return_t r) const { return r; }
862
863   const hb_ot_shape_plan_t *plan;
864   hb_font_t *font;
865   hb_face_t *face;
866   hb_buffer_t *buffer;
867   hb_sanitize_context_t sanitizer;
868   const ankr *ankr_table;
869   const OT::GDEF *gdef_table;
870
871   /* Unused. For debug tracing only. */
872   unsigned int lookup_index;
873
874   HB_INTERNAL hb_aat_apply_context_t (const hb_ot_shape_plan_t *plan_,
875                                       hb_font_t *font_,
876                                       hb_buffer_t *buffer_,
877                                       hb_blob_t *blob = const_cast<hb_blob_t *> (&Null (hb_blob_t)));
878
879   HB_INTERNAL ~hb_aat_apply_context_t ();
880
881   HB_INTERNAL void set_ankr_table (const AAT::ankr *ankr_table_);
882
883   void set_lookup_index (unsigned int i) { lookup_index = i; }
884 };
885
886
887 } /* namespace AAT */
888
889
890 #endif /* HB_AAT_LAYOUT_COMMON_HH */