blob: b1165e9bf143f86ccb7c30363862523c7a94cb38 [file] [log] [blame]
Behdad Esfahboda0175e72017-08-17 16:55:54 -07001/*
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
33namespace AAT {
34
35using namespace OT;
36
37
38/*
39 * Binary Searching Tables
40 */
41
42struct BinSearchHeader
43{
Behdad Esfahboda0175e72017-08-17 16:55:54 -070044
45 inline bool sanitize (hb_sanitize_context_t *c) const
46 {
47 TRACE_SANITIZE (this);
48 return_trace (c->check_struct (this));
49 }
50
Behdad Esfahbod6b191782018-01-10 03:07:30 +010051 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
Behdad Esfahboda0175e72017-08-17 16:55:54 -070054 * that is less than or equal to the value of nUnits. */
Behdad Esfahbod6b191782018-01-10 03:07:30 +010055 HBUINT16 entrySelector; /* The log base 2 of the largest power of 2 less than
Behdad Esfahboda0175e72017-08-17 16:55:54 -070056 * or equal to the value of nUnits. */
Behdad Esfahbod6b191782018-01-10 03:07:30 +010057 HBUINT16 rangeShift; /* The value of unitSize times the difference of the
Behdad Esfahboda0175e72017-08-17 16:55:54 -070058 * 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
64template <typename Type>
65struct 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>
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100107 inline const Type *bsearch (const T &key) const
Behdad Esfahboda0175e72017-08-17 16:55:54 -0700108 {
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100109 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 NULL;
Behdad Esfahboda0175e72017-08-17 16:55:54 -0700124 }
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;
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100137 HBUINT8 bytes[VAR];
Behdad Esfahboda0175e72017-08-17 16:55:54 -0700138 public:
139 DEFINE_SIZE_ARRAY (10, bytes);
140};
141
142
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100143/* TODO Move this to hb-open-type-private.hh and use it in ArrayOf, HeadlessArrayOf,
144 * and other places around the code base?? */
145template <typename Type>
146struct 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);
Behdad Esfahbod335a9c12018-01-11 14:50:47 +0100154 if (unlikely (!sanitize_shallow (c, count))) return_trace (false);
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100155
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 */
Behdad Esfahbod335a9c12018-01-11 14:50:47 +0100163 (void) (false && arrayZ[0].sanitize (c));
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100164
Behdad Esfahbod335a9c12018-01-11 14:50:47 +0100165 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);
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100191 return_trace (c->check_array (arrayZ, arrayZ[0].static_size, count));
192 }
193
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100194 public:
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100195 Type arrayZ[VAR];
196 public:
197 DEFINE_SIZE_ARRAY (0, arrayZ);
198};
199
Behdad Esfahbod335a9c12018-01-11 14:50:47 +0100200/* Unsized array of offset's */
201template <typename Type, typename OffsetType>
202struct UnsizedOffsetArrayOf : UnsizedArrayOf<OffsetTo<Type, OffsetType> > {};
203
204/* Unsized array of offsets relative to the beginning of the array itself. */
205template <typename Type, typename OffsetType>
206struct 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
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100226
227/*
228 * Lookup Table
229 */
230
231template <typename T> struct Lookup;
232
233template <typename T>
234struct LookupFormat0
235{
236 friend struct Lookup<T>;
237
238 private:
Behdad Esfahbod748b9892018-01-09 17:55:17 +0100239 inline const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100240 {
Behdad Esfahbod748b9892018-01-09 17:55:17 +0100241 if (unlikely (glyph_id >= num_glyphs)) return nullptr;
242 return &arrayZ[glyph_id];
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100243 }
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:
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100252 HBUINT16 format; /* Format identifier--format = 0 */
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100253 UnsizedArrayOf<T>
254 arrayZ; /* Array of lookup values, indexed by glyph index. */
255 public:
256 DEFINE_SIZE_ARRAY (2, arrayZ);
257};
258
259
260template <typename T>
261struct 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:
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100277 DEFINE_SIZE_STATIC (4 + T::static_size);
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100278};
279
280template <typename T>
281struct LookupFormat2
282{
283 friend struct Lookup<T>;
284
285 private:
Behdad Esfahbod748b9892018-01-09 17:55:17 +0100286 inline const T* get_value (hb_codepoint_t glyph_id) const
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100287 {
288 const LookupSegmentSingle<T> *v = segments.bsearch (glyph_id);
Behdad Esfahbod748b9892018-01-09 17:55:17 +0100289 return v ? &v->value : nullptr;
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100290 }
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:
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100299 HBUINT16 format; /* Format identifier--format = 2 */
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100300 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
308template <typename T>
309struct LookupSegmentArray
310{
Behdad Esfahbod748b9892018-01-09 17:55:17 +0100311 inline const T* get_value (hb_codepoint_t glyph_id, const void *base) const
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100312 {
Behdad Esfahbod748b9892018-01-09 17:55:17 +0100313 return first <= glyph_id && glyph_id <= last ? &(base+valuesZ)[glyph_id - first] : nullptr;
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100314 }
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
337template <typename T>
338struct LookupFormat4
339{
340 friend struct Lookup<T>;
341
342 private:
Behdad Esfahbod748b9892018-01-09 17:55:17 +0100343 inline const T* get_value (hb_codepoint_t glyph_id) const
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100344 {
345 const LookupSegmentArray<T> *v = segments.bsearch (glyph_id);
Behdad Esfahbod748b9892018-01-09 17:55:17 +0100346 return v ? v->get_value (glyph_id, this) : nullptr;
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100347 }
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:
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100356 HBUINT16 format; /* Format identifier--format = 2 */
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100357 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
365template <typename T>
366struct 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:
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100379 DEFINE_SIZE_STATIC (4 + T::static_size);
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100380};
381
382template <typename T>
383struct LookupFormat6
384{
385 friend struct Lookup<T>;
386
387 private:
Behdad Esfahbod748b9892018-01-09 17:55:17 +0100388 inline const T* get_value (hb_codepoint_t glyph_id) const
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100389 {
390 const LookupSingle<T> *v = entries.bsearch (glyph_id);
Behdad Esfahbod748b9892018-01-09 17:55:17 +0100391 return v ? &v->value : nullptr;
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100392 }
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:
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100401 HBUINT16 format; /* Format identifier--format = 6 */
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100402 BinSearchArrayOf<LookupSingle<T> >
403 entries; /* The actual entries, sorted by glyph index. */
404 public:
405 DEFINE_SIZE_ARRAY (8, entries);
406};
407
408template <typename T>
409struct LookupFormat8
410{
411 friend struct Lookup<T>;
412
413 private:
Behdad Esfahbod748b9892018-01-09 17:55:17 +0100414 inline const T* get_value (hb_codepoint_t glyph_id) const
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100415 {
Behdad Esfahbod748b9892018-01-09 17:55:17 +0100416 return firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount ? &valueArrayZ[glyph_id - firstGlyph] : nullptr;
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100417 }
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:
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100426 HBUINT16 format; /* Format identifier--format = 6 */
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100427 GlyphID firstGlyph; /* First glyph index included in the trimmed array. */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100428 HBUINT16 glyphCount; /* Total number of glyphs (equivalent to the last
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100429 * 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
437template <typename T>
438struct Lookup
439{
Behdad Esfahbod748b9892018-01-09 17:55:17 +0100440 inline const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100441 {
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);
Behdad Esfahbod748b9892018-01-09 17:55:17 +0100448 default:return nullptr;
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100449 }
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 {
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100468 HBUINT16 format; /* Format identifier */
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100469 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
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100479
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100480/*
Behdad Esfahbod1f1c85a2018-01-11 22:43:57 +0100481 * Extended State Table
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100482 */
483
484template <typename T>
485struct Entry
486{
487 inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
488 {
489 TRACE_SANITIZE (this);
Behdad Esfahbod17f01af2018-01-11 18:54:49 +0100490 /* 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));
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100495 }
496
497 public:
Behdad Esfahbod17f01af2018-01-11 18:54:49 +0100498 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. */
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100501 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
507template <>
508struct 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
Behdad Esfahbod1f1c85a2018-01-11 22:43:57 +0100523template <typename Extra>
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100524struct StateTable
525{
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100526 inline unsigned int get_class (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
Behdad Esfahbod1f1c85a2018-01-11 22:43:57 +0100527 {
528 const HBUINT16 *v = (this+classTable).get_value (glyph_id, num_glyphs);
529 return v ? *v : 1;
530 }
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100531
Behdad Esfahbod17f01af2018-01-11 18:54:49 +0100532 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
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100538 {
Behdad Esfahbod680cbc22018-01-11 18:15:53 +0100539 if (unlikely (klass >= nClasses)) return nullptr;
540
Behdad Esfahbod1f1c85a2018-01-11 22:43:57 +0100541 const HBUINT16 *states = (this+stateArrayTable).arrayZ;
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100542 const Entry<Extra> *entries = (this+entryTable).arrayZ;
543
Behdad Esfahbod680cbc22018-01-11 18:15:53 +0100544 unsigned int entry = states[state * nClasses + klass];
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100545
Behdad Esfahbod680cbc22018-01-11 18:15:53 +0100546 return &entries[entry];
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100547 }
548
Behdad Esfahbod17f01af2018-01-11 18:54:49 +0100549 inline bool sanitize (hb_sanitize_context_t *c,
550 unsigned int *num_entries_out = nullptr) const
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100551 {
552 TRACE_SANITIZE (this);
Behdad Esfahbod12fffce2018-01-15 15:41:51 -0500553 if (unlikely (!(c->check_struct (this) &&
554 classTable.sanitize (c, this)))) return_trace (false);
Behdad Esfahbod680cbc22018-01-11 18:15:53 +0100555
Behdad Esfahbod1f1c85a2018-01-11 22:43:57 +0100556 const HBUINT16 *states = (this+stateArrayTable).arrayZ;
Behdad Esfahbod680cbc22018-01-11 18:15:53 +0100557 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 + state * nClasses,
567 states[0].static_size,
568 nClasses * (num_states - state))))
569 return_trace (false);
570 { /* Sweep new states. */
Behdad Esfahbod1f1c85a2018-01-11 22:43:57 +0100571 const HBUINT16 *stop = &states[num_states * nClasses];
572 for (const HBUINT16 *p = &states[state * nClasses]; p < stop; p++)
Behdad Esfahbod680cbc22018-01-11 18:15:53 +0100573 num_entries = MAX<unsigned int> (num_entries, *p + 1);
574 state = num_states;
575 }
576
577 if (unlikely (!c->check_array (entries + entry,
578 entries[0].static_size,
579 num_entries - entry)))
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
Behdad Esfahbod17f01af2018-01-11 18:54:49 +0100589 if (num_entries_out)
590 *num_entries_out = num_entries;
591
Behdad Esfahbod680cbc22018-01-11 18:15:53 +0100592 return_trace (true);
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100593 }
594
595 protected:
Behdad Esfahbod1f1c85a2018-01-11 22:43:57 +0100596 HBUINT32 nClasses; /* Number of classes, which is the number of indices
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100597 * in a single line in the state array. */
Behdad Esfahbod1f1c85a2018-01-11 22:43:57 +0100598 OffsetTo<Lookup<HBUINT16>, HBUINT32>
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100599 classTable; /* Offset to the class table. */
Behdad Esfahbod1f1c85a2018-01-11 22:43:57 +0100600 OffsetTo<UnsizedArrayOf<HBUINT16>, HBUINT32>
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100601 stateArrayTable;/* Offset to the state array. */
Behdad Esfahbod1f1c85a2018-01-11 22:43:57 +0100602 OffsetTo<UnsizedArrayOf<Entry<Extra> >, HBUINT32>
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100603 entryTable; /* Offset to the entry array. */
604
605 public:
Behdad Esfahbod9009b342018-01-12 12:04:53 +0100606 DEFINE_SIZE_STATIC (16);
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100607};
608
Behdad Esfahbod117cfe72018-01-12 00:01:36 +0100609template <typename EntryData>
610struct 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 ()),
Behdad Esfahbod461a6052018-01-17 10:02:48 -0800618 last_zero (0),
619 dont_advance_set (nullptr) {}
Behdad Esfahbodf7600222018-01-12 11:09:21 +0100620
621 inline ~StateTableDriver (void)
622 {
Behdad Esfahbod461a6052018-01-17 10:02:48 -0800623 hb_set_destroy (dont_advance_set);
Behdad Esfahbodf7600222018-01-12 11:09:21 +0100624 }
Behdad Esfahbod117cfe72018-01-12 00:01:36 +0100625
626 template <typename context_t>
627 inline void drive (context_t *c)
628 {
629 hb_glyph_info_t *info = buffer->info;
630 unsigned int count = buffer->len;
Behdad Esfahbodf7600222018-01-12 11:09:21 +0100631 unsigned int state = 0;
632 bool last_was_dont_advance = false;
Behdad Esfahbod57051b42018-01-12 11:42:25 +0100633 for (buffer->idx = 0; buffer->idx <= count;)
Behdad Esfahbod117cfe72018-01-12 00:01:36 +0100634 {
635 if (!state)
636 last_zero = buffer->idx;
637
638 unsigned int klass = buffer->idx < count ?
639 machine.get_class (info[buffer->idx].codepoint, num_glyphs) :
640 0 /* End of text */;
641 const Entry<EntryData> *entry = machine.get_entryZ (state, klass);
642 if (unlikely (!entry))
643 break;
644
645 c->transition (this, entry);
646
Behdad Esfahbodf7600222018-01-12 11:09:21 +0100647
Behdad Esfahboddd38db52018-01-12 09:45:42 +0100648 if (entry->flags & context_t::DontAdvance)
Behdad Esfahbodf7600222018-01-12 11:09:21 +0100649 {
650 if (!last_was_dont_advance)
Behdad Esfahbod461a6052018-01-17 10:02:48 -0800651 {
652 if (dont_advance_set)
653 dont_advance_set->clear ();
654 else
655 dont_advance_set = hb_set_create ();
656 }
Behdad Esfahbodf7600222018-01-12 11:09:21 +0100657
658 unsigned int key = info[buffer->idx].codepoint | (state << 16);
Behdad Esfahbod461a6052018-01-17 10:02:48 -0800659 if (likely (!dont_advance_set->has (key)))
Behdad Esfahbodf7600222018-01-12 11:09:21 +0100660 {
Behdad Esfahbod461a6052018-01-17 10:02:48 -0800661 dont_advance_set->add (key);
Behdad Esfahbodf7600222018-01-12 11:09:21 +0100662 last_was_dont_advance = true;
663 }
Behdad Esfahbodcdfa8012018-01-12 11:12:20 +0100664 else
665 last_was_dont_advance = false;
Behdad Esfahbodf7600222018-01-12 11:09:21 +0100666 }
667 else
668 last_was_dont_advance = false;
Behdad Esfahbod117cfe72018-01-12 00:01:36 +0100669
Behdad Esfahbod57051b42018-01-12 11:42:25 +0100670 if (!last_was_dont_advance)
671 buffer->next_glyph ();
672
Behdad Esfahbod117cfe72018-01-12 00:01:36 +0100673 state = entry->newState;
674 }
675
Behdad Esfahbod57051b42018-01-12 11:42:25 +0100676 if (!c->in_place)
677 {
678 for (buffer->idx = 0; buffer->idx <= count;)
679 buffer->next_glyph ();
680 }
Behdad Esfahbod117cfe72018-01-12 00:01:36 +0100681 }
682
683 public:
684 const StateTable<EntryData> &machine;
685 hb_buffer_t *buffer;
Behdad Esfahbod117cfe72018-01-12 00:01:36 +0100686 unsigned int num_glyphs;
Behdad Esfahbod117cfe72018-01-12 00:01:36 +0100687 unsigned int last_zero;
Behdad Esfahbodf7600222018-01-12 11:09:21 +0100688
689 private:
Behdad Esfahbod461a6052018-01-17 10:02:48 -0800690 hb_set_t *dont_advance_set; /* Infinite-loop detection */
Behdad Esfahbod117cfe72018-01-12 00:01:36 +0100691};
692
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100693
Behdad Esfahbod046690a2018-01-17 16:59:55 -0800694
695struct hb_aat_apply_context_t :
696 hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY>
697{
698 inline const char *get_name (void) { return "APPLY"; }
699 template <typename T>
700 inline return_t dispatch (const T &obj) { return obj.apply (this); }
701 static return_t default_return_value (void) { return false; }
702 bool stop_sublookup_iteration (return_t r) const { return r; }
703
704 hb_font_t *font;
705 hb_face_t *face;
706 hb_buffer_t *buffer;
707 const char *end;
708
709 hb_aat_apply_context_t (hb_font_t *font_,
710 hb_buffer_t *buffer_,
711 const char *end_) :
712 font (font_), face (font->face), buffer (buffer_),
713 end (end_) {}
714};
715
716
Behdad Esfahboda0175e72017-08-17 16:55:54 -0700717} /* namespace AAT */
718
719
720#endif /* HB_AAT_LAYOUT_COMMON_PRIVATE_HH */