blob: 51add22138b503f4e808f8fa7bd0b0b8e6a3aa8e [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
Ebrahim Byagowib053cab2018-10-30 18:41:34 +0330413template <typename Types, typename Extra>
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100414struct StateTable
415{
Ebrahim Byagowib053cab2018-10-30 18:41:34 +0330416 typedef typename Types::HBUINT HBUINT;
417 typedef typename Types::HBUSHORT HBUSHORT;
418 typedef typename Types::ClassType ClassType;
419
Behdad Esfahbod4653e6c2018-09-14 11:31:33 +0200420 enum State
421 {
422 STATE_START_OF_TEXT = 0,
423 STATE_START_OF_LINE = 1,
424 };
425 enum Class
426 {
427 CLASS_END_OF_TEXT = 0,
428 CLASS_OUT_OF_BOUNDS = 1,
429 CLASS_DELETED_GLYPH = 2,
430 CLASS_END_OF_LINE = 3,
431 };
432
Behdad Esfahbod0cf282a2018-10-30 20:51:44 -0700433 inline unsigned int new_state (unsigned int newState) const
Behdad Esfahbod11dbf0f2018-10-30 21:49:59 -0700434 { return Types::extended ? newState : (newState - stateArrayTable) / nClasses; }
Behdad Esfahbod0cf282a2018-10-30 20:51:44 -0700435
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100436 inline unsigned int get_class (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
Behdad Esfahbod1f1c85a2018-01-11 22:43:57 +0100437 {
Behdad Esfahbod102af612018-10-25 17:29:32 -0700438 if (unlikely (glyph_id == DELETED_GLYPH)) return CLASS_DELETED_GLYPH;
Behdad Esfahbodc2527a12018-10-30 19:26:16 -0700439 return (this+classTable).get_class (glyph_id, num_glyphs);
Behdad Esfahbod1f1c85a2018-01-11 22:43:57 +0100440 }
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100441
Behdad Esfahbod17f01af2018-01-11 18:54:49 +0100442 inline const Entry<Extra> *get_entries () const
443 {
444 return (this+entryTable).arrayZ;
445 }
446
447 inline const Entry<Extra> *get_entryZ (unsigned int state, unsigned int klass) const
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100448 {
Behdad Esfahbod680cbc22018-01-11 18:15:53 +0100449 if (unlikely (klass >= nClasses)) return nullptr;
450
Behdad Esfahbodc2527a12018-10-30 19:26:16 -0700451 const HBUSHORT *states = (this+stateArrayTable).arrayZ;
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100452 const Entry<Extra> *entries = (this+entryTable).arrayZ;
453
Behdad Esfahbod680cbc22018-01-11 18:15:53 +0100454 unsigned int entry = states[state * nClasses + klass];
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100455
Behdad Esfahbod680cbc22018-01-11 18:15:53 +0100456 return &entries[entry];
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100457 }
458
Behdad Esfahbod17f01af2018-01-11 18:54:49 +0100459 inline bool sanitize (hb_sanitize_context_t *c,
460 unsigned int *num_entries_out = nullptr) const
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100461 {
462 TRACE_SANITIZE (this);
Behdad Esfahbod12fffce2018-01-15 15:41:51 -0500463 if (unlikely (!(c->check_struct (this) &&
464 classTable.sanitize (c, this)))) return_trace (false);
Behdad Esfahbod680cbc22018-01-11 18:15:53 +0100465
Behdad Esfahbodc2527a12018-10-30 19:26:16 -0700466 const HBUSHORT *states = (this+stateArrayTable).arrayZ;
Behdad Esfahbod680cbc22018-01-11 18:15:53 +0100467 const Entry<Extra> *entries = (this+entryTable).arrayZ;
468
Behdad Esfahbode9405302018-10-11 15:56:17 -0400469 unsigned int num_classes = nClasses;
470
Behdad Esfahbod680cbc22018-01-11 18:15:53 +0100471 unsigned int num_states = 1;
472 unsigned int num_entries = 0;
473
474 unsigned int state = 0;
475 unsigned int entry = 0;
476 while (state < num_states)
477 {
Behdad Esfahbode9405302018-10-11 15:56:17 -0400478 if (unlikely (hb_unsigned_mul_overflows (num_classes, states[0].static_size)))
479 return_trace (false);
480
Behdad Esfahbod5021ba22018-02-08 15:11:28 -0600481 if (unlikely (!c->check_array (states,
Behdad Esfahbod9507b052018-09-10 23:18:07 +0200482 num_states,
Behdad Esfahbode9405302018-10-11 15:56:17 -0400483 num_classes * states[0].static_size)))
Behdad Esfahbod680cbc22018-01-11 18:15:53 +0100484 return_trace (false);
Behdad Esfahbod83780302018-10-17 22:34:16 -0700485 if ((c->max_ops -= num_states - state) < 0)
486 return_trace (false);
Behdad Esfahbod680cbc22018-01-11 18:15:53 +0100487 { /* Sweep new states. */
Behdad Esfahbodc2527a12018-10-30 19:26:16 -0700488 const HBUSHORT *stop = &states[num_states * num_classes];
489 for (const HBUSHORT *p = &states[state * num_classes]; p < stop; p++)
Behdad Esfahbod680cbc22018-01-11 18:15:53 +0100490 num_entries = MAX<unsigned int> (num_entries, *p + 1);
491 state = num_states;
492 }
493
Behdad Esfahbod9507b052018-09-10 23:18:07 +0200494 if (unlikely (!c->check_array (entries, num_entries)))
Behdad Esfahbod680cbc22018-01-11 18:15:53 +0100495 return_trace (false);
Behdad Esfahbod83780302018-10-17 22:34:16 -0700496 if ((c->max_ops -= num_entries - entry) < 0)
497 return_trace (false);
Behdad Esfahbod680cbc22018-01-11 18:15:53 +0100498 { /* Sweep new entries. */
499 const Entry<Extra> *stop = &entries[num_entries];
500 for (const Entry<Extra> *p = &entries[entry]; p < stop; p++)
Behdad Esfahbod0cf282a2018-10-30 20:51:44 -0700501 {
502 unsigned int newState = new_state (p->newState);
503 num_states = MAX<unsigned int> (num_states, newState + 1);
504 }
Behdad Esfahbod680cbc22018-01-11 18:15:53 +0100505 entry = num_entries;
506 }
507 }
508
Behdad Esfahbod17f01af2018-01-11 18:54:49 +0100509 if (num_entries_out)
510 *num_entries_out = num_entries;
511
Behdad Esfahbod680cbc22018-01-11 18:15:53 +0100512 return_trace (true);
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100513 }
514
515 protected:
Ebrahim Byagowib053cab2018-10-30 18:41:34 +0330516 HBUINT nClasses; /* Number of classes, which is the number of indices
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100517 * in a single line in the state array. */
Ebrahim Byagowib053cab2018-10-30 18:41:34 +0330518 OffsetTo<ClassType, HBUINT, false>
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100519 classTable; /* Offset to the class table. */
Ebrahim Byagowib053cab2018-10-30 18:41:34 +0330520 OffsetTo<UnsizedArrayOf<HBUSHORT>, HBUINT, false>
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100521 stateArrayTable;/* Offset to the state array. */
Ebrahim Byagowib053cab2018-10-30 18:41:34 +0330522 OffsetTo<UnsizedArrayOf<Entry<Extra> >, HBUINT, false>
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100523 entryTable; /* Offset to the entry array. */
524
525 public:
Behdad Esfahbod11dbf0f2018-10-30 21:49:59 -0700526 DEFINE_SIZE_STATIC (4 * sizeof (HBUINT));
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100527};
528
Ebrahim Byagowib053cab2018-10-30 18:41:34 +0330529struct ClassTable
530{
531 inline unsigned int get_class (hb_codepoint_t glyph_id) const
532 {
533 return firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount ? classArrayZ[glyph_id - firstGlyph] : 1;
534 }
535 inline bool sanitize (hb_sanitize_context_t *c) const
536 {
537 TRACE_SANITIZE (this);
538 return_trace (c->check_struct (this) && classArrayZ.sanitize (c, glyphCount));
539 }
540 protected:
541 GlyphID firstGlyph; /* First glyph index included in the trimmed array. */
542 HBUINT16 glyphCount; /* Total number of glyphs (equivalent to the last
543 * glyph minus the value of firstGlyph plus 1). */
544 UnsizedArrayOf<HBUINT8>
545 classArrayZ; /* The class codes (indexed by glyph index minus
546 * firstGlyph). */
547 public:
548 DEFINE_SIZE_ARRAY (4, classArrayZ);
549};
550
551struct MortTypes
552{
553 static const bool extended = false;
554 typedef HBUINT16 HBUINT;
555 typedef HBUINT8 HBUSHORT;
556 struct ClassType : ClassTable
557 {
558 inline unsigned int get_class (hb_codepoint_t glyph_id, unsigned int num_glyphs HB_UNUSED) const
559 {
560 return ClassTable::get_class (glyph_id);
561 }
562 };
Behdad Esfahbod36e90ef2018-10-31 15:09:09 -0700563 template <typename T>
564 static inline unsigned int offsetToIndex (unsigned int offset,
565 const void *base,
566 const T *array)
567 {
568 return (offset - ((const char *) array - (const char *) base)) / sizeof (T);
569 }
570 template <typename T>
571 static inline unsigned int wordOffsetToIndex (unsigned int offset,
572 const void *base,
573 const T *array)
574 {
575 return offsetToIndex (2 * offset, base, array);
576 }
Ebrahim Byagowib053cab2018-10-30 18:41:34 +0330577};
578struct MorxTypes
579{
580 static const bool extended = true;
581 typedef HBUINT32 HBUINT;
582 typedef HBUINT16 HBUSHORT;
583 struct ClassType : Lookup<HBUINT16>
584 {
585 inline unsigned int get_class (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
586 {
587 const HBUINT16 *v = get_value (glyph_id, num_glyphs);
588 return v ? *v : 1;
589 }
590 };
Behdad Esfahbod36e90ef2018-10-31 15:09:09 -0700591 template <typename T>
592 static inline unsigned int offsetToIndex (unsigned int offset,
593 const void *base,
594 const T *array)
595 {
596 return offset;
597 }
598 template <typename T>
599 static inline unsigned int wordOffsetToIndex (unsigned int offset,
600 const void *base,
601 const T *array)
602 {
603 return offset;
604 }
Ebrahim Byagowib053cab2018-10-30 18:41:34 +0330605};
606
607template <typename Types, typename EntryData>
Behdad Esfahbod117cfe72018-01-12 00:01:36 +0100608struct StateTableDriver
609{
Ebrahim Byagowib053cab2018-10-30 18:41:34 +0330610 inline StateTableDriver (const StateTable<Types, EntryData> &machine_,
Behdad Esfahbod117cfe72018-01-12 00:01:36 +0100611 hb_buffer_t *buffer_,
612 hb_face_t *face_) :
613 machine (machine_),
614 buffer (buffer_),
Behdad Esfahbod54e6efa2018-02-04 14:58:02 -0500615 num_glyphs (face_->get_num_glyphs ()) {}
Behdad Esfahbod117cfe72018-01-12 00:01:36 +0100616
617 template <typename context_t>
618 inline void drive (context_t *c)
619 {
Behdad Esfahbode6f283e2018-01-19 18:08:56 -0800620 if (!c->in_place)
621 buffer->clear_output ();
622
Ebrahim Byagowib053cab2018-10-30 18:41:34 +0330623 unsigned int state = StateTable<Types, EntryData>::STATE_START_OF_TEXT;
Behdad Esfahbodf7600222018-01-12 11:09:21 +0100624 bool last_was_dont_advance = false;
Behdad Esfahbod1bb8ed82018-10-25 17:33:48 -0700625 for (buffer->idx = 0; buffer->successful;)
Behdad Esfahbod117cfe72018-01-12 00:01:36 +0100626 {
Behdad Esfahbode6f283e2018-01-19 18:08:56 -0800627 unsigned int klass = buffer->idx < buffer->len ?
Behdad Esfahbod4831e612018-10-05 18:14:13 +0200628 machine.get_class (buffer->info[buffer->idx].codepoint, num_glyphs) :
Ebrahim Byagowib053cab2018-10-30 18:41:34 +0330629 (unsigned) StateTable<Types, EntryData>::CLASS_END_OF_TEXT;
Behdad Esfahbod117cfe72018-01-12 00:01:36 +0100630 const Entry<EntryData> *entry = machine.get_entryZ (state, klass);
631 if (unlikely (!entry))
632 break;
633
Behdad Esfahbod54e6efa2018-02-04 14:58:02 -0500634 /* Unsafe-to-break before this if not in state 0, as things might
Behdad Esfahbod7ee50af2018-10-06 21:31:44 +0200635 * go differently if we start from state 0 here.
636 *
637 * Ugh. The indexing here is ugly... */
638 if (state && buffer->backtrack_len () && buffer->idx < buffer->len)
Behdad Esfahbod54e6efa2018-02-04 14:58:02 -0500639 {
Behdad Esfahbod2971e9d2018-02-06 11:48:04 -0500640 /* If there's no action and we're just epsilon-transitioning to state 0,
641 * safe to break. */
642 if (c->is_actionable (this, entry) ||
Ebrahim Byagowib053cab2018-10-30 18:41:34 +0330643 !(entry->newState == StateTable<Types, EntryData>::STATE_START_OF_TEXT &&
Behdad Esfahbod0739b282018-09-19 17:32:21 -0400644 entry->flags == context_t::DontAdvance))
Behdad Esfahbod7ee50af2018-10-06 21:31:44 +0200645 buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1);
Behdad Esfahbod54e6efa2018-02-04 14:58:02 -0500646 }
647
648 /* Unsafe-to-break if end-of-text would kick in here. */
649 if (buffer->idx + 2 <= buffer->len)
650 {
651 const Entry<EntryData> *end_entry = machine.get_entryZ (state, 0);
652 if (c->is_actionable (this, end_entry))
653 buffer->unsafe_to_break (buffer->idx, buffer->idx + 2);
654 }
655
Behdad Esfahbode6f283e2018-01-19 18:08:56 -0800656 if (unlikely (!c->transition (this, entry)))
Behdad Esfahbod0cf282a2018-10-30 20:51:44 -0700657 break;
Behdad Esfahbodf7600222018-01-12 11:09:21 +0100658
Behdad Esfahbod7033fe52018-02-18 17:12:04 -0800659 last_was_dont_advance = (entry->flags & context_t::DontAdvance) && buffer->max_ops-- > 0;
Behdad Esfahbod117cfe72018-01-12 00:01:36 +0100660
Behdad Esfahbod0cf282a2018-10-30 20:51:44 -0700661 state = machine.new_state (entry->newState);
Behdad Esfahbode6f283e2018-01-19 18:08:56 -0800662
663 if (buffer->idx == buffer->len)
Behdad Esfahbod0cf282a2018-10-30 20:51:44 -0700664 break;
Behdad Esfahbode6f283e2018-01-19 18:08:56 -0800665
Behdad Esfahbod57051b42018-01-12 11:42:25 +0100666 if (!last_was_dont_advance)
Behdad Esfahbod0cf282a2018-10-30 20:51:44 -0700667 buffer->next_glyph ();
Behdad Esfahbod117cfe72018-01-12 00:01:36 +0100668 }
669
Behdad Esfahbod57051b42018-01-12 11:42:25 +0100670 if (!c->in_place)
671 {
Behdad Esfahbod7efa3822018-10-14 19:30:44 -0700672 for (; buffer->successful && buffer->idx < buffer->len;)
673 buffer->next_glyph ();
674 if (likely (buffer->successful))
675 buffer->swap_buffers ();
Behdad Esfahbod57051b42018-01-12 11:42:25 +0100676 }
Behdad Esfahbod117cfe72018-01-12 00:01:36 +0100677 }
678
679 public:
Ebrahim Byagowib053cab2018-10-30 18:41:34 +0330680 const StateTable<Types, EntryData> &machine;
Behdad Esfahbod117cfe72018-01-12 00:01:36 +0100681 hb_buffer_t *buffer;
Behdad Esfahbod117cfe72018-01-12 00:01:36 +0100682 unsigned int num_glyphs;
Behdad Esfahbod117cfe72018-01-12 00:01:36 +0100683};
684
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100685
Behdad Esfahbod7bb4da72018-10-11 00:52:07 -0400686struct ankr;
Behdad Esfahbod046690a2018-01-17 16:59:55 -0800687
688struct hb_aat_apply_context_t :
689 hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY>
690{
691 inline const char *get_name (void) { return "APPLY"; }
692 template <typename T>
693 inline return_t dispatch (const T &obj) { return obj.apply (this); }
694 static return_t default_return_value (void) { return false; }
695 bool stop_sublookup_iteration (return_t r) const { return r; }
696
Behdad Esfahbod53e55942018-10-09 22:35:22 -0400697 hb_ot_shape_plan_t *plan;
Behdad Esfahbod046690a2018-01-17 16:59:55 -0800698 hb_font_t *font;
699 hb_face_t *face;
700 hb_buffer_t *buffer;
Behdad Esfahbodf07ce662018-01-19 16:52:01 -0800701 hb_sanitize_context_t sanitizer;
Behdad Esfahbod7bb4da72018-10-11 00:52:07 -0400702 const ankr &ankr_table;
Behdad Esfahbod1622ba52018-10-11 01:14:18 -0400703 const char *ankr_end;
Behdad Esfahbod046690a2018-01-17 16:59:55 -0800704
Behdad Esfahbod126ffdb2018-02-07 12:26:41 -0500705 /* Unused. For debug tracing only. */
706 unsigned int lookup_index;
707 unsigned int debug_depth;
708
Behdad Esfahbod53e55942018-10-09 22:35:22 -0400709 inline hb_aat_apply_context_t (hb_ot_shape_plan_t *plan_,
710 hb_font_t *font_,
Behdad Esfahbodf07ce662018-01-19 16:52:01 -0800711 hb_buffer_t *buffer_,
Behdad Esfahbodd6a12db2018-10-11 11:10:06 -0400712 hb_blob_t *blob = const_cast<hb_blob_t *> (&Null(hb_blob_t)),
Behdad Esfahbod1622ba52018-10-11 01:14:18 -0400713 const ankr &ankr_table_ = Null(ankr),
714 const char *ankr_end_ = nullptr) :
Behdad Esfahbod53e55942018-10-09 22:35:22 -0400715 plan (plan_), font (font_), face (font->face), buffer (buffer_),
Behdad Esfahbod1622ba52018-10-11 01:14:18 -0400716 sanitizer (),
717 ankr_table (ankr_table_), ankr_end (ankr_end_),
718 lookup_index (0), debug_depth (0)
Behdad Esfahbodf07ce662018-01-19 16:52:01 -0800719 {
Behdad Esfahbodd6a12db2018-10-11 11:10:06 -0400720 sanitizer.init (blob);
Behdad Esfahbodbe707382018-07-17 18:45:25 +0200721 sanitizer.set_num_glyphs (face->get_num_glyphs ());
Behdad Esfahbodf07ce662018-01-19 16:52:01 -0800722 sanitizer.start_processing ();
Behdad Esfahbodd35315c2018-10-09 23:17:32 -0400723 sanitizer.set_max_ops (HB_SANITIZE_MAX_OPS_MAX);
Behdad Esfahbodf07ce662018-01-19 16:52:01 -0800724 }
725
Behdad Esfahbodee433d32018-02-07 12:30:18 -0500726 inline void set_lookup_index (unsigned int i) { lookup_index = i; }
727
Behdad Esfahbodf07ce662018-01-19 16:52:01 -0800728 inline ~hb_aat_apply_context_t (void)
729 {
730 sanitizer.end_processing ();
731 }
Behdad Esfahbod046690a2018-01-17 16:59:55 -0800732};
733
734
Behdad Esfahboda0175e72017-08-17 16:55:54 -0700735} /* namespace AAT */
736
737
Behdad Esfahbodc77ae402018-08-25 22:36:36 -0700738#endif /* HB_AAT_LAYOUT_COMMON_HH */