1/*
2 * Copyright © 2007,2008,2009,2010 Red Hat, Inc.
3 * Copyright © 2012 Google, Inc.
4 *
5 * This is part of HarfBuzz, a text shaping library.
6 *
7 * Permission is hereby granted, without written agreement and without
8 * license or royalty fees, to use, copy, modify, and distribute this
9 * software and its documentation for any purpose, provided that the
10 * above copyright notice and the following two paragraphs appear in
11 * all copies of this software.
12 *
13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17 * DAMAGE.
18 *
19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24 *
25 * Red Hat Author(s): Behdad Esfahbod
26 * Google Author(s): Behdad Esfahbod
27 */
28
29#ifndef HB_OPEN_TYPE_HH
30#define HB_OPEN_TYPE_HH
31
32#include "hb.hh"
33#include "hb-blob.hh"
34#include "hb-face.hh"
35#include "hb-machinery.hh"
36#include "hb-meta.hh"
37#include "hb-subset.hh"
38
39
40namespace OT {
41
42
43/*
44 *
45 * The OpenType Font File: Data Types
46 */
47
48
49/* "The following data types are used in the OpenType font file.
50 * All OpenType fonts use Motorola-style byte ordering (Big Endian):" */
51
52/*
53 * Int types
54 */
55
56/* Integer types in big-endian order and no alignment requirement */
57template <typename Type,
58 unsigned int Size = sizeof (Type)>
59struct IntType
60{
61 typedef Type type;
62
63 IntType () = default;
64 explicit constexpr IntType (Type V) : v {V} {}
65 IntType& operator = (Type i) { v = i; return *this; }
66 /* For reason we define cast out operator for signed/unsigned, instead of Type, see:
67 * https://github.com/harfbuzz/harfbuzz/pull/2875/commits/09836013995cab2b9f07577a179ad7b024130467 */
68 operator typename std::conditional<std::is_signed<Type>::value, signed, unsigned>::type () const { return v; }
69
70 bool operator == (const IntType &o) const { return (Type) v == (Type) o.v; }
71 bool operator != (const IntType &o) const { return !(*this == o); }
72
73 IntType& operator += (unsigned count) { *this = *this + count; return *this; }
74 IntType& operator -= (unsigned count) { *this = *this - count; return *this; }
75 IntType& operator ++ () { *this += 1; return *this; }
76 IntType& operator -- () { *this -= 1; return *this; }
77 IntType operator ++ (int) { IntType c (*this); ++*this; return c; }
78 IntType operator -- (int) { IntType c (*this); --*this; return c; }
79
80 HB_INTERNAL static int cmp (const IntType *a, const IntType *b)
81 { return b->cmp (*a); }
82 HB_INTERNAL static int cmp (const void *a, const void *b)
83 {
84 IntType *pa = (IntType *) a;
85 IntType *pb = (IntType *) b;
86
87 return pb->cmp (*pa);
88 }
89 template <typename Type2,
90 hb_enable_if (std::is_integral<Type2>::value &&
91 sizeof (Type2) < sizeof (int) &&
92 sizeof (Type) < sizeof (int))>
93 int cmp (Type2 a) const
94 {
95 Type b = v;
96 return (int) a - (int) b;
97 }
98 template <typename Type2,
99 hb_enable_if (hb_is_convertible (Type2, Type))>
100 int cmp (Type2 a) const
101 {
102 Type b = v;
103 return a < b ? -1 : a == b ? 0 : +1;
104 }
105 bool sanitize (hb_sanitize_context_t *c) const
106 {
107 TRACE_SANITIZE (this);
108 return_trace (c->check_struct (this));
109 }
110 protected:
111 BEInt<Type, Size> v;
112 public:
113 DEFINE_SIZE_STATIC (Size);
114};
115
116typedef IntType<uint8_t> HBUINT8; /* 8-bit unsigned integer. */
117typedef IntType<int8_t> HBINT8; /* 8-bit signed integer. */
118typedef IntType<uint16_t> HBUINT16; /* 16-bit unsigned integer. */
119typedef IntType<int16_t> HBINT16; /* 16-bit signed integer. */
120typedef IntType<uint32_t> HBUINT32; /* 32-bit unsigned integer. */
121typedef IntType<int32_t> HBINT32; /* 32-bit signed integer. */
122/* Note: we cannot defined a signed HBINT24 because there's no corresponding C type.
123 * Works for unsigned, but not signed, since we rely on compiler for sign-extension. */
124typedef IntType<uint32_t, 3> HBUINT24; /* 24-bit unsigned integer. */
125
126/* 15-bit unsigned number; top bit used for extension. */
127struct HBUINT15 : HBUINT16
128{
129 /* TODO Flesh out; actually mask top bit. */
130 HBUINT15& operator = (uint16_t i ) { HBUINT16::operator= (i); return *this; }
131 public:
132 DEFINE_SIZE_STATIC (2);
133};
134
135/* 16-bit signed integer (HBINT16) that describes a quantity in FUnits. */
136typedef HBINT16 FWORD;
137
138/* 32-bit signed integer (HBINT32) that describes a quantity in FUnits. */
139typedef HBINT32 FWORD32;
140
141/* 16-bit unsigned integer (HBUINT16) that describes a quantity in FUnits. */
142typedef HBUINT16 UFWORD;
143
144template <typename Type, unsigned fraction_bits>
145struct HBFixed : Type
146{
147 static constexpr float shift = (float) (1 << fraction_bits);
148 static_assert (Type::static_size * 8 > fraction_bits, "");
149
150 operator signed () const = delete;
151 operator unsigned () const = delete;
152 typename Type::type to_int () const { return Type::v; }
153 void set_int (typename Type::type i ) { Type::v = i; }
154 float to_float (float offset = 0) const { return ((int32_t) Type::v + offset) / shift; }
155 void set_float (float f) { Type::v = roundf (f * shift); }
156 public:
157 DEFINE_SIZE_STATIC (Type::static_size);
158};
159
160/* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */
161using F2DOT14 = HBFixed<HBINT16, 14>;
162using F4DOT12 = HBFixed<HBINT16, 12>;
163using F6DOT10 = HBFixed<HBINT16, 10>;
164
165/* 32-bit signed fixed-point number (16.16). */
166using F16DOT16 = HBFixed<HBINT32, 16>;
167
168/* Date represented in number of seconds since 12:00 midnight, January 1,
169 * 1904. The value is represented as a signed 64-bit integer. */
170struct LONGDATETIME
171{
172 bool sanitize (hb_sanitize_context_t *c) const
173 {
174 TRACE_SANITIZE (this);
175 return_trace (c->check_struct (this));
176 }
177 protected:
178 HBINT32 major;
179 HBUINT32 minor;
180 public:
181 DEFINE_SIZE_STATIC (8);
182};
183
184/* Array of four uint8s (length = 32 bits) used to identify a script, language
185 * system, feature, or baseline */
186struct Tag : HBUINT32
187{
188 Tag& operator = (hb_tag_t i) { HBUINT32::operator= (i); return *this; }
189 /* What the char* converters return is NOT nul-terminated. Print using "%.4s" */
190 operator const char* () const { return reinterpret_cast<const char *> (this); }
191 operator char* () { return reinterpret_cast<char *> (this); }
192 public:
193 DEFINE_SIZE_STATIC (4);
194};
195
196/* Glyph index number, same as uint16 (length = 16 bits) */
197struct HBGlyphID16 : HBUINT16
198{
199 HBGlyphID16& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; }
200};
201struct HBGlyphID24 : HBUINT24
202{
203 HBGlyphID24& operator = (uint32_t i) { HBUINT24::operator= (i); return *this; }
204};
205
206/* Script/language-system/feature index */
207struct Index : HBUINT16 {
208 static constexpr unsigned NOT_FOUND_INDEX = 0xFFFFu;
209 Index& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; }
210};
211DECLARE_NULL_NAMESPACE_BYTES (OT, Index);
212
213typedef Index NameID;
214
215struct VarIdx : HBUINT32 {
216 static constexpr unsigned NO_VARIATION = 0xFFFFFFFFu;
217 static_assert (NO_VARIATION == HB_OT_LAYOUT_NO_VARIATIONS_INDEX, "");
218 static uint32_t add (uint32_t i, unsigned short v)
219 {
220 if (i == NO_VARIATION) return i;
221 return i + v;
222 }
223 VarIdx& operator = (uint32_t i) { HBUINT32::operator= (i); return *this; }
224};
225DECLARE_NULL_NAMESPACE_BYTES (OT, VarIdx);
226
227/* Offset, Null offset = 0 */
228template <typename Type, bool has_null=true>
229struct Offset : Type
230{
231 Offset& operator = (typename Type::type i) { Type::operator= (i); return *this; }
232
233 typedef Type type;
234
235 bool is_null () const { return has_null && 0 == *this; }
236
237 public:
238 DEFINE_SIZE_STATIC (sizeof (Type));
239};
240
241typedef Offset<HBUINT16> Offset16;
242typedef Offset<HBUINT24> Offset24;
243typedef Offset<HBUINT32> Offset32;
244
245
246/* CheckSum */
247struct CheckSum : HBUINT32
248{
249 CheckSum& operator = (uint32_t i) { HBUINT32::operator= (i); return *this; }
250
251 /* This is reference implementation from the spec. */
252 static uint32_t CalcTableChecksum (const HBUINT32 *Table, uint32_t Length)
253 {
254 uint32_t Sum = 0L;
255 assert (0 == (Length & 3));
256 const HBUINT32 *EndPtr = Table + Length / HBUINT32::static_size;
257
258 while (Table < EndPtr)
259 Sum += *Table++;
260 return Sum;
261 }
262
263 /* Note: data should be 4byte aligned and have 4byte padding at the end. */
264 void set_for_data (const void *data, unsigned int length)
265 { *this = CalcTableChecksum ((const HBUINT32 *) data, length); }
266
267 public:
268 DEFINE_SIZE_STATIC (4);
269};
270
271
272/*
273 * Version Numbers
274 */
275
276template <typename FixedType=HBUINT16>
277struct FixedVersion
278{
279 uint32_t to_int () const { return (major << (sizeof (FixedType) * 8)) + minor; }
280
281 bool sanitize (hb_sanitize_context_t *c) const
282 {
283 TRACE_SANITIZE (this);
284 return_trace (c->check_struct (this));
285 }
286
287 FixedType major;
288 FixedType minor;
289 public:
290 DEFINE_SIZE_STATIC (2 * sizeof (FixedType));
291};
292
293
294/*
295 * Template subclasses of Offset that do the dereferencing.
296 * Use: (base+offset)
297 */
298
299template <typename Type, bool has_null>
300struct _hb_has_null
301{
302 static const Type *get_null () { return nullptr; }
303 static Type *get_crap () { return nullptr; }
304};
305template <typename Type>
306struct _hb_has_null<Type, true>
307{
308 static const Type *get_null () { return &Null (Type); }
309 static Type *get_crap () { return &Crap (Type); }
310};
311
312template <typename Type, typename OffsetType, bool has_null=true>
313struct OffsetTo : Offset<OffsetType, has_null>
314{
315 using target_t = Type;
316
317 // Make sure Type is not unbounded; works only for types that are fully defined at OffsetTo time.
318 static_assert (has_null == false ||
319 (hb_has_null_size (Type) || !hb_has_min_size (Type)), "");
320
321 HB_DELETE_COPY_ASSIGN (OffsetTo);
322 OffsetTo () = default;
323
324 OffsetTo& operator = (typename OffsetType::type i) { OffsetType::operator= (i); return *this; }
325
326 const Type& operator () (const void *base) const
327 {
328 if (unlikely (this->is_null ())) return *_hb_has_null<Type, has_null>::get_null ();
329 return StructAtOffset<const Type> (base, *this);
330 }
331 Type& operator () (void *base) const
332 {
333 if (unlikely (this->is_null ())) return *_hb_has_null<Type, has_null>::get_crap ();
334 return StructAtOffset<Type> (base, *this);
335 }
336
337 template <typename Base,
338 hb_enable_if (hb_is_convertible (const Base, const void *))>
339 friend const Type& operator + (const Base &base, const OffsetTo &offset) { return offset ((const void *) base); }
340 template <typename Base,
341 hb_enable_if (hb_is_convertible (const Base, const void *))>
342 friend const Type& operator + (const OffsetTo &offset, const Base &base) { return offset ((const void *) base); }
343 template <typename Base,
344 hb_enable_if (hb_is_convertible (Base, void *))>
345 friend Type& operator + (Base &&base, OffsetTo &offset) { return offset ((void *) base); }
346 template <typename Base,
347 hb_enable_if (hb_is_convertible (Base, void *))>
348 friend Type& operator + (OffsetTo &offset, Base &&base) { return offset ((void *) base); }
349
350
351 template <typename ...Ts>
352 bool serialize_subset (hb_subset_context_t *c, const OffsetTo& src,
353 const void *src_base, Ts&&... ds)
354 {
355 *this = 0;
356 if (src.is_null ())
357 return false;
358
359 auto *s = c->serializer;
360
361 s->push ();
362
363 bool ret = c->dispatch (src_base+src, std::forward<Ts> (ds)...);
364
365 if (ret || !has_null)
366 s->add_link (*this, s->pop_pack ());
367 else
368 s->pop_discard ();
369
370 return ret;
371 }
372
373
374 template <typename ...Ts>
375 bool serialize_serialize (hb_serialize_context_t *c, Ts&&... ds)
376 {
377 *this = 0;
378
379 Type* obj = c->push<Type> ();
380 bool ret = obj->serialize (c, std::forward<Ts> (ds)...);
381
382 if (ret)
383 c->add_link (*this, c->pop_pack ());
384 else
385 c->pop_discard ();
386
387 return ret;
388 }
389
390 /* TODO: Somehow merge this with previous function into a serialize_dispatch(). */
391 /* Workaround clang bug: https://bugs.llvm.org/show_bug.cgi?id=23029
392 * Can't compile: whence = hb_serialize_context_t::Head followed by Ts&&...
393 */
394 template <typename ...Ts>
395 bool serialize_copy (hb_serialize_context_t *c, const OffsetTo& src,
396 const void *src_base, unsigned dst_bias,
397 hb_serialize_context_t::whence_t whence,
398 Ts&&... ds)
399 {
400 *this = 0;
401 if (src.is_null ())
402 return false;
403
404 c->push ();
405
406 bool ret = c->copy (src_base+src, std::forward<Ts> (ds)...);
407
408 c->add_link (*this, c->pop_pack (), whence, dst_bias);
409
410 return ret;
411 }
412
413 bool serialize_copy (hb_serialize_context_t *c, const OffsetTo& src,
414 const void *src_base, unsigned dst_bias = 0)
415 { return serialize_copy (c, src, src_base, dst_bias, hb_serialize_context_t::Head); }
416
417 bool sanitize_shallow (hb_sanitize_context_t *c, const void *base) const
418 {
419 TRACE_SANITIZE (this);
420 if (unlikely (!c->check_struct (this))) return_trace (false);
421 //if (unlikely (this->is_null ())) return_trace (true);
422 if (unlikely ((const char *) base + (unsigned) *this < (const char *) base)) return_trace (false);
423 return_trace (true);
424 }
425
426 template <typename ...Ts>
427#ifndef HB_OPTIMIZE_SIZE
428 HB_ALWAYS_INLINE
429#endif
430 bool sanitize (hb_sanitize_context_t *c, const void *base, Ts&&... ds) const
431 {
432 TRACE_SANITIZE (this);
433 return_trace (sanitize_shallow (c, base) &&
434 (this->is_null () ||
435 c->dispatch (StructAtOffset<Type> (base, *this), std::forward<Ts> (ds)...) ||
436 neuter (c)));
437 }
438
439 /* Set the offset to Null */
440 bool neuter (hb_sanitize_context_t *c) const
441 {
442 if (!has_null) return false;
443 return c->try_set (this, 0);
444 }
445 DEFINE_SIZE_STATIC (sizeof (OffsetType));
446};
447/* Partial specializations. */
448template <typename Type, bool has_null=true> using Offset16To = OffsetTo<Type, HBUINT16, has_null>;
449template <typename Type, bool has_null=true> using Offset24To = OffsetTo<Type, HBUINT24, has_null>;
450template <typename Type, bool has_null=true> using Offset32To = OffsetTo<Type, HBUINT32, has_null>;
451
452template <typename Type, typename OffsetType> using NNOffsetTo = OffsetTo<Type, OffsetType, false>;
453template <typename Type> using NNOffset16To = Offset16To<Type, false>;
454template <typename Type> using NNOffset24To = Offset24To<Type, false>;
455template <typename Type> using NNOffset32To = Offset32To<Type, false>;
456
457
458/*
459 * Array Types
460 */
461
462template <typename Type>
463struct UnsizedArrayOf
464{
465 typedef Type item_t;
466 static constexpr unsigned item_size = hb_static_size (Type);
467
468 HB_DELETE_CREATE_COPY_ASSIGN (UnsizedArrayOf);
469
470 const Type& operator [] (unsigned int i) const
471 {
472 return arrayZ[i];
473 }
474 Type& operator [] (unsigned int i)
475 {
476 return arrayZ[i];
477 }
478
479 static unsigned int get_size (unsigned int len)
480 { return len * Type::static_size; }
481
482 template <typename T> operator T * () { return arrayZ; }
483 template <typename T> operator const T * () const { return arrayZ; }
484 hb_array_t<Type> as_array (unsigned int len)
485 { return hb_array (arrayZ, len); }
486 hb_array_t<const Type> as_array (unsigned int len) const
487 { return hb_array (arrayZ, len); }
488
489 template <typename T>
490 Type &lsearch (unsigned int len, const T &x, Type &not_found = Crap (Type))
491 { return *as_array (len).lsearch (x, &not_found); }
492 template <typename T>
493 const Type &lsearch (unsigned int len, const T &x, const Type &not_found = Null (Type)) const
494 { return *as_array (len).lsearch (x, &not_found); }
495 template <typename T>
496 bool lfind (unsigned int len, const T &x, unsigned int *i = nullptr,
497 hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE,
498 unsigned int to_store = (unsigned int) -1) const
499 { return as_array (len).lfind (x, i, not_found, to_store); }
500
501 void qsort (unsigned int len, unsigned int start = 0, unsigned int end = (unsigned int) -1)
502 { as_array (len).qsort (start, end); }
503
504 bool serialize (hb_serialize_context_t *c, unsigned int items_len, bool clear = true)
505 {
506 TRACE_SERIALIZE (this);
507 if (unlikely (!c->extend_size (this, get_size (items_len), clear))) return_trace (false);
508 return_trace (true);
509 }
510 template <typename Iterator,
511 hb_requires (hb_is_source_of (Iterator, Type))>
512 bool serialize (hb_serialize_context_t *c, Iterator items)
513 {
514 TRACE_SERIALIZE (this);
515 unsigned count = hb_len (items);
516 if (unlikely (!serialize (c, count, false))) return_trace (false);
517 /* TODO Umm. Just exhaust the iterator instead? Being extra
518 * cautious right now.. */
519 for (unsigned i = 0; i < count; i++, ++items)
520 arrayZ[i] = *items;
521 return_trace (true);
522 }
523
524 UnsizedArrayOf* copy (hb_serialize_context_t *c, unsigned count) const
525 {
526 TRACE_SERIALIZE (this);
527 auto *out = c->start_embed (this);
528 if (unlikely (!as_array (count).copy (c))) return_trace (nullptr);
529 return_trace (out);
530 }
531
532 template <typename ...Ts>
533 HB_ALWAYS_INLINE
534 bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const
535 {
536 TRACE_SANITIZE (this);
537 if (unlikely (!sanitize_shallow (c, count))) return_trace (false);
538 if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true);
539 for (unsigned int i = 0; i < count; i++)
540 if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...)))
541 return_trace (false);
542 return_trace (true);
543 }
544
545 bool sanitize_shallow (hb_sanitize_context_t *c, unsigned int count) const
546 {
547 TRACE_SANITIZE (this);
548 return_trace (c->check_array (arrayZ, count));
549 }
550
551 public:
552 Type arrayZ[HB_VAR_ARRAY];
553 public:
554 DEFINE_SIZE_UNBOUNDED (0);
555};
556
557/* Unsized array of offset's */
558template <typename Type, typename OffsetType, bool has_null=true>
559using UnsizedArray16OfOffsetTo = UnsizedArrayOf<OffsetTo<Type, OffsetType, has_null>>;
560
561/* Unsized array of offsets relative to the beginning of the array itself. */
562template <typename Type, typename OffsetType, bool has_null=true>
563struct UnsizedListOfOffset16To : UnsizedArray16OfOffsetTo<Type, OffsetType, has_null>
564{
565 const Type& operator [] (int i_) const
566 {
567 unsigned int i = (unsigned int) i_;
568 const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i];
569 if (unlikely ((const void *) p < (const void *) this->arrayZ)) return Null (Type); /* Overflowed. */
570 _hb_compiler_memory_r_barrier ();
571 return this+*p;
572 }
573 Type& operator [] (int i_)
574 {
575 unsigned int i = (unsigned int) i_;
576 const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i];
577 if (unlikely ((const void *) p < (const void *) this->arrayZ)) return Crap (Type); /* Overflowed. */
578 _hb_compiler_memory_r_barrier ();
579 return this+*p;
580 }
581
582 template <typename ...Ts>
583 bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const
584 {
585 TRACE_SANITIZE (this);
586 return_trace ((UnsizedArray16OfOffsetTo<Type, OffsetType, has_null>
587 ::sanitize (c, count, this, std::forward<Ts> (ds)...)));
588 }
589};
590
591/* An array with sorted elements. Supports binary searching. */
592template <typename Type>
593struct SortedUnsizedArrayOf : UnsizedArrayOf<Type>
594{
595 hb_sorted_array_t<Type> as_array (unsigned int len)
596 { return hb_sorted_array (this->arrayZ, len); }
597 hb_sorted_array_t<const Type> as_array (unsigned int len) const
598 { return hb_sorted_array (this->arrayZ, len); }
599 operator hb_sorted_array_t<Type> () { return as_array (); }
600 operator hb_sorted_array_t<const Type> () const { return as_array (); }
601
602 template <typename T>
603 Type &bsearch (unsigned int len, const T &x, Type &not_found = Crap (Type))
604 { return *as_array (len).bsearch (x, &not_found); }
605 template <typename T>
606 const Type &bsearch (unsigned int len, const T &x, const Type &not_found = Null (Type)) const
607 { return *as_array (len).bsearch (x, &not_found); }
608 template <typename T>
609 bool bfind (unsigned int len, const T &x, unsigned int *i = nullptr,
610 hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE,
611 unsigned int to_store = (unsigned int) -1) const
612 { return as_array (len).bfind (x, i, not_found, to_store); }
613};
614
615
616/* An array with a number of elements. */
617template <typename Type, typename LenType>
618struct ArrayOf
619{
620 typedef Type item_t;
621 static constexpr unsigned item_size = hb_static_size (Type);
622
623 HB_DELETE_CREATE_COPY_ASSIGN (ArrayOf);
624
625 const Type& operator [] (int i_) const
626 {
627 unsigned int i = (unsigned int) i_;
628 if (unlikely (i >= len)) return Null (Type);
629 _hb_compiler_memory_r_barrier ();
630 return arrayZ[i];
631 }
632 Type& operator [] (int i_)
633 {
634 unsigned int i = (unsigned int) i_;
635 if (unlikely (i >= len)) return Crap (Type);
636 _hb_compiler_memory_r_barrier ();
637 return arrayZ[i];
638 }
639
640 unsigned int get_size () const
641 { return len.static_size + len * Type::static_size; }
642
643 explicit operator bool () const { return len; }
644
645 void pop () { len--; }
646
647 hb_array_t< Type> as_array () { return hb_array (arrayZ, len); }
648 hb_array_t<const Type> as_array () const { return hb_array (arrayZ, len); }
649
650 /* Iterator. */
651 typedef hb_array_t<const Type> iter_t;
652 typedef hb_array_t< Type> writer_t;
653 iter_t iter () const { return as_array (); }
654 writer_t writer () { return as_array (); }
655 operator iter_t () const { return iter (); }
656 operator writer_t () { return writer (); }
657
658 /* Faster range-based for loop. */
659 const Type *begin () const { return arrayZ; }
660 const Type *end () const { return arrayZ + len; }
661
662 template <typename T>
663 Type &lsearch (const T &x, Type &not_found = Crap (Type))
664 { return *as_array ().lsearch (x, &not_found); }
665 template <typename T>
666 const Type &lsearch (const T &x, const Type &not_found = Null (Type)) const
667 { return *as_array ().lsearch (x, &not_found); }
668 template <typename T>
669 bool lfind (const T &x, unsigned int *i = nullptr,
670 hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE,
671 unsigned int to_store = (unsigned int) -1) const
672 { return as_array ().lfind (x, i, not_found, to_store); }
673
674 void qsort ()
675 { as_array ().qsort (); }
676
677 HB_NODISCARD bool serialize (hb_serialize_context_t *c, unsigned items_len, bool clear = true)
678 {
679 TRACE_SERIALIZE (this);
680 if (unlikely (!c->extend_min (this))) return_trace (false);
681 c->check_assign (len, items_len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW);
682 if (unlikely (!c->extend_size (this, get_size (), clear))) return_trace (false);
683 return_trace (true);
684 }
685 template <typename Iterator,
686 hb_requires (hb_is_source_of (Iterator, Type))>
687 HB_NODISCARD bool serialize (hb_serialize_context_t *c, Iterator items)
688 {
689 TRACE_SERIALIZE (this);
690 unsigned count = hb_len (items);
691 if (unlikely (!serialize (c, count, false))) return_trace (false);
692 /* TODO Umm. Just exhaust the iterator instead? Being extra
693 * cautious right now.. */
694 for (unsigned i = 0; i < count; i++, ++items)
695 arrayZ[i] = *items;
696 return_trace (true);
697 }
698
699 Type* serialize_append (hb_serialize_context_t *c)
700 {
701 TRACE_SERIALIZE (this);
702 len++;
703 if (unlikely (!len || !c->extend (this)))
704 {
705 len--;
706 return_trace (nullptr);
707 }
708 return_trace (&arrayZ[len - 1]);
709 }
710
711 ArrayOf* copy (hb_serialize_context_t *c) const
712 {
713 TRACE_SERIALIZE (this);
714 auto *out = c->start_embed (this);
715 if (unlikely (!c->extend_min (out))) return_trace (nullptr);
716 c->check_assign (out->len, len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW);
717 if (unlikely (!as_array ().copy (c))) return_trace (nullptr);
718 return_trace (out);
719 }
720
721 template <typename ...Ts>
722 HB_ALWAYS_INLINE
723 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
724 {
725 TRACE_SANITIZE (this);
726 if (unlikely (!sanitize_shallow (c))) return_trace (false);
727 if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true);
728 unsigned int count = len;
729 for (unsigned int i = 0; i < count; i++)
730 if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...)))
731 return_trace (false);
732 return_trace (true);
733 }
734
735 bool sanitize_shallow (hb_sanitize_context_t *c) const
736 {
737 TRACE_SANITIZE (this);
738 return_trace (len.sanitize (c) && c->check_array_sized (arrayZ, len, sizeof (LenType)));
739 }
740
741 public:
742 LenType len;
743 Type arrayZ[HB_VAR_ARRAY];
744 public:
745 DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
746};
747template <typename Type> using Array16Of = ArrayOf<Type, HBUINT16>;
748template <typename Type> using Array24Of = ArrayOf<Type, HBUINT24>;
749template <typename Type> using Array32Of = ArrayOf<Type, HBUINT32>;
750using PString = ArrayOf<HBUINT8, HBUINT8>;
751
752/* Array of Offset's */
753template <typename Type> using Array16OfOffset16To = ArrayOf<OffsetTo<Type, HBUINT16>, HBUINT16>;
754template <typename Type> using Array16OfOffset32To = ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT16>;
755template <typename Type> using Array32OfOffset32To = ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT32>;
756
757/* Array of offsets relative to the beginning of the array itself. */
758template <typename Type, typename OffsetType>
759struct List16OfOffsetTo : ArrayOf<OffsetTo<Type, OffsetType>, HBUINT16>
760{
761 const Type& operator [] (int i_) const
762 {
763 unsigned int i = (unsigned int) i_;
764 if (unlikely (i >= this->len)) return Null (Type);
765 _hb_compiler_memory_r_barrier ();
766 return this+this->arrayZ[i];
767 }
768 const Type& operator [] (int i_)
769 {
770 unsigned int i = (unsigned int) i_;
771 if (unlikely (i >= this->len)) return Crap (Type);
772 _hb_compiler_memory_r_barrier ();
773 return this+this->arrayZ[i];
774 }
775
776 bool subset (hb_subset_context_t *c) const
777 {
778 TRACE_SUBSET (this);
779 struct List16OfOffsetTo *out = c->serializer->embed (*this);
780 if (unlikely (!out)) return_trace (false);
781 unsigned int count = this->len;
782 for (unsigned int i = 0; i < count; i++)
783 out->arrayZ[i].serialize_subset (c, this->arrayZ[i], this, out);
784 return_trace (true);
785 }
786
787 template <typename ...Ts>
788 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
789 {
790 TRACE_SANITIZE (this);
791 return_trace ((Array16Of<OffsetTo<Type, OffsetType>>::sanitize (c, this, std::forward<Ts> (ds)...)));
792 }
793};
794
795template <typename Type>
796using List16OfOffset16To = List16OfOffsetTo<Type, HBUINT16>;
797
798/* An array starting at second element. */
799template <typename Type, typename LenType>
800struct HeadlessArrayOf
801{
802 static constexpr unsigned item_size = Type::static_size;
803
804 HB_DELETE_CREATE_COPY_ASSIGN (HeadlessArrayOf);
805
806 const Type& operator [] (int i_) const
807 {
808 unsigned int i = (unsigned int) i_;
809 if (unlikely (i >= lenP1 || !i)) return Null (Type);
810 _hb_compiler_memory_r_barrier ();
811 return arrayZ[i-1];
812 }
813 Type& operator [] (int i_)
814 {
815 unsigned int i = (unsigned int) i_;
816 if (unlikely (i >= lenP1 || !i)) return Crap (Type);
817 _hb_compiler_memory_r_barrier ();
818 return arrayZ[i-1];
819 }
820 unsigned int get_size () const
821 { return lenP1.static_size + get_length () * Type::static_size; }
822
823 unsigned get_length () const { return lenP1 ? lenP1 - 1 : 0; }
824
825 hb_array_t< Type> as_array () { return hb_array (arrayZ, get_length ()); }
826 hb_array_t<const Type> as_array () const { return hb_array (arrayZ, get_length ()); }
827
828 /* Iterator. */
829 typedef hb_array_t<const Type> iter_t;
830 typedef hb_array_t< Type> writer_t;
831 iter_t iter () const { return as_array (); }
832 writer_t writer () { return as_array (); }
833 operator iter_t () const { return iter (); }
834 operator writer_t () { return writer (); }
835
836 /* Faster range-based for loop. */
837 const Type *begin () const { return arrayZ; }
838 const Type *end () const { return arrayZ + get_length (); }
839
840 HB_NODISCARD bool serialize (hb_serialize_context_t *c, unsigned int items_len, bool clear = true)
841 {
842 TRACE_SERIALIZE (this);
843 if (unlikely (!c->extend_min (this))) return_trace (false);
844 c->check_assign (lenP1, items_len + 1, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW);
845 if (unlikely (!c->extend_size (this, get_size (), clear))) return_trace (false);
846 return_trace (true);
847 }
848 template <typename Iterator,
849 hb_requires (hb_is_source_of (Iterator, Type))>
850 HB_NODISCARD bool serialize (hb_serialize_context_t *c, Iterator items)
851 {
852 TRACE_SERIALIZE (this);
853 unsigned count = hb_len (items);
854 if (unlikely (!serialize (c, count, false))) return_trace (false);
855 /* TODO Umm. Just exhaust the iterator instead? Being extra
856 * cautious right now.. */
857 for (unsigned i = 0; i < count; i++, ++items)
858 arrayZ[i] = *items;
859 return_trace (true);
860 }
861
862 template <typename ...Ts>
863 HB_ALWAYS_INLINE
864 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
865 {
866 TRACE_SANITIZE (this);
867 if (unlikely (!sanitize_shallow (c))) return_trace (false);
868 if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true);
869 unsigned int count = get_length ();
870 for (unsigned int i = 0; i < count; i++)
871 if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...)))
872 return_trace (false);
873 return_trace (true);
874 }
875
876 private:
877 bool sanitize_shallow (hb_sanitize_context_t *c) const
878 {
879 TRACE_SANITIZE (this);
880 return_trace (lenP1.sanitize (c) &&
881 (!lenP1 || c->check_array_sized (arrayZ, lenP1 - 1, sizeof (LenType))));
882 }
883
884 public:
885 LenType lenP1;
886 Type arrayZ[HB_VAR_ARRAY];
887 public:
888 DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
889};
890template <typename Type> using HeadlessArray16Of = HeadlessArrayOf<Type, HBUINT16>;
891
892/* An array storing length-1. */
893template <typename Type, typename LenType=HBUINT16>
894struct ArrayOfM1
895{
896 HB_DELETE_CREATE_COPY_ASSIGN (ArrayOfM1);
897
898 const Type& operator [] (int i_) const
899 {
900 unsigned int i = (unsigned int) i_;
901 if (unlikely (i > lenM1)) return Null (Type);
902 _hb_compiler_memory_r_barrier ();
903 return arrayZ[i];
904 }
905 Type& operator [] (int i_)
906 {
907 unsigned int i = (unsigned int) i_;
908 if (unlikely (i > lenM1)) return Crap (Type);
909 _hb_compiler_memory_r_barrier ();
910 return arrayZ[i];
911 }
912 unsigned int get_size () const
913 { return lenM1.static_size + (lenM1 + 1) * Type::static_size; }
914
915 template <typename ...Ts>
916 HB_ALWAYS_INLINE
917 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
918 {
919 TRACE_SANITIZE (this);
920 if (unlikely (!sanitize_shallow (c))) return_trace (false);
921 if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true);
922 unsigned int count = lenM1 + 1;
923 for (unsigned int i = 0; i < count; i++)
924 if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...)))
925 return_trace (false);
926 return_trace (true);
927 }
928
929 private:
930 bool sanitize_shallow (hb_sanitize_context_t *c) const
931 {
932 TRACE_SANITIZE (this);
933 return_trace (lenM1.sanitize (c) &&
934 (c->check_array_sized (arrayZ, lenM1 + 1, sizeof (LenType))));
935 }
936
937 public:
938 LenType lenM1;
939 Type arrayZ[HB_VAR_ARRAY];
940 public:
941 DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
942};
943
944/* An array with sorted elements. Supports binary searching. */
945template <typename Type, typename LenType>
946struct SortedArrayOf : ArrayOf<Type, LenType>
947{
948 hb_sorted_array_t< Type> as_array () { return hb_sorted_array (this->arrayZ, this->len); }
949 hb_sorted_array_t<const Type> as_array () const { return hb_sorted_array (this->arrayZ, this->len); }
950
951 /* Iterator. */
952 typedef hb_sorted_array_t<const Type> iter_t;
953 typedef hb_sorted_array_t< Type> writer_t;
954 iter_t iter () const { return as_array (); }
955 writer_t writer () { return as_array (); }
956 operator iter_t () const { return iter (); }
957 operator writer_t () { return writer (); }
958
959 /* Faster range-based for loop. */
960 const Type *begin () const { return this->arrayZ; }
961 const Type *end () const { return this->arrayZ + this->len; }
962
963 bool serialize (hb_serialize_context_t *c, unsigned int items_len)
964 {
965 TRACE_SERIALIZE (this);
966 bool ret = ArrayOf<Type, LenType>::serialize (c, items_len);
967 return_trace (ret);
968 }
969 template <typename Iterator,
970 hb_requires (hb_is_sorted_source_of (Iterator, Type))>
971 bool serialize (hb_serialize_context_t *c, Iterator items)
972 {
973 TRACE_SERIALIZE (this);
974 bool ret = ArrayOf<Type, LenType>::serialize (c, items);
975 return_trace (ret);
976 }
977
978 template <typename T>
979 Type &bsearch (const T &x, Type &not_found = Crap (Type))
980 { return *as_array ().bsearch (x, &not_found); }
981 template <typename T>
982 const Type &bsearch (const T &x, const Type &not_found = Null (Type)) const
983 { return *as_array ().bsearch (x, &not_found); }
984 template <typename T>
985 bool bfind (const T &x, unsigned int *i = nullptr,
986 hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE,
987 unsigned int to_store = (unsigned int) -1) const
988 { return as_array ().bfind (x, i, not_found, to_store); }
989};
990
991template <typename Type> using SortedArray16Of = SortedArrayOf<Type, HBUINT16>;
992template <typename Type> using SortedArray24Of = SortedArrayOf<Type, HBUINT24>;
993template <typename Type> using SortedArray32Of = SortedArrayOf<Type, HBUINT32>;
994
995/*
996 * Binary-search arrays
997 */
998
999template <typename LenType=HBUINT16>
1000struct BinSearchHeader
1001{
1002 operator uint32_t () const { return len; }
1003
1004 bool sanitize (hb_sanitize_context_t *c) const
1005 {
1006 TRACE_SANITIZE (this);
1007 return_trace (c->check_struct (this));
1008 }
1009
1010 BinSearchHeader& operator = (unsigned int v)
1011 {
1012 len = v;
1013 assert (len == v);
1014 entrySelector = hb_max (1u, hb_bit_storage (v)) - 1;
1015 searchRange = 16 * (1u << entrySelector);
1016 rangeShift = v * 16 > searchRange
1017 ? 16 * v - searchRange
1018 : 0;
1019 return *this;
1020 }
1021
1022 protected:
1023 LenType len;
1024 LenType searchRange;
1025 LenType entrySelector;
1026 LenType rangeShift;
1027
1028 public:
1029 DEFINE_SIZE_STATIC (8);
1030};
1031
1032template <typename Type, typename LenType=HBUINT16>
1033using BinSearchArrayOf = SortedArrayOf<Type, BinSearchHeader<LenType>>;
1034
1035
1036struct VarSizedBinSearchHeader
1037{
1038
1039 bool sanitize (hb_sanitize_context_t *c) const
1040 {
1041 TRACE_SANITIZE (this);
1042 return_trace (c->check_struct (this));
1043 }
1044
1045 HBUINT16 unitSize; /* Size of a lookup unit for this search in bytes. */
1046 HBUINT16 nUnits; /* Number of units of the preceding size to be searched. */
1047 HBUINT16 searchRange; /* The value of unitSize times the largest power of 2
1048 * that is less than or equal to the value of nUnits. */
1049 HBUINT16 entrySelector; /* The log base 2 of the largest power of 2 less than
1050 * or equal to the value of nUnits. */
1051 HBUINT16 rangeShift; /* The value of unitSize times the difference of the
1052 * value of nUnits minus the largest power of 2 less
1053 * than or equal to the value of nUnits. */
1054 public:
1055 DEFINE_SIZE_STATIC (10);
1056};
1057
1058template <typename Type>
1059struct VarSizedBinSearchArrayOf
1060{
1061 static constexpr unsigned item_size = Type::static_size;
1062
1063 HB_DELETE_CREATE_COPY_ASSIGN (VarSizedBinSearchArrayOf);
1064
1065 bool last_is_terminator () const
1066 {
1067 if (unlikely (!header.nUnits)) return false;
1068
1069 /* Gah.
1070 *
1071 * "The number of termination values that need to be included is table-specific.
1072 * The value that indicates binary search termination is 0xFFFF." */
1073 const HBUINT16 *words = &StructAtOffset<HBUINT16> (&bytesZ, (header.nUnits - 1) * header.unitSize);
1074 unsigned int count = Type::TerminationWordCount;
1075 for (unsigned int i = 0; i < count; i++)
1076 if (words[i] != 0xFFFFu)
1077 return false;
1078 return true;
1079 }
1080
1081 const Type& operator [] (int i_) const
1082 {
1083 unsigned int i = (unsigned int) i_;
1084 if (unlikely (i >= get_length ())) return Null (Type);
1085 _hb_compiler_memory_r_barrier ();
1086 return StructAtOffset<Type> (&bytesZ, i * header.unitSize);
1087 }
1088 Type& operator [] (int i_)
1089 {
1090 unsigned int i = (unsigned int) i_;
1091 if (unlikely (i >= get_length ())) return Crap (Type);
1092 _hb_compiler_memory_r_barrier ();
1093 return StructAtOffset<Type> (&bytesZ, i * header.unitSize);
1094 }
1095 unsigned int get_length () const
1096 { return header.nUnits - last_is_terminator (); }
1097 unsigned int get_size () const
1098 { return header.static_size + header.nUnits * header.unitSize; }
1099
1100 template <typename ...Ts>
1101 HB_ALWAYS_INLINE
1102 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
1103 {
1104 TRACE_SANITIZE (this);
1105 if (unlikely (!sanitize_shallow (c))) return_trace (false);
1106 if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true);
1107 unsigned int count = get_length ();
1108 for (unsigned int i = 0; i < count; i++)
1109 if (unlikely (!(*this)[i].sanitize (c, std::forward<Ts> (ds)...)))
1110 return_trace (false);
1111 return_trace (true);
1112 }
1113
1114 template <typename T>
1115 const Type *bsearch (const T &key) const
1116 {
1117 unsigned pos;
1118 return hb_bsearch_impl (&pos,
1119 key,
1120 (const void *) bytesZ,
1121 get_length (),
1122 header.unitSize,
1123 _hb_cmp_method<T, Type>)
1124 ? (const Type *) (((const char *) &bytesZ) + (pos * header.unitSize))
1125 : nullptr;
1126 }
1127
1128 private:
1129 bool sanitize_shallow (hb_sanitize_context_t *c) const
1130 {
1131 TRACE_SANITIZE (this);
1132 return_trace (header.sanitize (c) &&
1133 Type::static_size <= header.unitSize &&
1134 c->check_range (bytesZ.arrayZ,
1135 header.nUnits,
1136 header.unitSize));
1137 }
1138
1139 protected:
1140 VarSizedBinSearchHeader header;
1141 UnsizedArrayOf<HBUINT8> bytesZ;
1142 public:
1143 DEFINE_SIZE_ARRAY (10, bytesZ);
1144};
1145
1146
1147} /* namespace OT */
1148
1149
1150#endif /* HB_OPEN_TYPE_HH */
1151