Home | History | Annotate | Download | only in src
      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:
     51   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 
     57   bool sanitize (hb_sanitize_context_t *c) const
     58   {
     59     TRACE_SANITIZE (this);
     60     return_trace (arrayZ.sanitize (c, c->get_num_glyphs ()));
     61   }
     62   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   enum { TerminationWordCount = 2 };
     81 
     82   int cmp (hb_codepoint_t g) const
     83   { return g < first ? -1 : g <= last ? 0 : +1 ; }
     84 
     85   bool sanitize (hb_sanitize_context_t *c) const
     86   {
     87     TRACE_SANITIZE (this);
     88     return_trace (c->check_struct (this) && value.sanitize (c));
     89   }
     90   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   GlyphID	last;		/* Last GlyphID in this segment */
     97   GlyphID	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:
    109   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 
    115   bool sanitize (hb_sanitize_context_t *c) const
    116   {
    117     TRACE_SANITIZE (this);
    118     return_trace (segments.sanitize (c));
    119   }
    120   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   enum { TerminationWordCount = 2 };
    140 
    141   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 
    146   int cmp (hb_codepoint_t g) const
    147   { return g < first ? -1 : g <= last ? 0 : +1; }
    148 
    149   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 T2>
    157   bool sanitize (hb_sanitize_context_t *c, const void *base, T2 user_data) const
    158   {
    159     TRACE_SANITIZE (this);
    160     return_trace (c->check_struct (this) &&
    161 		  first <= last &&
    162 		  valuesZ.sanitize (c, base, last - first + 1, user_data));
    163   }
    164 
    165   GlyphID	last;		/* Last GlyphID in this segment */
    166   GlyphID	first;		/* First GlyphID in this segment */
    167   OffsetTo<UnsizedArrayOf<T>, HBUINT16, false>
    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:
    180   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 
    186   bool sanitize (hb_sanitize_context_t *c) const
    187   {
    188     TRACE_SANITIZE (this);
    189     return_trace (segments.sanitize (c, this));
    190   }
    191   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   enum { TerminationWordCount = 1 };
    211 
    212   int cmp (hb_codepoint_t g) const { return glyph.cmp (g); }
    213 
    214   bool sanitize (hb_sanitize_context_t *c) const
    215   {
    216     TRACE_SANITIZE (this);
    217     return_trace (c->check_struct (this) && value.sanitize (c));
    218   }
    219   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   GlyphID	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:
    237   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 
    243   bool sanitize (hb_sanitize_context_t *c) const
    244   {
    245     TRACE_SANITIZE (this);
    246     return_trace (entries.sanitize (c));
    247   }
    248   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:
    268   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 
    274   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   }
    279   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   GlyphID	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:
    303   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 
    318   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   GlyphID	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 {
    342   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 
    354   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 
    365   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 
    373   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   }
    387   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); /* No need to support format10 apparently */
    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 <>
    422 /*static*/ inline const AAT::Lookup<OT::HBUINT16>& Null<AAT::Lookup<OT::HBUINT16> > ()
    423 { return *reinterpret_cast<const AAT::Lookup<OT::HBUINT16> *> (_hb_Null_AAT_Lookup); }
    424 template <>
    425 /*static*/ inline const AAT::Lookup<OT::HBUINT32>& Null<AAT::Lookup<OT::HBUINT32> > ()
    426 { return *reinterpret_cast<const AAT::Lookup<OT::HBUINT32> *> (_hb_Null_AAT_Lookup); }
    427 template <>
    428 /*static*/ inline const AAT::Lookup<OT::Offset<OT::HBUINT16, false> >& Null<AAT::Lookup<OT::Offset<OT::HBUINT16, false> > > ()
    429 { return *reinterpret_cast<const AAT::Lookup<OT::Offset<OT::HBUINT16, false> > *> (_hb_Null_AAT_Lookup); }
    430 namespace AAT {
    431 
    432 enum { DELETED_GLYPH = 0xFFFF };
    433 
    434 /*
    435  * (Extended) State Table
    436  */
    437 
    438 template <typename T>
    439 struct Entry
    440 {
    441   bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
    442   {
    443     TRACE_SANITIZE (this);
    444     /* Note, we don't recurse-sanitize data because we don't access it.
    445      * That said, in our DEFINE_SIZE_STATIC we access T::static_size,
    446      * which ensures that data has a simple sanitize(). To be determined
    447      * if I need to remove that as well.
    448      *
    449      * HOWEVER! Because we are a template, our DEFINE_SIZE_STATIC
    450      * assertion wouldn't be checked, hence the line below. */
    451     static_assert (T::static_size, "");
    452 
    453     return_trace (c->check_struct (this));
    454   }
    455 
    456   public:
    457   HBUINT16	newState;	/* Byte offset from beginning of state table
    458 				 * to the new state. Really?!?! Or just state
    459 				 * number?  The latter in morx for sure. */
    460   HBUINT16	flags;		/* Table specific. */
    461   T		data;		/* Optional offsets to per-glyph tables. */
    462   public:
    463   DEFINE_SIZE_STATIC (4 + T::static_size);
    464 };
    465 
    466 template <>
    467 struct Entry<void>
    468 {
    469   bool sanitize (hb_sanitize_context_t *c, unsigned int count /*XXX Unused?*/) const
    470   {
    471     TRACE_SANITIZE (this);
    472     return_trace (c->check_struct (this));
    473   }
    474 
    475   public:
    476   HBUINT16	newState;	/* Byte offset from beginning of state table to the new state. */
    477   HBUINT16	flags;		/* Table specific. */
    478   public:
    479   DEFINE_SIZE_STATIC (4);
    480 };
    481 
    482 template <typename Types, typename Extra>
    483 struct StateTable
    484 {
    485   typedef typename Types::HBUINT HBUINT;
    486   typedef typename Types::HBUSHORT HBUSHORT;
    487   typedef typename Types::ClassTypeNarrow ClassType;
    488 
    489   enum State
    490   {
    491     STATE_START_OF_TEXT = 0,
    492     STATE_START_OF_LINE = 1,
    493   };
    494   enum Class
    495   {
    496     CLASS_END_OF_TEXT = 0,
    497     CLASS_OUT_OF_BOUNDS = 1,
    498     CLASS_DELETED_GLYPH = 2,
    499     CLASS_END_OF_LINE = 3,
    500   };
    501 
    502   int new_state (unsigned int newState) const
    503   { return Types::extended ? newState : ((int) newState - (int) stateArrayTable) / (int) nClasses; }
    504 
    505   unsigned int get_class (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
    506   {
    507     if (unlikely (glyph_id == DELETED_GLYPH)) return CLASS_DELETED_GLYPH;
    508     return (this+classTable).get_class (glyph_id, num_glyphs, 1);
    509   }
    510 
    511   const Entry<Extra> *get_entries () const
    512   { return (this+entryTable).arrayZ; }
    513 
    514   const Entry<Extra> *get_entryZ (int state, unsigned int klass) const
    515   {
    516     if (unlikely (klass >= nClasses)) return nullptr;
    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 		    classTable.sanitize (c, this)))) return_trace (false);
    533 
    534     const HBUSHORT *states = (this+stateArrayTable).arrayZ;
    535     const Entry<Extra> *entries = (this+entryTable).arrayZ;
    536 
    537     unsigned int num_classes = nClasses;
    538     if (unlikely (hb_unsigned_mul_overflows (num_classes, states[0].static_size)))
    539       return_trace (false);
    540     unsigned int row_stride = num_classes * states[0].static_size;
    541 
    542     /* Apple 'kern' table has this peculiarity:
    543      *
    544      * "Because the stateTableOffset in the state table header is (strictly
    545      * speaking) redundant, some 'kern' tables use it to record an initial
    546      * state where that should not be StartOfText. To determine if this is
    547      * done, calculate what the stateTableOffset should be. If it's different
    548      * from the actual stateTableOffset, use it as the initial state."
    549      *
    550      * We implement this by calling the initial state zero, but allow *negative*
    551      * states if the start state indeed was not the first state.  Since the code
    552      * is shared, this will also apply to 'mort' table.  The 'kerx' / 'morx'
    553      * tables are not affected since those address states by index, not offset.
    554      */
    555 
    556     int min_state = 0;
    557     int max_state = 0;
    558     unsigned int num_entries = 0;
    559 
    560     int state_pos = 0;
    561     int state_neg = 0;
    562     unsigned int entry = 0;
    563     while (min_state < state_neg || state_pos <= max_state)
    564     {
    565       if (min_state < state_neg)
    566       {
    567 	/* Negative states. */
    568 	if (unlikely (hb_unsigned_mul_overflows (min_state, num_classes)))
    569 	  return_trace (false);
    570 	if (unlikely (!c->check_range (&states[min_state * num_classes],
    571 				       -min_state,
    572 				       row_stride)))
    573 	  return_trace (false);
    574 	if ((c->max_ops -= state_neg - min_state) < 0)
    575 	  return_trace (false);
    576 	{ /* Sweep new states. */
    577 	  const HBUSHORT *stop = &states[min_state * num_classes];
    578 	  if (unlikely (stop > states))
    579 	    return_trace (false);
    580 	  for (const HBUSHORT *p = states; stop < p; p--)
    581 	    num_entries = MAX<unsigned int> (num_entries, *(p - 1) + 1);
    582 	  state_neg = min_state;
    583 	}
    584       }
    585 
    586       if (state_pos <= max_state)
    587       {
    588 	/* Positive states. */
    589 	if (unlikely (!c->check_range (states,
    590 				       max_state + 1,
    591 				       row_stride)))
    592 	  return_trace (false);
    593 	if ((c->max_ops -= max_state - state_pos + 1) < 0)
    594 	  return_trace (false);
    595 	{ /* Sweep new states. */
    596 	  if (unlikely (hb_unsigned_mul_overflows ((max_state + 1), num_classes)))
    597 	    return_trace (false);
    598 	  const HBUSHORT *stop = &states[(max_state + 1) * num_classes];
    599 	  if (unlikely (stop < states))
    600 	    return_trace (false);
    601 	  for (const HBUSHORT *p = &states[state_pos * num_classes]; p < stop; p++)
    602 	    num_entries = MAX<unsigned int> (num_entries, *p + 1);
    603 	  state_pos = max_state + 1;
    604 	}
    605       }
    606 
    607       if (unlikely (!c->check_array (entries, num_entries)))
    608 	return_trace (false);
    609       if ((c->max_ops -= num_entries - entry) < 0)
    610 	return_trace (false);
    611       { /* Sweep new entries. */
    612 	const Entry<Extra> *stop = &entries[num_entries];
    613 	for (const Entry<Extra> *p = &entries[entry]; p < stop; p++)
    614 	{
    615 	  int newState = new_state (p->newState);
    616 	  min_state = MIN (min_state, newState);
    617 	  max_state = MAX (max_state, newState);
    618 	}
    619 	entry = num_entries;
    620       }
    621     }
    622 
    623     if (num_entries_out)
    624       *num_entries_out = num_entries;
    625 
    626     return_trace (true);
    627   }
    628 
    629   protected:
    630   HBUINT	nClasses;	/* Number of classes, which is the number of indices
    631 				 * in a single line in the state array. */
    632   OffsetTo<ClassType, HBUINT, false>
    633 		classTable;	/* Offset to the class table. */
    634   OffsetTo<UnsizedArrayOf<HBUSHORT>, HBUINT, false>
    635 		stateArrayTable;/* Offset to the state array. */
    636   OffsetTo<UnsizedArrayOf<Entry<Extra> >, HBUINT, false>
    637 		entryTable;	/* Offset to the entry array. */
    638 
    639   public:
    640   DEFINE_SIZE_STATIC (4 * sizeof (HBUINT));
    641 };
    642 
    643 template <typename HBUCHAR>
    644 struct ClassTable
    645 {
    646   unsigned int get_class (hb_codepoint_t glyph_id, unsigned int outOfRange) const
    647   {
    648     unsigned int i = glyph_id - firstGlyph;
    649     return i >= classArray.len ? outOfRange : classArray.arrayZ[i];
    650   }
    651   unsigned int get_class (hb_codepoint_t glyph_id,
    652 			  unsigned int num_glyphs HB_UNUSED,
    653 			  unsigned int outOfRange) const
    654   {
    655     return get_class (glyph_id, outOfRange);
    656   }
    657   bool sanitize (hb_sanitize_context_t *c) const
    658   {
    659     TRACE_SANITIZE (this);
    660     return_trace (c->check_struct (this) && classArray.sanitize (c));
    661   }
    662   protected:
    663   GlyphID		firstGlyph;	/* First glyph index included in the trimmed array. */
    664   ArrayOf<HBUCHAR>	classArray;	/* The class codes (indexed by glyph index minus
    665 					 * firstGlyph). */
    666   public:
    667   DEFINE_SIZE_ARRAY (4, classArray);
    668 };
    669 
    670 struct ObsoleteTypes
    671 {
    672   enum { extended = false };
    673   typedef HBUINT16 HBUINT;
    674   typedef HBUINT8 HBUSHORT;
    675   typedef ClassTable<HBUINT8> ClassTypeNarrow;
    676   typedef ClassTable<HBUINT16> ClassTypeWide;
    677 
    678   template <typename T>
    679   static unsigned int offsetToIndex (unsigned int offset,
    680 				     const void *base,
    681 				     const T *array)
    682   {
    683     return (offset - ((const char *) array - (const char *) base)) / sizeof (T);
    684   }
    685   template <typename T>
    686   static unsigned int byteOffsetToIndex (unsigned int offset,
    687 					 const void *base,
    688 					 const T *array)
    689   {
    690     return offsetToIndex (offset, base, array);
    691   }
    692   template <typename T>
    693   static unsigned int wordOffsetToIndex (unsigned int offset,
    694 					 const void *base,
    695 					 const T *array)
    696   {
    697     return offsetToIndex (2 * offset, base, array);
    698   }
    699 };
    700 struct ExtendedTypes
    701 {
    702   enum { extended = true };
    703   typedef HBUINT32 HBUINT;
    704   typedef HBUINT16 HBUSHORT;
    705   typedef Lookup<HBUINT16> ClassTypeNarrow;
    706   typedef Lookup<HBUINT16> ClassTypeWide;
    707 
    708   template <typename T>
    709   static unsigned int offsetToIndex (unsigned int offset,
    710 				     const void *base,
    711 				     const T *array)
    712   {
    713     return offset;
    714   }
    715   template <typename T>
    716   static unsigned int byteOffsetToIndex (unsigned int offset,
    717 					 const void *base,
    718 					 const T *array)
    719   {
    720     return offset / 2;
    721   }
    722   template <typename T>
    723   static unsigned int wordOffsetToIndex (unsigned int offset,
    724 					 const void *base,
    725 					 const T *array)
    726   {
    727     return offset;
    728   }
    729 };
    730 
    731 template <typename Types, typename EntryData>
    732 struct StateTableDriver
    733 {
    734   StateTableDriver (const StateTable<Types, EntryData> &machine_,
    735 		    hb_buffer_t *buffer_,
    736 		    hb_face_t *face_) :
    737 	      machine (machine_),
    738 	      buffer (buffer_),
    739 	      num_glyphs (face_->get_num_glyphs ()) {}
    740 
    741   template <typename context_t>
    742   void drive (context_t *c)
    743   {
    744     if (!c->in_place)
    745       buffer->clear_output ();
    746 
    747     int state = StateTable<Types, EntryData>::STATE_START_OF_TEXT;
    748     bool last_was_dont_advance = false;
    749     for (buffer->idx = 0; buffer->successful;)
    750     {
    751       unsigned int klass = buffer->idx < buffer->len ?
    752 			   machine.get_class (buffer->info[buffer->idx].codepoint, num_glyphs) :
    753 			   (unsigned) StateTable<Types, EntryData>::CLASS_END_OF_TEXT;
    754       DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx);
    755       const Entry<EntryData> *entry = machine.get_entryZ (state, klass);
    756       if (unlikely (!entry))
    757 	break;
    758 
    759       /* Unsafe-to-break before this if not in state 0, as things might
    760        * go differently if we start from state 0 here.
    761        *
    762        * Ugh.  The indexing here is ugly... */
    763       if (state && buffer->backtrack_len () && buffer->idx < buffer->len)
    764       {
    765 	/* If there's no action and we're just epsilon-transitioning to state 0,
    766 	 * safe to break. */
    767 	if (c->is_actionable (this, entry) ||
    768 	    !(entry->newState == StateTable<Types, EntryData>::STATE_START_OF_TEXT &&
    769 	      entry->flags == context_t::DontAdvance))
    770 	  buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1);
    771       }
    772 
    773       /* Unsafe-to-break if end-of-text would kick in here. */
    774       if (buffer->idx + 2 <= buffer->len)
    775       {
    776 	const Entry<EntryData> *end_entry = machine.get_entryZ (state, 0);
    777 	if (c->is_actionable (this, end_entry))
    778 	  buffer->unsafe_to_break (buffer->idx, buffer->idx + 2);
    779       }
    780 
    781       if (unlikely (!c->transition (this, entry)))
    782 	break;
    783 
    784       last_was_dont_advance = (entry->flags & context_t::DontAdvance) && buffer->max_ops-- > 0;
    785 
    786       state = machine.new_state (entry->newState);
    787       DEBUG_MSG (APPLY, nullptr, "s%d", state);
    788 
    789       if (buffer->idx == buffer->len)
    790 	break;
    791 
    792       if (!last_was_dont_advance)
    793 	buffer->next_glyph ();
    794     }
    795 
    796     if (!c->in_place)
    797     {
    798       for (; buffer->successful && buffer->idx < buffer->len;)
    799 	buffer->next_glyph ();
    800       buffer->swap_buffers ();
    801     }
    802   }
    803 
    804   public:
    805   const StateTable<Types, EntryData> &machine;
    806   hb_buffer_t *buffer;
    807   unsigned int num_glyphs;
    808 };
    809 
    810 
    811 struct ankr;
    812 
    813 struct hb_aat_apply_context_t :
    814        hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY>
    815 {
    816   const char *get_name () { return "APPLY"; }
    817   template <typename T>
    818   return_t dispatch (const T &obj) { return obj.apply (this); }
    819   static return_t default_return_value () { return false; }
    820   bool stop_sublookup_iteration (return_t r) const { return r; }
    821 
    822   const hb_ot_shape_plan_t *plan;
    823   hb_font_t *font;
    824   hb_face_t *face;
    825   hb_buffer_t *buffer;
    826   hb_sanitize_context_t sanitizer;
    827   const ankr *ankr_table;
    828   const char *ankr_end;
    829 
    830   /* Unused. For debug tracing only. */
    831   unsigned int lookup_index;
    832   unsigned int debug_depth;
    833 
    834   HB_INTERNAL hb_aat_apply_context_t (const hb_ot_shape_plan_t *plan_,
    835 				      hb_font_t *font_,
    836 				      hb_buffer_t *buffer_,
    837 				      hb_blob_t *blob = const_cast<hb_blob_t *> (&Null(hb_blob_t)));
    838 
    839   HB_INTERNAL ~hb_aat_apply_context_t ();
    840 
    841   HB_INTERNAL void set_ankr_table (const AAT::ankr *ankr_table_, const char *ankr_end_);
    842 
    843   void set_lookup_index (unsigned int i) { lookup_index = i; }
    844 };
    845 
    846 
    847 } /* namespace AAT */
    848 
    849 
    850 #endif /* HB_AAT_LAYOUT_COMMON_HH */
    851