• 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 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:
get_valueAAT::LookupFormat054   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 
sanitizeAAT::LookupFormat060   bool sanitize (hb_sanitize_context_t *c) const
61   {
62     TRACE_SANITIZE (this);
63     return_trace (arrayZ.sanitize (c, c->get_num_glyphs ()));
64   }
sanitizeAAT::LookupFormat065   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 
cmpAAT::LookupSegmentSingle85   int cmp (hb_codepoint_t g) const
86   { return g < first ? -1 : g <= last ? 0 : +1 ; }
87 
sanitizeAAT::LookupSegmentSingle88   bool sanitize (hb_sanitize_context_t *c) const
89   {
90     TRACE_SANITIZE (this);
91     return_trace (c->check_struct (this) && value.sanitize (c));
92   }
sanitizeAAT::LookupSegmentSingle93   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:
get_valueAAT::LookupFormat2112   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 
sanitizeAAT::LookupFormat2118   bool sanitize (hb_sanitize_context_t *c) const
119   {
120     TRACE_SANITIZE (this);
121     return_trace (segments.sanitize (c));
122   }
sanitizeAAT::LookupFormat2123   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 
get_valueAAT::LookupSegmentArray144   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 
cmpAAT::LookupSegmentArray149   int cmp (hb_codepoint_t g) const
150   { return g < first ? -1 : g <= last ? 0 : +1; }
151 
sanitizeAAT::LookupSegmentArray152   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>
sanitizeAAT::LookupSegmentArray160   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:
get_valueAAT::LookupFormat4183   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 
sanitizeAAT::LookupFormat4189   bool sanitize (hb_sanitize_context_t *c) const
190   {
191     TRACE_SANITIZE (this);
192     return_trace (segments.sanitize (c, this));
193   }
sanitizeAAT::LookupFormat4194   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 
cmpAAT::LookupSingle215   int cmp (hb_codepoint_t g) const { return glyph.cmp (g); }
216 
sanitizeAAT::LookupSingle217   bool sanitize (hb_sanitize_context_t *c) const
218   {
219     TRACE_SANITIZE (this);
220     return_trace (c->check_struct (this) && value.sanitize (c));
221   }
sanitizeAAT::LookupSingle222   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:
get_valueAAT::LookupFormat6240   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 
sanitizeAAT::LookupFormat6246   bool sanitize (hb_sanitize_context_t *c) const
247   {
248     TRACE_SANITIZE (this);
249     return_trace (entries.sanitize (c));
250   }
sanitizeAAT::LookupFormat6251   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:
get_valueAAT::LookupFormat8271   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 
sanitizeAAT::LookupFormat8277   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   }
sanitizeAAT::LookupFormat8282   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:
get_value_or_nullAAT::LookupFormat10306   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 
sanitizeAAT::LookupFormat10321   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 {
get_valueAAT::Lookup345   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 
get_value_or_nullAAT::Lookup357   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 
get_classAAT::Lookup368   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 
sanitizeAAT::Lookup376   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   }
sanitizeAAT::Lookup390   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>> {
get_nullNull426   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 {
sanitizeAAT::Entry440   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 {
sanitizeAAT::Entry468   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 
new_stateAAT::StateTable501   int new_state (unsigned int newState) const
502   { return Types::extended ? newState : ((int) newState - (int) stateArrayTable) / (int) nClasses; }
503 
get_classAAT::StateTable504   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 
get_entriesAAT::StateTable510   const Entry<Extra> *get_entries () const
511   { return (this+entryTable).arrayZ; }
512 
get_entryAAT::StateTable513   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 
sanitizeAAT::StateTable527   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 {
get_classAAT::ClassTable647   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   }
get_classAAT::ClassTable652   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   }
sanitizeAAT::ClassTable658   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>
offsetToIndexAAT::ObsoleteTypes680   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>
byteOffsetToIndexAAT::ObsoleteTypes688   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>
wordOffsetToIndexAAT::ObsoleteTypes695   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>
offsetToIndexAAT::ExtendedTypes711   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>
byteOffsetToIndexAAT::ExtendedTypes718   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>
wordOffsetToIndexAAT::ExtendedTypes725   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 
StateTableDriverAAT::StateTableDriver739   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>
driveAAT::StateTableDriver747   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->swap_buffers ();
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 {
get_nameAAT::hb_aat_apply_context_t857   const char *get_name () { return "APPLY"; }
858   template <typename T>
dispatchAAT::hb_aat_apply_context_t859   return_t dispatch (const T &obj) { return obj.apply (this); }
default_return_valueAAT::hb_aat_apply_context_t860   static return_t default_return_value () { return false; }
stop_sublookup_iterationAAT::hb_aat_apply_context_t861   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 
set_lookup_indexAAT::hb_aat_apply_context_t883   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 */
891