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