blob: ce40abd555267caa69495091d1c38fedd2607980 [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
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070027#ifndef HB_AAT_LAYOUT_COMMON_HH
28#define HB_AAT_LAYOUT_COMMON_HH
Behdad Esfahboda0175e72017-08-17 16:55:54 -070029
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070030#include "hb-aat-layout.hh"
Behdad Esfahboda0175e72017-08-17 16:55:54 -070031
32
33namespace AAT {
34
35using namespace OT;
36
37
38/*
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +010039 * Lookup Table
40 */
41
42template <typename T> struct Lookup;
43
44template <typename T>
45struct LookupFormat0
46{
47 friend struct Lookup<T>;
48
49 private:
Behdad Esfahbod748b9892018-01-09 17:55:17 +010050 inline const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +010051 {
Behdad Esfahbod748b9892018-01-09 17:55:17 +010052 if (unlikely (glyph_id >= num_glyphs)) return nullptr;
53 return &arrayZ[glyph_id];
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +010054 }
55
56 inline bool sanitize (hb_sanitize_context_t *c) const
57 {
58 TRACE_SANITIZE (this);
Behdad Esfahbodbe707382018-07-17 18:45:25 +020059 return_trace (arrayZ.sanitize (c, c->get_num_glyphs ()));
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +010060 }
61
62 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +010063 HBUINT16 format; /* Format identifier--format = 0 */
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +010064 UnsizedArrayOf<T>
65 arrayZ; /* Array of lookup values, indexed by glyph index. */
66 public:
67 DEFINE_SIZE_ARRAY (2, arrayZ);
68};
69
70
71template <typename T>
72struct LookupSegmentSingle
73{
74 inline int cmp (hb_codepoint_t g) const {
75 return g < first ? -1 : g <= last ? 0 : +1 ;
76 }
77
78 inline bool sanitize (hb_sanitize_context_t *c) const
79 {
80 TRACE_SANITIZE (this);
81 return_trace (c->check_struct (this) && value.sanitize (c));
82 }
83
84 GlyphID last; /* Last GlyphID in this segment */
85 GlyphID first; /* First GlyphID in this segment */
86 T value; /* The lookup value (only one) */
87 public:
Behdad Esfahbodca42d962018-01-11 09:15:34 +010088 DEFINE_SIZE_STATIC (4 + T::static_size);
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +010089};
90
91template <typename T>
92struct LookupFormat2
93{
94 friend struct Lookup<T>;
95
96 private:
Behdad Esfahbod748b9892018-01-09 17:55:17 +010097 inline const T* get_value (hb_codepoint_t glyph_id) const
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +010098 {
99 const LookupSegmentSingle<T> *v = segments.bsearch (glyph_id);
Behdad Esfahbod748b9892018-01-09 17:55:17 +0100100 return v ? &v->value : nullptr;
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100101 }
102
103 inline bool sanitize (hb_sanitize_context_t *c) const
104 {
105 TRACE_SANITIZE (this);
106 return_trace (segments.sanitize (c));
107 }
108
109 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100110 HBUINT16 format; /* Format identifier--format = 2 */
Behdad Esfahbod3515c8b2018-10-07 22:27:00 -0400111 VarSizedBinSearchArrayOf<LookupSegmentSingle<T> >
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100112 segments; /* The actual segments. These must already be sorted,
113 * according to the first word in each one (the last
114 * glyph in each segment). */
115 public:
116 DEFINE_SIZE_ARRAY (8, segments);
117};
118
119template <typename T>
120struct LookupSegmentArray
121{
Behdad Esfahbod748b9892018-01-09 17:55:17 +0100122 inline const T* get_value (hb_codepoint_t glyph_id, const void *base) const
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100123 {
Behdad Esfahbod748b9892018-01-09 17:55:17 +0100124 return first <= glyph_id && glyph_id <= last ? &(base+valuesZ)[glyph_id - first] : nullptr;
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100125 }
126
127 inline int cmp (hb_codepoint_t g) const {
128 return g < first ? -1 : g <= last ? 0 : +1 ;
129 }
130
131 inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
132 {
133 TRACE_SANITIZE (this);
134 return_trace (c->check_struct (this) &&
135 first <= last &&
136 valuesZ.sanitize (c, base, last - first + 1));
137 }
138
139 GlyphID last; /* Last GlyphID in this segment */
140 GlyphID first; /* First GlyphID in this segment */
Behdad Esfahbod10642b32018-09-15 19:43:33 +0200141 OffsetTo<UnsizedArrayOf<T>, HBUINT16, false>
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100142 valuesZ; /* A 16-bit offset from the start of
143 * the table to the data. */
144 public:
145 DEFINE_SIZE_STATIC (6);
146};
147
148template <typename T>
149struct LookupFormat4
150{
151 friend struct Lookup<T>;
152
153 private:
Behdad Esfahbod748b9892018-01-09 17:55:17 +0100154 inline const T* get_value (hb_codepoint_t glyph_id) const
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100155 {
156 const LookupSegmentArray<T> *v = segments.bsearch (glyph_id);
Behdad Esfahbod748b9892018-01-09 17:55:17 +0100157 return v ? v->get_value (glyph_id, this) : nullptr;
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100158 }
159
160 inline bool sanitize (hb_sanitize_context_t *c) const
161 {
162 TRACE_SANITIZE (this);
163 return_trace (segments.sanitize (c, this));
164 }
165
166 protected:
Behdad Esfahbod2c824d32018-10-11 16:41:01 -0400167 HBUINT16 format; /* Format identifier--format = 4 */
Behdad Esfahbod3515c8b2018-10-07 22:27:00 -0400168 VarSizedBinSearchArrayOf<LookupSegmentArray<T> >
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100169 segments; /* The actual segments. These must already be sorted,
170 * according to the first word in each one (the last
171 * glyph in each segment). */
172 public:
173 DEFINE_SIZE_ARRAY (8, segments);
174};
175
176template <typename T>
177struct LookupSingle
178{
179 inline int cmp (hb_codepoint_t g) const { return glyph.cmp (g); }
180
181 inline bool sanitize (hb_sanitize_context_t *c) const
182 {
183 TRACE_SANITIZE (this);
184 return_trace (c->check_struct (this) && value.sanitize (c));
185 }
186
187 GlyphID glyph; /* Last GlyphID */
188 T value; /* The lookup value (only one) */
189 public:
Behdad Esfahbod2c824d32018-10-11 16:41:01 -0400190 DEFINE_SIZE_STATIC (2 + T::static_size);
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100191};
192
193template <typename T>
194struct LookupFormat6
195{
196 friend struct Lookup<T>;
197
198 private:
Behdad Esfahbod748b9892018-01-09 17:55:17 +0100199 inline const T* get_value (hb_codepoint_t glyph_id) const
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100200 {
201 const LookupSingle<T> *v = entries.bsearch (glyph_id);
Behdad Esfahbod748b9892018-01-09 17:55:17 +0100202 return v ? &v->value : nullptr;
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100203 }
204
205 inline bool sanitize (hb_sanitize_context_t *c) const
206 {
207 TRACE_SANITIZE (this);
208 return_trace (entries.sanitize (c));
209 }
210
211 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100212 HBUINT16 format; /* Format identifier--format = 6 */
Behdad Esfahbod3515c8b2018-10-07 22:27:00 -0400213 VarSizedBinSearchArrayOf<LookupSingle<T> >
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100214 entries; /* The actual entries, sorted by glyph index. */
215 public:
216 DEFINE_SIZE_ARRAY (8, entries);
217};
218
219template <typename T>
220struct LookupFormat8
221{
222 friend struct Lookup<T>;
223
224 private:
Behdad Esfahbod748b9892018-01-09 17:55:17 +0100225 inline const T* get_value (hb_codepoint_t glyph_id) const
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100226 {
Behdad Esfahbod44af1f92018-10-14 14:52:17 -0700227 return firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount ?
228 &valueArrayZ[glyph_id - firstGlyph] : nullptr;
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100229 }
230
231 inline bool sanitize (hb_sanitize_context_t *c) const
232 {
233 TRACE_SANITIZE (this);
234 return_trace (c->check_struct (this) && valueArrayZ.sanitize (c, glyphCount));
235 }
236
237 protected:
Behdad Esfahbod44af1f92018-10-14 14:52:17 -0700238 HBUINT16 format; /* Format identifier--format = 8 */
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100239 GlyphID firstGlyph; /* First glyph index included in the trimmed array. */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100240 HBUINT16 glyphCount; /* Total number of glyphs (equivalent to the last
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100241 * glyph minus the value of firstGlyph plus 1). */
242 UnsizedArrayOf<T>
243 valueArrayZ; /* The lookup values (indexed by the glyph index
244 * minus the value of firstGlyph). */
245 public:
246 DEFINE_SIZE_ARRAY (6, valueArrayZ);
247};
248
249template <typename T>
Behdad Esfahbodf7c0b432018-10-19 15:23:49 -0700250struct LookupFormat10
251{
252 friend struct Lookup<T>;
253
254 private:
255 inline const typename T::type get_value_or_null (hb_codepoint_t glyph_id) const
256 {
257 if (!(firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount))
258 return Null(T);
259
260 const HBUINT8 *p = &valueArrayZ[(glyph_id - firstGlyph) * valueSize];
261
262 unsigned int v = 0;
263 unsigned int count = valueSize;
264 for (unsigned int i = 0; i < count; i++)
265 v = (v << 8) | *p++;
266
267 return v;
268 }
269
270 inline bool sanitize (hb_sanitize_context_t *c) const
271 {
272 TRACE_SANITIZE (this);
273 return_trace (c->check_struct (this) &&
274 valueSize <= 4 &&
275 valueArrayZ.sanitize (c, glyphCount * valueSize));
276 }
277
278 protected:
279 HBUINT16 format; /* Format identifier--format = 8 */
280 HBUINT16 valueSize; /* Byte size of each value. */
281 GlyphID firstGlyph; /* First glyph index included in the trimmed array. */
282 HBUINT16 glyphCount; /* Total number of glyphs (equivalent to the last
283 * glyph minus the value of firstGlyph plus 1). */
284 UnsizedArrayOf<HBUINT8>
285 valueArrayZ; /* The lookup values (indexed by the glyph index
286 * minus the value of firstGlyph). */
287 public:
Behdad Esfahbod00fdbca2018-10-20 12:04:51 -0700288 DEFINE_SIZE_ARRAY (8, valueArrayZ);
Behdad Esfahbodf7c0b432018-10-19 15:23:49 -0700289};
290
291template <typename T>
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100292struct Lookup
293{
Behdad Esfahbod748b9892018-01-09 17:55:17 +0100294 inline const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100295 {
296 switch (u.format) {
297 case 0: return u.format0.get_value (glyph_id, num_glyphs);
298 case 2: return u.format2.get_value (glyph_id);
299 case 4: return u.format4.get_value (glyph_id);
300 case 6: return u.format6.get_value (glyph_id);
301 case 8: return u.format8.get_value (glyph_id);
Behdad Esfahbod748b9892018-01-09 17:55:17 +0100302 default:return nullptr;
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100303 }
304 }
305
Behdad Esfahbodf7c0b432018-10-19 15:23:49 -0700306 inline const typename T::type get_value_or_null (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
Behdad Esfahbod7727e732018-10-10 13:24:51 -0400307 {
Behdad Esfahbodf7c0b432018-10-19 15:23:49 -0700308 switch (u.format) {
309 /* Format 10 cannot return a pointer. */
310 case 10: return u.format10.get_value_or_null (glyph_id);
311 default:
312 const T *v = get_value (glyph_id, num_glyphs);
313 return v ? *v : Null(T);
314 }
Behdad Esfahbod7727e732018-10-10 13:24:51 -0400315 }
316
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100317 inline bool sanitize (hb_sanitize_context_t *c) const
318 {
319 TRACE_SANITIZE (this);
320 if (!u.format.sanitize (c)) return_trace (false);
321 switch (u.format) {
322 case 0: return_trace (u.format0.sanitize (c));
323 case 2: return_trace (u.format2.sanitize (c));
324 case 4: return_trace (u.format4.sanitize (c));
325 case 6: return_trace (u.format6.sanitize (c));
326 case 8: return_trace (u.format8.sanitize (c));
Behdad Esfahbodf7c0b432018-10-19 15:23:49 -0700327 case 10: return_trace (u.format10.sanitize (c));
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100328 default:return_trace (true);
329 }
330 }
331
332 protected:
333 union {
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100334 HBUINT16 format; /* Format identifier */
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100335 LookupFormat0<T> format0;
336 LookupFormat2<T> format2;
337 LookupFormat4<T> format4;
338 LookupFormat6<T> format6;
339 LookupFormat8<T> format8;
Behdad Esfahbodf7c0b432018-10-19 15:23:49 -0700340 LookupFormat10<T> format10;
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100341 } u;
342 public:
Behdad Esfahbod9e8a9b82018-10-17 21:41:25 -0700343 DEFINE_SIZE_UNION (2, format);
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100344};
Behdad Esfahbod9e8a9b82018-10-17 21:41:25 -0700345/* Lookup 0 has unbounded size (dependant on num_glyphs). So we need to defined
346 * special NULL objects for Lookup<> objects, but since it's template our macros
347 * don't work. So we have to hand-code them here. UGLY. */
348} /* Close namespace. */
349/* Ugly hand-coded null objects for template Lookup<> :(. */
350extern HB_INTERNAL const unsigned char _hb_Null_AAT_Lookup[2];
351template <>
352/*static*/ inline const AAT::Lookup<OT::HBUINT16>& Null<AAT::Lookup<OT::HBUINT16> > (void) {
353 return *reinterpret_cast<const AAT::Lookup<OT::HBUINT16> *> (_hb_Null_AAT_Lookup);
354}
355template <>
356/*static*/ inline const AAT::Lookup<OT::HBUINT32>& Null<AAT::Lookup<OT::HBUINT32> > (void) {
357 return *reinterpret_cast<const AAT::Lookup<OT::HBUINT32> *> (_hb_Null_AAT_Lookup);
358}
359template <>
Behdad Esfahbod270a37c2018-10-17 22:42:47 -0700360/*static*/ inline const AAT::Lookup<OT::Offset<OT::HBUINT16, false> >& Null<AAT::Lookup<OT::Offset<OT::HBUINT16, false> > > (void) {
361 return *reinterpret_cast<const AAT::Lookup<OT::Offset<OT::HBUINT16, false> > *> (_hb_Null_AAT_Lookup);
Behdad Esfahbod9e8a9b82018-10-17 21:41:25 -0700362}
363namespace AAT {
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100364
Behdad Esfahbod102af612018-10-25 17:29:32 -0700365enum { DELETED_GLYPH = 0xFFFF };
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100366
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100367/*
Behdad Esfahbod1f1c85a2018-01-11 22:43:57 +0100368 * Extended State Table
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100369 */
370
371template <typename T>
372struct Entry
373{
374 inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
375 {
376 TRACE_SANITIZE (this);
Behdad Esfahbod17f01af2018-01-11 18:54:49 +0100377 /* Note, we don't recurse-sanitize data because we don't access it.
378 * That said, in our DEFINE_SIZE_STATIC we access T::static_size,
379 * which ensures that data has a simple sanitize(). To be determined
Behdad Esfahbod39bd07a2018-10-26 21:01:11 -0700380 * if I need to remove that as well.
381 *
382 * XXX Because we are a template, our DEFINE_SIZE_STATIC assertion
383 * wouldn't be checked. */
Behdad Esfahbod17f01af2018-01-11 18:54:49 +0100384 return_trace (c->check_struct (this));
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100385 }
386
387 public:
Behdad Esfahbod17f01af2018-01-11 18:54:49 +0100388 HBUINT16 newState; /* Byte offset from beginning of state table
389 * to the new state. Really?!?! Or just state
390 * number? The latter in morx for sure. */
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100391 HBUINT16 flags; /* Table specific. */
392 T data; /* Optional offsets to per-glyph tables. */
393 public:
394 DEFINE_SIZE_STATIC (4 + T::static_size);
395};
396
397template <>
398struct Entry<void>
399{
Behdad Esfahbod39bd07a2018-10-26 21:01:11 -0700400 inline bool sanitize (hb_sanitize_context_t *c, unsigned int count /*XXX Unused?*/) const
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100401 {
402 TRACE_SANITIZE (this);
403 return_trace (c->check_struct (this));
404 }
405
406 public:
407 HBUINT16 newState; /* Byte offset from beginning of state table to the new state. */
408 HBUINT16 flags; /* Table specific. */
409 public:
410 DEFINE_SIZE_STATIC (4);
411};
412
Behdad Esfahbod1f1c85a2018-01-11 22:43:57 +0100413template <typename Extra>
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100414struct StateTable
415{
Behdad Esfahbod4653e6c2018-09-14 11:31:33 +0200416 enum State
417 {
418 STATE_START_OF_TEXT = 0,
419 STATE_START_OF_LINE = 1,
420 };
421 enum Class
422 {
423 CLASS_END_OF_TEXT = 0,
424 CLASS_OUT_OF_BOUNDS = 1,
425 CLASS_DELETED_GLYPH = 2,
426 CLASS_END_OF_LINE = 3,
427 };
428
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100429 inline unsigned int get_class (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
Behdad Esfahbod1f1c85a2018-01-11 22:43:57 +0100430 {
Behdad Esfahbod102af612018-10-25 17:29:32 -0700431 if (unlikely (glyph_id == DELETED_GLYPH)) return CLASS_DELETED_GLYPH;
Behdad Esfahbod1f1c85a2018-01-11 22:43:57 +0100432 const HBUINT16 *v = (this+classTable).get_value (glyph_id, num_glyphs);
Behdad Esfahbod957dbed2018-09-14 12:14:42 +0200433 return v ? (unsigned) *v : (unsigned) CLASS_OUT_OF_BOUNDS;
Behdad Esfahbod1f1c85a2018-01-11 22:43:57 +0100434 }
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100435
Behdad Esfahbod17f01af2018-01-11 18:54:49 +0100436 inline const Entry<Extra> *get_entries () const
437 {
438 return (this+entryTable).arrayZ;
439 }
440
441 inline const Entry<Extra> *get_entryZ (unsigned int state, unsigned int klass) const
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100442 {
Behdad Esfahbod680cbc22018-01-11 18:15:53 +0100443 if (unlikely (klass >= nClasses)) return nullptr;
444
Behdad Esfahbod1f1c85a2018-01-11 22:43:57 +0100445 const HBUINT16 *states = (this+stateArrayTable).arrayZ;
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100446 const Entry<Extra> *entries = (this+entryTable).arrayZ;
447
Behdad Esfahbod680cbc22018-01-11 18:15:53 +0100448 unsigned int entry = states[state * nClasses + klass];
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100449
Behdad Esfahbod680cbc22018-01-11 18:15:53 +0100450 return &entries[entry];
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100451 }
452
Behdad Esfahbod17f01af2018-01-11 18:54:49 +0100453 inline bool sanitize (hb_sanitize_context_t *c,
454 unsigned int *num_entries_out = nullptr) const
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100455 {
456 TRACE_SANITIZE (this);
Behdad Esfahbod12fffce2018-01-15 15:41:51 -0500457 if (unlikely (!(c->check_struct (this) &&
458 classTable.sanitize (c, this)))) return_trace (false);
Behdad Esfahbod680cbc22018-01-11 18:15:53 +0100459
Behdad Esfahbod1f1c85a2018-01-11 22:43:57 +0100460 const HBUINT16 *states = (this+stateArrayTable).arrayZ;
Behdad Esfahbod680cbc22018-01-11 18:15:53 +0100461 const Entry<Extra> *entries = (this+entryTable).arrayZ;
462
Behdad Esfahbode9405302018-10-11 15:56:17 -0400463 unsigned int num_classes = nClasses;
464
Behdad Esfahbod680cbc22018-01-11 18:15:53 +0100465 unsigned int num_states = 1;
466 unsigned int num_entries = 0;
467
468 unsigned int state = 0;
469 unsigned int entry = 0;
470 while (state < num_states)
471 {
Behdad Esfahbode9405302018-10-11 15:56:17 -0400472 if (unlikely (hb_unsigned_mul_overflows (num_classes, states[0].static_size)))
473 return_trace (false);
474
Behdad Esfahbod5021ba22018-02-08 15:11:28 -0600475 if (unlikely (!c->check_array (states,
Behdad Esfahbod9507b052018-09-10 23:18:07 +0200476 num_states,
Behdad Esfahbode9405302018-10-11 15:56:17 -0400477 num_classes * states[0].static_size)))
Behdad Esfahbod680cbc22018-01-11 18:15:53 +0100478 return_trace (false);
Behdad Esfahbod83780302018-10-17 22:34:16 -0700479 if ((c->max_ops -= num_states - state) < 0)
480 return_trace (false);
Behdad Esfahbod680cbc22018-01-11 18:15:53 +0100481 { /* Sweep new states. */
Behdad Esfahbode9405302018-10-11 15:56:17 -0400482 const HBUINT16 *stop = &states[num_states * num_classes];
483 for (const HBUINT16 *p = &states[state * num_classes]; p < stop; p++)
Behdad Esfahbod680cbc22018-01-11 18:15:53 +0100484 num_entries = MAX<unsigned int> (num_entries, *p + 1);
485 state = num_states;
486 }
487
Behdad Esfahbod9507b052018-09-10 23:18:07 +0200488 if (unlikely (!c->check_array (entries, num_entries)))
Behdad Esfahbod680cbc22018-01-11 18:15:53 +0100489 return_trace (false);
Behdad Esfahbod83780302018-10-17 22:34:16 -0700490 if ((c->max_ops -= num_entries - entry) < 0)
491 return_trace (false);
Behdad Esfahbod680cbc22018-01-11 18:15:53 +0100492 { /* Sweep new entries. */
493 const Entry<Extra> *stop = &entries[num_entries];
494 for (const Entry<Extra> *p = &entries[entry]; p < stop; p++)
495 num_states = MAX<unsigned int> (num_states, p->newState + 1);
496 entry = num_entries;
497 }
498 }
499
Behdad Esfahbod17f01af2018-01-11 18:54:49 +0100500 if (num_entries_out)
501 *num_entries_out = num_entries;
502
Behdad Esfahbod680cbc22018-01-11 18:15:53 +0100503 return_trace (true);
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100504 }
505
506 protected:
Behdad Esfahbod1f1c85a2018-01-11 22:43:57 +0100507 HBUINT32 nClasses; /* Number of classes, which is the number of indices
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100508 * in a single line in the state array. */
Behdad Esfahbod10642b32018-09-15 19:43:33 +0200509 LOffsetTo<Lookup<HBUINT16>, false>
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100510 classTable; /* Offset to the class table. */
Behdad Esfahbod10642b32018-09-15 19:43:33 +0200511 LOffsetTo<UnsizedArrayOf<HBUINT16>, false>
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100512 stateArrayTable;/* Offset to the state array. */
Behdad Esfahbod10642b32018-09-15 19:43:33 +0200513 LOffsetTo<UnsizedArrayOf<Entry<Extra> >, false>
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100514 entryTable; /* Offset to the entry array. */
515
516 public:
Behdad Esfahbod9009b342018-01-12 12:04:53 +0100517 DEFINE_SIZE_STATIC (16);
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100518};
519
Behdad Esfahbod117cfe72018-01-12 00:01:36 +0100520template <typename EntryData>
521struct StateTableDriver
522{
523 inline StateTableDriver (const StateTable<EntryData> &machine_,
524 hb_buffer_t *buffer_,
525 hb_face_t *face_) :
526 machine (machine_),
527 buffer (buffer_),
Behdad Esfahbod54e6efa2018-02-04 14:58:02 -0500528 num_glyphs (face_->get_num_glyphs ()) {}
Behdad Esfahbod117cfe72018-01-12 00:01:36 +0100529
530 template <typename context_t>
531 inline void drive (context_t *c)
532 {
Behdad Esfahbode6f283e2018-01-19 18:08:56 -0800533 if (!c->in_place)
534 buffer->clear_output ();
535
Behdad Esfahbod4653e6c2018-09-14 11:31:33 +0200536 unsigned int state = StateTable<EntryData>::STATE_START_OF_TEXT;
Behdad Esfahbodf7600222018-01-12 11:09:21 +0100537 bool last_was_dont_advance = false;
Behdad Esfahbod1bb8ed82018-10-25 17:33:48 -0700538 for (buffer->idx = 0; buffer->successful;)
Behdad Esfahbod117cfe72018-01-12 00:01:36 +0100539 {
Behdad Esfahbode6f283e2018-01-19 18:08:56 -0800540 unsigned int klass = buffer->idx < buffer->len ?
Behdad Esfahbod4831e612018-10-05 18:14:13 +0200541 machine.get_class (buffer->info[buffer->idx].codepoint, num_glyphs) :
Behdad Esfahbod4653e6c2018-09-14 11:31:33 +0200542 (unsigned) StateTable<EntryData>::CLASS_END_OF_TEXT;
Behdad Esfahbod117cfe72018-01-12 00:01:36 +0100543 const Entry<EntryData> *entry = machine.get_entryZ (state, klass);
544 if (unlikely (!entry))
545 break;
546
Behdad Esfahbod54e6efa2018-02-04 14:58:02 -0500547 /* Unsafe-to-break before this if not in state 0, as things might
Behdad Esfahbod7ee50af2018-10-06 21:31:44 +0200548 * go differently if we start from state 0 here.
549 *
550 * Ugh. The indexing here is ugly... */
551 if (state && buffer->backtrack_len () && buffer->idx < buffer->len)
Behdad Esfahbod54e6efa2018-02-04 14:58:02 -0500552 {
Behdad Esfahbod2971e9d2018-02-06 11:48:04 -0500553 /* If there's no action and we're just epsilon-transitioning to state 0,
554 * safe to break. */
555 if (c->is_actionable (this, entry) ||
Behdad Esfahbod0739b282018-09-19 17:32:21 -0400556 !(entry->newState == StateTable<EntryData>::STATE_START_OF_TEXT &&
557 entry->flags == context_t::DontAdvance))
Behdad Esfahbod7ee50af2018-10-06 21:31:44 +0200558 buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1);
Behdad Esfahbod54e6efa2018-02-04 14:58:02 -0500559 }
560
561 /* Unsafe-to-break if end-of-text would kick in here. */
562 if (buffer->idx + 2 <= buffer->len)
563 {
564 const Entry<EntryData> *end_entry = machine.get_entryZ (state, 0);
565 if (c->is_actionable (this, end_entry))
566 buffer->unsafe_to_break (buffer->idx, buffer->idx + 2);
567 }
568
Behdad Esfahbode6f283e2018-01-19 18:08:56 -0800569 if (unlikely (!c->transition (this, entry)))
570 break;
Behdad Esfahbodf7600222018-01-12 11:09:21 +0100571
Behdad Esfahbod7033fe52018-02-18 17:12:04 -0800572 last_was_dont_advance = (entry->flags & context_t::DontAdvance) && buffer->max_ops-- > 0;
Behdad Esfahbod117cfe72018-01-12 00:01:36 +0100573
Behdad Esfahbode6f283e2018-01-19 18:08:56 -0800574 state = entry->newState;
575
576 if (buffer->idx == buffer->len)
577 break;
578
Behdad Esfahbod57051b42018-01-12 11:42:25 +0100579 if (!last_was_dont_advance)
580 buffer->next_glyph ();
Behdad Esfahbod117cfe72018-01-12 00:01:36 +0100581 }
582
Behdad Esfahbod57051b42018-01-12 11:42:25 +0100583 if (!c->in_place)
584 {
Behdad Esfahbod7efa3822018-10-14 19:30:44 -0700585 for (; buffer->successful && buffer->idx < buffer->len;)
586 buffer->next_glyph ();
587 if (likely (buffer->successful))
588 buffer->swap_buffers ();
Behdad Esfahbod57051b42018-01-12 11:42:25 +0100589 }
Behdad Esfahbod117cfe72018-01-12 00:01:36 +0100590 }
591
592 public:
593 const StateTable<EntryData> &machine;
594 hb_buffer_t *buffer;
Behdad Esfahbod117cfe72018-01-12 00:01:36 +0100595 unsigned int num_glyphs;
Behdad Esfahbod117cfe72018-01-12 00:01:36 +0100596};
597
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100598
Behdad Esfahbod7bb4da72018-10-11 00:52:07 -0400599struct ankr;
Behdad Esfahbod046690a2018-01-17 16:59:55 -0800600
601struct hb_aat_apply_context_t :
602 hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY>
603{
604 inline const char *get_name (void) { return "APPLY"; }
605 template <typename T>
606 inline return_t dispatch (const T &obj) { return obj.apply (this); }
607 static return_t default_return_value (void) { return false; }
608 bool stop_sublookup_iteration (return_t r) const { return r; }
609
Behdad Esfahbod53e55942018-10-09 22:35:22 -0400610 hb_ot_shape_plan_t *plan;
Behdad Esfahbod046690a2018-01-17 16:59:55 -0800611 hb_font_t *font;
612 hb_face_t *face;
613 hb_buffer_t *buffer;
Behdad Esfahbodf07ce662018-01-19 16:52:01 -0800614 hb_sanitize_context_t sanitizer;
Behdad Esfahbod7bb4da72018-10-11 00:52:07 -0400615 const ankr &ankr_table;
Behdad Esfahbod1622ba52018-10-11 01:14:18 -0400616 const char *ankr_end;
Behdad Esfahbod046690a2018-01-17 16:59:55 -0800617
Behdad Esfahbod126ffdb2018-02-07 12:26:41 -0500618 /* Unused. For debug tracing only. */
619 unsigned int lookup_index;
620 unsigned int debug_depth;
621
Behdad Esfahbod53e55942018-10-09 22:35:22 -0400622 inline hb_aat_apply_context_t (hb_ot_shape_plan_t *plan_,
623 hb_font_t *font_,
Behdad Esfahbodf07ce662018-01-19 16:52:01 -0800624 hb_buffer_t *buffer_,
Behdad Esfahbodd6a12db2018-10-11 11:10:06 -0400625 hb_blob_t *blob = const_cast<hb_blob_t *> (&Null(hb_blob_t)),
Behdad Esfahbod1622ba52018-10-11 01:14:18 -0400626 const ankr &ankr_table_ = Null(ankr),
627 const char *ankr_end_ = nullptr) :
Behdad Esfahbod53e55942018-10-09 22:35:22 -0400628 plan (plan_), font (font_), face (font->face), buffer (buffer_),
Behdad Esfahbod1622ba52018-10-11 01:14:18 -0400629 sanitizer (),
630 ankr_table (ankr_table_), ankr_end (ankr_end_),
631 lookup_index (0), debug_depth (0)
Behdad Esfahbodf07ce662018-01-19 16:52:01 -0800632 {
Behdad Esfahbodd6a12db2018-10-11 11:10:06 -0400633 sanitizer.init (blob);
Behdad Esfahbodbe707382018-07-17 18:45:25 +0200634 sanitizer.set_num_glyphs (face->get_num_glyphs ());
Behdad Esfahbodf07ce662018-01-19 16:52:01 -0800635 sanitizer.start_processing ();
Behdad Esfahbodd35315c2018-10-09 23:17:32 -0400636 sanitizer.set_max_ops (HB_SANITIZE_MAX_OPS_MAX);
Behdad Esfahbodf07ce662018-01-19 16:52:01 -0800637 }
638
Behdad Esfahbodee433d32018-02-07 12:30:18 -0500639 inline void set_lookup_index (unsigned int i) { lookup_index = i; }
640
Behdad Esfahbodf07ce662018-01-19 16:52:01 -0800641 inline ~hb_aat_apply_context_t (void)
642 {
643 sanitizer.end_processing ();
644 }
Behdad Esfahbod046690a2018-01-17 16:59:55 -0800645};
646
647
Behdad Esfahboda0175e72017-08-17 16:55:54 -0700648} /* namespace AAT */
649
650
Behdad Esfahbodc77ae402018-08-25 22:36:36 -0700651#endif /* HB_AAT_LAYOUT_COMMON_HH */