7c0dfa8b0cf2bbd3c3a7e49590d53e68082196f2
[platform/upstream/harfbuzz.git] / src / hb-aat-layout-common-private.hh
1 /*
2  * Copyright © 2017  Google, Inc.
3  *
4  *  This is part of HarfBuzz, a text shaping library.
5  *
6  * Permission is hereby granted, without written agreement and without
7  * license or royalty fees, to use, copy, modify, and distribute this
8  * software and its documentation for any purpose, provided that the
9  * above copyright notice and the following two paragraphs appear in
10  * all copies of this software.
11  *
12  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16  * DAMAGE.
17  *
18  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
21  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23  *
24  * Google Author(s): Behdad Esfahbod
25  */
26
27 #ifndef HB_AAT_LAYOUT_COMMON_PRIVATE_HH
28 #define HB_AAT_LAYOUT_COMMON_PRIVATE_HH
29
30 #include "hb-aat-layout-private.hh"
31
32
33 namespace AAT {
34
35 using namespace OT;
36
37
38 /*
39  * Binary Searching Tables
40  */
41
42 struct BinSearchHeader
43 {
44
45   inline bool sanitize (hb_sanitize_context_t *c) const
46   {
47     TRACE_SANITIZE (this);
48     return_trace (c->check_struct (this));
49   }
50
51   HBUINT16      unitSize;       /* Size of a lookup unit for this search in bytes. */
52   HBUINT16      nUnits;         /* Number of units of the preceding size to be searched. */
53   HBUINT16      searchRange;    /* The value of unitSize times the largest power of 2
54                                  * that is less than or equal to the value of nUnits. */
55   HBUINT16      entrySelector;  /* The log base 2 of the largest power of 2 less than
56                                  * or equal to the value of nUnits. */
57   HBUINT16      rangeShift;     /* The value of unitSize times the difference of the
58                                  * value of nUnits minus the largest power of 2 less
59                                  * than or equal to the value of nUnits. */
60   public:
61   DEFINE_SIZE_STATIC (10);
62 };
63
64 template <typename Type>
65 struct BinSearchArrayOf
66 {
67   inline const Type& operator [] (unsigned int i) const
68   {
69     if (unlikely (i >= header.nUnits)) return Null(Type);
70     return StructAtOffset<Type> (bytes, i * header.unitSize);
71   }
72   inline Type& operator [] (unsigned int i)
73   {
74     return StructAtOffset<Type> (bytes, i * header.unitSize);
75   }
76   inline unsigned int get_size (void) const
77   { return header.static_size + header.nUnits * header.unitSize; }
78
79   inline bool sanitize (hb_sanitize_context_t *c) const
80   {
81     TRACE_SANITIZE (this);
82     if (unlikely (!sanitize_shallow (c))) return_trace (false);
83
84     /* Note: for structs that do not reference other structs,
85      * we do not need to call their sanitize() as we already did
86      * a bound check on the aggregate array size.  We just include
87      * a small unreachable expression to make sure the structs
88      * pointed to do have a simple sanitize(), ie. they do not
89      * reference other structs via offsets.
90      */
91     (void) (false && StructAtOffset<Type> (bytes, 0).sanitize (c));
92
93     return_trace (true);
94   }
95   inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
96   {
97     TRACE_SANITIZE (this);
98     if (unlikely (!sanitize_shallow (c))) return_trace (false);
99     unsigned int count = header.nUnits;
100     for (unsigned int i = 0; i < count; i++)
101       if (unlikely (!(*this)[i].sanitize (c, base)))
102         return_trace (false);
103     return_trace (true);
104   }
105
106   template <typename T>
107   inline const Type *bsearch (const T &key) const
108   {
109     unsigned int size = header.unitSize;
110     int min = 0, max = (int) header.nUnits - 1;
111     while (min <= max)
112     {
113       int mid = (min + max) / 2;
114       const Type *p = (const Type *) (((const char *) bytes) + (mid * size));
115       int c = p->cmp (key);
116       if (c < 0)
117         max = mid - 1;
118       else if (c > 0)
119         min = mid + 1;
120       else
121         return p;
122     }
123     return nullptr;
124   }
125
126   private:
127   inline bool sanitize_shallow (hb_sanitize_context_t *c) const
128   {
129     TRACE_SANITIZE (this);
130     return_trace (header.sanitize (c) &&
131                   Type::static_size >= header.unitSize &&
132                   c->check_array (bytes, header.unitSize, header.nUnits));
133   }
134
135   protected:
136   BinSearchHeader       header;
137   HBUINT8                       bytes[VAR];
138   public:
139   DEFINE_SIZE_ARRAY (10, bytes);
140 };
141
142
143 /* TODO Move this to hb-open-type-private.hh and use it in ArrayOf, HeadlessArrayOf,
144  * and other places around the code base?? */
145 template <typename Type>
146 struct UnsizedArrayOf
147 {
148   inline const Type& operator [] (unsigned int i) const { return arrayZ[i]; }
149   inline Type& operator [] (unsigned int i) { return arrayZ[i]; }
150
151   inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
152   {
153     TRACE_SANITIZE (this);
154     if (unlikely (!sanitize_shallow (c, count))) return_trace (false);
155
156     /* Note: for structs that do not reference other structs,
157      * we do not need to call their sanitize() as we already did
158      * a bound check on the aggregate array size.  We just include
159      * a small unreachable expression to make sure the structs
160      * pointed to do have a simple sanitize(), ie. they do not
161      * reference other structs via offsets.
162      */
163     (void) (false && arrayZ[0].sanitize (c));
164
165     return_trace (true);
166   }
167   inline bool sanitize (hb_sanitize_context_t *c, unsigned int count, const void *base) const
168   {
169     TRACE_SANITIZE (this);
170     if (unlikely (!sanitize_shallow (c, count))) return_trace (false);
171     for (unsigned int i = 0; i < count; i++)
172       if (unlikely (!arrayZ[i].sanitize (c, base)))
173         return_trace (false);
174     return_trace (true);
175   }
176   template <typename T>
177   inline bool sanitize (hb_sanitize_context_t *c, unsigned int count, const void *base, T user_data) const
178   {
179     TRACE_SANITIZE (this);
180     if (unlikely (!sanitize_shallow (c, count))) return_trace (false);
181     for (unsigned int i = 0; i < count; i++)
182       if (unlikely (!arrayZ[i].sanitize (c, base, user_data)))
183         return_trace (false);
184     return_trace (true);
185   }
186
187   private:
188   inline bool sanitize_shallow (hb_sanitize_context_t *c, unsigned int count) const
189   {
190     TRACE_SANITIZE (this);
191     return_trace (c->check_array (arrayZ, arrayZ[0].static_size, count));
192   }
193
194   public:
195   Type  arrayZ[VAR];
196   public:
197   DEFINE_SIZE_ARRAY (0, arrayZ);
198 };
199
200 /* Unsized array of offset's */
201 template <typename Type, typename OffsetType>
202 struct UnsizedOffsetArrayOf : UnsizedArrayOf<OffsetTo<Type, OffsetType> > {};
203
204 /* Unsized array of offsets relative to the beginning of the array itself. */
205 template <typename Type, typename OffsetType>
206 struct UnsizedOffsetListOf : UnsizedOffsetArrayOf<Type, OffsetType>
207 {
208   inline const Type& operator [] (unsigned int i) const
209   {
210     return this+this->arrayZ[i];
211   }
212
213   inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
214   {
215     TRACE_SANITIZE (this);
216     return_trace ((UnsizedOffsetArrayOf<Type, OffsetType>::sanitize (c, count, this)));
217   }
218   template <typename T>
219   inline bool sanitize (hb_sanitize_context_t *c, unsigned int count, T user_data) const
220   {
221     TRACE_SANITIZE (this);
222     return_trace ((UnsizedOffsetArrayOf<Type, OffsetType>::sanitize (c, count, this, user_data)));
223   }
224 };
225
226
227 /*
228  * Lookup Table
229  */
230
231 template <typename T> struct Lookup;
232
233 template <typename T>
234 struct LookupFormat0
235 {
236   friend struct Lookup<T>;
237
238   private:
239   inline const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
240   {
241     if (unlikely (glyph_id >= num_glyphs)) return nullptr;
242     return &arrayZ[glyph_id];
243   }
244
245   inline bool sanitize (hb_sanitize_context_t *c) const
246   {
247     TRACE_SANITIZE (this);
248     return_trace (arrayZ.sanitize (c, c->num_glyphs));
249   }
250
251   protected:
252   HBUINT16      format;         /* Format identifier--format = 0 */
253   UnsizedArrayOf<T>
254                 arrayZ;         /* Array of lookup values, indexed by glyph index. */
255   public:
256   DEFINE_SIZE_ARRAY (2, arrayZ);
257 };
258
259
260 template <typename T>
261 struct LookupSegmentSingle
262 {
263   inline int cmp (hb_codepoint_t g) const {
264     return g < first ? -1 : g <= last ? 0 : +1 ;
265   }
266
267   inline bool sanitize (hb_sanitize_context_t *c) const
268   {
269     TRACE_SANITIZE (this);
270     return_trace (c->check_struct (this) && value.sanitize (c));
271   }
272
273   GlyphID       last;           /* Last GlyphID in this segment */
274   GlyphID       first;          /* First GlyphID in this segment */
275   T             value;          /* The lookup value (only one) */
276   public:
277   DEFINE_SIZE_STATIC (4 + T::static_size);
278 };
279
280 template <typename T>
281 struct LookupFormat2
282 {
283   friend struct Lookup<T>;
284
285   private:
286   inline const T* get_value (hb_codepoint_t glyph_id) const
287   {
288     const LookupSegmentSingle<T> *v = segments.bsearch (glyph_id);
289     return v ? &v->value : nullptr;
290   }
291
292   inline bool sanitize (hb_sanitize_context_t *c) const
293   {
294     TRACE_SANITIZE (this);
295     return_trace (segments.sanitize (c));
296   }
297
298   protected:
299   HBUINT16      format;         /* Format identifier--format = 2 */
300   BinSearchArrayOf<LookupSegmentSingle<T> >
301                 segments;       /* The actual segments. These must already be sorted,
302                                  * according to the first word in each one (the last
303                                  * glyph in each segment). */
304   public:
305   DEFINE_SIZE_ARRAY (8, segments);
306 };
307
308 template <typename T>
309 struct LookupSegmentArray
310 {
311   inline const T* get_value (hb_codepoint_t glyph_id, const void *base) const
312   {
313     return first <= glyph_id && glyph_id <= last ? &(base+valuesZ)[glyph_id - first] : nullptr;
314   }
315
316   inline int cmp (hb_codepoint_t g) const {
317     return g < first ? -1 : g <= last ? 0 : +1 ;
318   }
319
320   inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
321   {
322     TRACE_SANITIZE (this);
323     return_trace (c->check_struct (this) &&
324                   first <= last &&
325                   valuesZ.sanitize (c, base, last - first + 1));
326   }
327
328   GlyphID       last;           /* Last GlyphID in this segment */
329   GlyphID       first;          /* First GlyphID in this segment */
330   OffsetTo<UnsizedArrayOf<T> >
331                 valuesZ;        /* A 16-bit offset from the start of
332                                  * the table to the data. */
333   public:
334   DEFINE_SIZE_STATIC (6);
335 };
336
337 template <typename T>
338 struct LookupFormat4
339 {
340   friend struct Lookup<T>;
341
342   private:
343   inline const T* get_value (hb_codepoint_t glyph_id) const
344   {
345     const LookupSegmentArray<T> *v = segments.bsearch (glyph_id);
346     return v ? v->get_value (glyph_id, this) : nullptr;
347   }
348
349   inline bool sanitize (hb_sanitize_context_t *c) const
350   {
351     TRACE_SANITIZE (this);
352     return_trace (segments.sanitize (c, this));
353   }
354
355   protected:
356   HBUINT16      format;         /* Format identifier--format = 2 */
357   BinSearchArrayOf<LookupSegmentArray<T> >
358                 segments;       /* The actual segments. These must already be sorted,
359                                  * according to the first word in each one (the last
360                                  * glyph in each segment). */
361   public:
362   DEFINE_SIZE_ARRAY (8, segments);
363 };
364
365 template <typename T>
366 struct LookupSingle
367 {
368   inline int cmp (hb_codepoint_t g) const { return glyph.cmp (g); }
369
370   inline bool sanitize (hb_sanitize_context_t *c) const
371   {
372     TRACE_SANITIZE (this);
373     return_trace (c->check_struct (this) && value.sanitize (c));
374   }
375
376   GlyphID       glyph;          /* Last GlyphID */
377   T             value;          /* The lookup value (only one) */
378   public:
379   DEFINE_SIZE_STATIC (4 + T::static_size);
380 };
381
382 template <typename T>
383 struct LookupFormat6
384 {
385   friend struct Lookup<T>;
386
387   private:
388   inline const T* get_value (hb_codepoint_t glyph_id) const
389   {
390     const LookupSingle<T> *v = entries.bsearch (glyph_id);
391     return v ? &v->value : nullptr;
392   }
393
394   inline bool sanitize (hb_sanitize_context_t *c) const
395   {
396     TRACE_SANITIZE (this);
397     return_trace (entries.sanitize (c));
398   }
399
400   protected:
401   HBUINT16      format;         /* Format identifier--format = 6 */
402   BinSearchArrayOf<LookupSingle<T> >
403                 entries;        /* The actual entries, sorted by glyph index. */
404   public:
405   DEFINE_SIZE_ARRAY (8, entries);
406 };
407
408 template <typename T>
409 struct LookupFormat8
410 {
411   friend struct Lookup<T>;
412
413   private:
414   inline const T* get_value (hb_codepoint_t glyph_id) const
415   {
416     return firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount ? &valueArrayZ[glyph_id - firstGlyph] : nullptr;
417   }
418
419   inline bool sanitize (hb_sanitize_context_t *c) const
420   {
421     TRACE_SANITIZE (this);
422     return_trace (c->check_struct (this) && valueArrayZ.sanitize (c, glyphCount));
423   }
424
425   protected:
426   HBUINT16      format;         /* Format identifier--format = 6 */
427   GlyphID       firstGlyph;     /* First glyph index included in the trimmed array. */
428   HBUINT16      glyphCount;     /* Total number of glyphs (equivalent to the last
429                                  * glyph minus the value of firstGlyph plus 1). */
430   UnsizedArrayOf<T>
431                 valueArrayZ;    /* The lookup values (indexed by the glyph index
432                                  * minus the value of firstGlyph). */
433   public:
434   DEFINE_SIZE_ARRAY (6, valueArrayZ);
435 };
436
437 template <typename T>
438 struct Lookup
439 {
440   inline const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
441   {
442     switch (u.format) {
443     case 0: return u.format0.get_value (glyph_id, num_glyphs);
444     case 2: return u.format2.get_value (glyph_id);
445     case 4: return u.format4.get_value (glyph_id);
446     case 6: return u.format6.get_value (glyph_id);
447     case 8: return u.format8.get_value (glyph_id);
448     default:return nullptr;
449     }
450   }
451
452   inline bool sanitize (hb_sanitize_context_t *c) const
453   {
454     TRACE_SANITIZE (this);
455     if (!u.format.sanitize (c)) return_trace (false);
456     switch (u.format) {
457     case 0: return_trace (u.format0.sanitize (c));
458     case 2: return_trace (u.format2.sanitize (c));
459     case 4: return_trace (u.format4.sanitize (c));
460     case 6: return_trace (u.format6.sanitize (c));
461     case 8: return_trace (u.format8.sanitize (c));
462     default:return_trace (true);
463     }
464   }
465
466   protected:
467   union {
468   HBUINT16              format;         /* Format identifier */
469   LookupFormat0<T>      format0;
470   LookupFormat2<T>      format2;
471   LookupFormat4<T>      format4;
472   LookupFormat6<T>      format6;
473   LookupFormat8<T>      format8;
474   } u;
475   public:
476   DEFINE_SIZE_UNION (2, format);
477 };
478
479
480 /*
481  * Extended State Table
482  */
483
484 template <typename T>
485 struct Entry
486 {
487   inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
488   {
489     TRACE_SANITIZE (this);
490     /* Note, we don't recurse-sanitize data because we don't access it.
491      * That said, in our DEFINE_SIZE_STATIC we access T::static_size,
492      * which ensures that data has a simple sanitize(). To be determined
493      * if I need to remove that as well. */
494     return_trace (c->check_struct (this));
495   }
496
497   public:
498   HBUINT16      newState;       /* Byte offset from beginning of state table
499                                  * to the new state. Really?!?! Or just state
500                                  * number?  The latter in morx for sure. */
501   HBUINT16      flags;          /* Table specific. */
502   T             data;           /* Optional offsets to per-glyph tables. */
503   public:
504   DEFINE_SIZE_STATIC (4 + T::static_size);
505 };
506
507 template <>
508 struct Entry<void>
509 {
510   inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
511   {
512     TRACE_SANITIZE (this);
513     return_trace (c->check_struct (this));
514   }
515
516   public:
517   HBUINT16      newState;       /* Byte offset from beginning of state table to the new state. */
518   HBUINT16      flags;          /* Table specific. */
519   public:
520   DEFINE_SIZE_STATIC (4);
521 };
522
523 template <typename Extra>
524 struct StateTable
525 {
526   inline unsigned int get_class (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
527   {
528     const HBUINT16 *v = (this+classTable).get_value (glyph_id, num_glyphs);
529     return v ? *v : 1;
530   }
531
532   inline const Entry<Extra> *get_entries () const
533   {
534     return (this+entryTable).arrayZ;
535   }
536
537   inline const Entry<Extra> *get_entryZ (unsigned int state, unsigned int klass) const
538   {
539     if (unlikely (klass >= nClasses)) return nullptr;
540
541     const HBUINT16 *states = (this+stateArrayTable).arrayZ;
542     const Entry<Extra> *entries = (this+entryTable).arrayZ;
543
544     unsigned int entry = states[state * nClasses + klass];
545
546     return &entries[entry];
547   }
548
549   inline bool sanitize (hb_sanitize_context_t *c,
550                         unsigned int *num_entries_out = nullptr) const
551   {
552     TRACE_SANITIZE (this);
553     if (unlikely (!(c->check_struct (this) &&
554                     classTable.sanitize (c, this)))) return_trace (false);
555
556     const HBUINT16 *states = (this+stateArrayTable).arrayZ;
557     const Entry<Extra> *entries = (this+entryTable).arrayZ;
558
559     unsigned int num_states = 1;
560     unsigned int num_entries = 0;
561
562     unsigned int state = 0;
563     unsigned int entry = 0;
564     while (state < num_states)
565     {
566       if (unlikely (!c->check_array (states,
567                                      states[0].static_size * nClasses,
568                                      num_states)))
569         return_trace (false);
570       { /* Sweep new states. */
571         const HBUINT16 *stop = &states[num_states * nClasses];
572         for (const HBUINT16 *p = &states[state * nClasses]; p < stop; p++)
573           num_entries = MAX<unsigned int> (num_entries, *p + 1);
574         state = num_states;
575       }
576
577       if (unlikely (!c->check_array (entries,
578                                      entries[0].static_size,
579                                      num_entries)))
580         return_trace (false);
581       { /* Sweep new entries. */
582         const Entry<Extra> *stop = &entries[num_entries];
583         for (const Entry<Extra> *p = &entries[entry]; p < stop; p++)
584           num_states = MAX<unsigned int> (num_states, p->newState + 1);
585         entry = num_entries;
586       }
587     }
588
589     if (num_entries_out)
590       *num_entries_out = num_entries;
591
592     return_trace (true);
593   }
594
595   protected:
596   HBUINT32      nClasses;       /* Number of classes, which is the number of indices
597                                  * in a single line in the state array. */
598   OffsetTo<Lookup<HBUINT16>, HBUINT32>
599                 classTable;     /* Offset to the class table. */
600   OffsetTo<UnsizedArrayOf<HBUINT16>, HBUINT32>
601                 stateArrayTable;/* Offset to the state array. */
602   OffsetTo<UnsizedArrayOf<Entry<Extra> >, HBUINT32>
603                 entryTable;     /* Offset to the entry array. */
604
605   public:
606   DEFINE_SIZE_STATIC (16);
607 };
608
609 template <typename EntryData>
610 struct StateTableDriver
611 {
612   inline StateTableDriver (const StateTable<EntryData> &machine_,
613                            hb_buffer_t *buffer_,
614                            hb_face_t *face_) :
615               machine (machine_),
616               buffer (buffer_),
617               num_glyphs (face_->get_num_glyphs ()) {}
618
619   template <typename context_t>
620   inline void drive (context_t *c)
621   {
622     hb_glyph_info_t *info = buffer->info;
623
624     if (!c->in_place)
625       buffer->clear_output ();
626
627     unsigned int state = 0;
628     bool last_was_dont_advance = false;
629     for (buffer->idx = 0;;)
630     {
631       unsigned int klass = buffer->idx < buffer->len ?
632                            machine.get_class (info[buffer->idx].codepoint, num_glyphs) :
633                            0 /* End of text */;
634       const Entry<EntryData> *entry = machine.get_entryZ (state, klass);
635       if (unlikely (!entry))
636         break;
637
638       /* Unsafe-to-break before this if not in state 0, as things might
639        * go differently if we start from state 0 here. */
640       if (state && buffer->idx)
641       {
642         /* If there's no action and we're just epsilon-transitioning to state 0,
643          * safe to break. */
644         if (c->is_actionable (this, entry) ||
645             !(entry->newState == 0 && entry->flags == context_t::DontAdvance))
646           buffer->unsafe_to_break (buffer->idx - 1, buffer->idx + 1);
647       }
648
649       /* Unsafe-to-break if end-of-text would kick in here. */
650       if (buffer->idx + 2 <= buffer->len)
651       {
652         const Entry<EntryData> *end_entry = machine.get_entryZ (state, 0);
653         if (c->is_actionable (this, end_entry))
654           buffer->unsafe_to_break (buffer->idx, buffer->idx + 2);
655       }
656
657       if (unlikely (!c->transition (this, entry)))
658         break;
659
660       last_was_dont_advance = (entry->flags & context_t::DontAdvance) && buffer->max_ops-- > 0;
661
662       state = entry->newState;
663
664       if (buffer->idx == buffer->len)
665         break;
666
667       if (!last_was_dont_advance)
668         buffer->next_glyph ();
669     }
670
671     if (!c->in_place)
672     {
673       for (; buffer->idx < buffer->len;)
674         buffer->next_glyph ();
675       buffer->swap_buffers ();
676     }
677   }
678
679   public:
680   const StateTable<EntryData> &machine;
681   hb_buffer_t *buffer;
682   unsigned int num_glyphs;
683 };
684
685
686
687 struct hb_aat_apply_context_t :
688        hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY>
689 {
690   inline const char *get_name (void) { return "APPLY"; }
691   template <typename T>
692   inline return_t dispatch (const T &obj) { return obj.apply (this); }
693   static return_t default_return_value (void) { return false; }
694   bool stop_sublookup_iteration (return_t r) const { return r; }
695
696   hb_font_t *font;
697   hb_face_t *face;
698   hb_buffer_t *buffer;
699   hb_sanitize_context_t sanitizer;
700
701   /* Unused. For debug tracing only. */
702   unsigned int lookup_index;
703   unsigned int debug_depth;
704
705   inline hb_aat_apply_context_t (hb_font_t *font_,
706                                  hb_buffer_t *buffer_,
707                                  hb_blob_t *table) :
708                 font (font_), face (font->face), buffer (buffer_),
709                 sanitizer (), lookup_index (0), debug_depth (0)
710   {
711     sanitizer.init (table);
712     sanitizer.num_glyphs = face->get_num_glyphs ();
713     sanitizer.start_processing ();
714   }
715
716   inline void set_lookup_index (unsigned int i) { lookup_index = i; }
717
718   inline ~hb_aat_apply_context_t (void)
719   {
720     sanitizer.end_processing ();
721   }
722 };
723
724
725 } /* namespace AAT */
726
727
728 #endif /* HB_AAT_LAYOUT_COMMON_PRIVATE_HH */