blob: 47efb4910b4c8f33b9774cdd9eefe16e27fabbd5 [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 Esfahbod7c7cb422018-01-08 14:32:55 +000051 UINT16 unitSize; /* Size of a lookup unit for this search in bytes. */
52 UINT16 nUnits; /* Number of units of the preceding size to be searched. */
53 UINT16 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 Esfahbod7c7cb422018-01-08 14:32:55 +000055 UINT16 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 Esfahbod7c7cb422018-01-08 14:32:55 +000057 UINT16 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 Esfahbod7c7cb422018-01-08 14:32:55 +0000137 UINT8 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);
154
155 /* Note: for structs that do not reference other structs,
156 * we do not need to call their sanitize() as we already did
157 * a bound check on the aggregate array size. We just include
158 * a small unreachable expression to make sure the structs
159 * pointed to do have a simple sanitize(), ie. they do not
160 * reference other structs via offsets.
161 */
162 (void) (false && count && arrayZ->sanitize (c));
163
164 return_trace (c->check_array (arrayZ, arrayZ[0].static_size, count));
165 }
166
167 protected:
168 Type arrayZ[VAR];
169 public:
170 DEFINE_SIZE_ARRAY (0, arrayZ);
171};
172
173
174/*
175 * Lookup Table
176 */
177
178template <typename T> struct Lookup;
179
180template <typename T>
181struct LookupFormat0
182{
183 friend struct Lookup<T>;
184
185 private:
Behdad Esfahbod748b9892018-01-09 17:55:17 +0100186 inline const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100187 {
Behdad Esfahbod748b9892018-01-09 17:55:17 +0100188 if (unlikely (glyph_id >= num_glyphs)) return nullptr;
189 return &arrayZ[glyph_id];
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100190 }
191
192 inline bool sanitize (hb_sanitize_context_t *c) const
193 {
194 TRACE_SANITIZE (this);
195 return_trace (arrayZ.sanitize (c, c->num_glyphs));
196 }
197
198 protected:
199 UINT16 format; /* Format identifier--format = 0 */
200 UnsizedArrayOf<T>
201 arrayZ; /* Array of lookup values, indexed by glyph index. */
202 public:
203 DEFINE_SIZE_ARRAY (2, arrayZ);
204};
205
206
207template <typename T>
208struct LookupSegmentSingle
209{
210 inline int cmp (hb_codepoint_t g) const {
211 return g < first ? -1 : g <= last ? 0 : +1 ;
212 }
213
214 inline bool sanitize (hb_sanitize_context_t *c) const
215 {
216 TRACE_SANITIZE (this);
217 return_trace (c->check_struct (this) && value.sanitize (c));
218 }
219
220 GlyphID last; /* Last GlyphID in this segment */
221 GlyphID first; /* First GlyphID in this segment */
222 T value; /* The lookup value (only one) */
223 public:
224 DEFINE_SIZE_STATIC (4 + sizeof (T));
225};
226
227template <typename T>
228struct LookupFormat2
229{
230 friend struct Lookup<T>;
231
232 private:
Behdad Esfahbod748b9892018-01-09 17:55:17 +0100233 inline const T* get_value (hb_codepoint_t glyph_id) const
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100234 {
235 const LookupSegmentSingle<T> *v = segments.bsearch (glyph_id);
Behdad Esfahbod748b9892018-01-09 17:55:17 +0100236 return v ? &v->value : nullptr;
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100237 }
238
239 inline bool sanitize (hb_sanitize_context_t *c) const
240 {
241 TRACE_SANITIZE (this);
242 return_trace (segments.sanitize (c));
243 }
244
245 protected:
246 UINT16 format; /* Format identifier--format = 2 */
247 BinSearchArrayOf<LookupSegmentSingle<T> >
248 segments; /* The actual segments. These must already be sorted,
249 * according to the first word in each one (the last
250 * glyph in each segment). */
251 public:
252 DEFINE_SIZE_ARRAY (8, segments);
253};
254
255template <typename T>
256struct LookupSegmentArray
257{
Behdad Esfahbod748b9892018-01-09 17:55:17 +0100258 inline const T* get_value (hb_codepoint_t glyph_id, const void *base) const
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100259 {
Behdad Esfahbod748b9892018-01-09 17:55:17 +0100260 return first <= glyph_id && glyph_id <= last ? &(base+valuesZ)[glyph_id - first] : nullptr;
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100261 }
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 void *base) const
268 {
269 TRACE_SANITIZE (this);
270 return_trace (c->check_struct (this) &&
271 first <= last &&
272 valuesZ.sanitize (c, base, last - first + 1));
273 }
274
275 GlyphID last; /* Last GlyphID in this segment */
276 GlyphID first; /* First GlyphID in this segment */
277 OffsetTo<UnsizedArrayOf<T> >
278 valuesZ; /* A 16-bit offset from the start of
279 * the table to the data. */
280 public:
281 DEFINE_SIZE_STATIC (6);
282};
283
284template <typename T>
285struct LookupFormat4
286{
287 friend struct Lookup<T>;
288
289 private:
Behdad Esfahbod748b9892018-01-09 17:55:17 +0100290 inline const T* get_value (hb_codepoint_t glyph_id) const
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100291 {
292 const LookupSegmentArray<T> *v = segments.bsearch (glyph_id);
Behdad Esfahbod748b9892018-01-09 17:55:17 +0100293 return v ? v->get_value (glyph_id, this) : nullptr;
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100294 }
295
296 inline bool sanitize (hb_sanitize_context_t *c) const
297 {
298 TRACE_SANITIZE (this);
299 return_trace (segments.sanitize (c, this));
300 }
301
302 protected:
303 UINT16 format; /* Format identifier--format = 2 */
304 BinSearchArrayOf<LookupSegmentArray<T> >
305 segments; /* The actual segments. These must already be sorted,
306 * according to the first word in each one (the last
307 * glyph in each segment). */
308 public:
309 DEFINE_SIZE_ARRAY (8, segments);
310};
311
312template <typename T>
313struct LookupSingle
314{
315 inline int cmp (hb_codepoint_t g) const { return glyph.cmp (g); }
316
317 inline bool sanitize (hb_sanitize_context_t *c) const
318 {
319 TRACE_SANITIZE (this);
320 return_trace (c->check_struct (this) && value.sanitize (c));
321 }
322
323 GlyphID glyph; /* Last GlyphID */
324 T value; /* The lookup value (only one) */
325 public:
326 DEFINE_SIZE_STATIC (4 + sizeof (T));
327};
328
329template <typename T>
330struct LookupFormat6
331{
332 friend struct Lookup<T>;
333
334 private:
Behdad Esfahbod748b9892018-01-09 17:55:17 +0100335 inline const T* get_value (hb_codepoint_t glyph_id) const
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100336 {
337 const LookupSingle<T> *v = entries.bsearch (glyph_id);
Behdad Esfahbod748b9892018-01-09 17:55:17 +0100338 return v ? &v->value : nullptr;
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100339 }
340
341 inline bool sanitize (hb_sanitize_context_t *c) const
342 {
343 TRACE_SANITIZE (this);
344 return_trace (entries.sanitize (c));
345 }
346
347 protected:
348 UINT16 format; /* Format identifier--format = 6 */
349 BinSearchArrayOf<LookupSingle<T> >
350 entries; /* The actual entries, sorted by glyph index. */
351 public:
352 DEFINE_SIZE_ARRAY (8, entries);
353};
354
355template <typename T>
356struct LookupFormat8
357{
358 friend struct Lookup<T>;
359
360 private:
Behdad Esfahbod748b9892018-01-09 17:55:17 +0100361 inline const T* get_value (hb_codepoint_t glyph_id) const
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100362 {
Behdad Esfahbod748b9892018-01-09 17:55:17 +0100363 return firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount ? &valueArrayZ[glyph_id - firstGlyph] : nullptr;
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100364 }
365
366 inline bool sanitize (hb_sanitize_context_t *c) const
367 {
368 TRACE_SANITIZE (this);
369 return_trace (c->check_struct (this) && valueArrayZ.sanitize (c, glyphCount));
370 }
371
372 protected:
373 UINT16 format; /* Format identifier--format = 6 */
374 GlyphID firstGlyph; /* First glyph index included in the trimmed array. */
375 UINT16 glyphCount; /* Total number of glyphs (equivalent to the last
376 * glyph minus the value of firstGlyph plus 1). */
377 UnsizedArrayOf<T>
378 valueArrayZ; /* The lookup values (indexed by the glyph index
379 * minus the value of firstGlyph). */
380 public:
381 DEFINE_SIZE_ARRAY (6, valueArrayZ);
382};
383
384template <typename T>
385struct Lookup
386{
Behdad Esfahbod748b9892018-01-09 17:55:17 +0100387 inline const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100388 {
389 switch (u.format) {
390 case 0: return u.format0.get_value (glyph_id, num_glyphs);
391 case 2: return u.format2.get_value (glyph_id);
392 case 4: return u.format4.get_value (glyph_id);
393 case 6: return u.format6.get_value (glyph_id);
394 case 8: return u.format8.get_value (glyph_id);
Behdad Esfahbod748b9892018-01-09 17:55:17 +0100395 default:return nullptr;
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100396 }
397 }
398
399 inline bool sanitize (hb_sanitize_context_t *c) const
400 {
401 TRACE_SANITIZE (this);
402 if (!u.format.sanitize (c)) return_trace (false);
403 switch (u.format) {
404 case 0: return_trace (u.format0.sanitize (c));
405 case 2: return_trace (u.format2.sanitize (c));
406 case 4: return_trace (u.format4.sanitize (c));
407 case 6: return_trace (u.format6.sanitize (c));
408 case 8: return_trace (u.format8.sanitize (c));
409 default:return_trace (true);
410 }
411 }
412
413 protected:
414 union {
415 UINT16 format; /* Format identifier */
416 LookupFormat0<T> format0;
417 LookupFormat2<T> format2;
418 LookupFormat4<T> format4;
419 LookupFormat6<T> format6;
420 LookupFormat8<T> format8;
421 } u;
422 public:
423 DEFINE_SIZE_UNION (2, format);
424};
425
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100426
Behdad Esfahboda0175e72017-08-17 16:55:54 -0700427} /* namespace AAT */
428
429
430#endif /* HB_AAT_LAYOUT_COMMON_PRIVATE_HH */