Bug 1760604 - fix bogus domain to be example.com which is part of our test PAC rules...
[gecko.git] / gfx / harfbuzz / src / hb-open-type.hh
blob7e524177f6705158982e0c84d3d7d451d8e159b1
1 /*
2 * Copyright © 2007,2008,2009,2010 Red Hat, Inc.
3 * Copyright © 2012 Google, Inc.
5 * This is part of HarfBuzz, a text shaping library.
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.
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.
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.
25 * Red Hat Author(s): Behdad Esfahbod
26 * Google Author(s): Behdad Esfahbod
29 #ifndef HB_OPEN_TYPE_HH
30 #define HB_OPEN_TYPE_HH
32 #include "hb.hh"
33 #include "hb-blob.hh"
34 #include "hb-face.hh"
35 #include "hb-machinery.hh"
36 #include "hb-subset.hh"
39 namespace OT {
44 * The OpenType Font File: Data Types
48 /* "The following data types are used in the OpenType font file.
49 * All OpenType fonts use Motorola-style byte ordering (Big Endian):" */
52 * Int types
55 /* Integer types in big-endian order and no alignment requirement */
56 template <typename Type,
57 unsigned int Size = sizeof (Type)>
58 struct IntType
60 typedef Type type;
62 IntType () = default;
63 explicit constexpr IntType (Type V) : v {V} {}
64 IntType& operator = (Type i) { v = i; return *this; }
65 /* For reason we define cast out operator for signed/unsigned, instead of Type, see:
66 * https://github.com/harfbuzz/harfbuzz/pull/2875/commits/09836013995cab2b9f07577a179ad7b024130467 */
67 operator typename std::conditional<std::is_signed<Type>::value, signed, unsigned>::type () const { return v; }
69 bool operator == (const IntType &o) const { return (Type) v == (Type) o.v; }
70 bool operator != (const IntType &o) const { return !(*this == o); }
72 IntType& operator += (unsigned count) { *this = *this + count; return *this; }
73 IntType& operator -= (unsigned count) { *this = *this - count; return *this; }
74 IntType& operator ++ () { *this += 1; return *this; }
75 IntType& operator -- () { *this -= 1; return *this; }
76 IntType operator ++ (int) { IntType c (*this); ++*this; return c; }
77 IntType operator -- (int) { IntType c (*this); --*this; return c; }
79 HB_INTERNAL static int cmp (const IntType *a, const IntType *b)
80 { return b->cmp (*a); }
81 HB_INTERNAL static int cmp (const void *a, const void *b)
83 IntType *pa = (IntType *) a;
84 IntType *pb = (IntType *) b;
86 return pb->cmp (*pa);
88 template <typename Type2,
89 hb_enable_if (std::is_integral<Type2>::value &&
90 sizeof (Type2) < sizeof (int) &&
91 sizeof (Type) < sizeof (int))>
92 int cmp (Type2 a) const
94 Type b = v;
95 return (int) a - (int) b;
97 template <typename Type2,
98 hb_enable_if (hb_is_convertible (Type2, Type))>
99 int cmp (Type2 a) const
101 Type b = v;
102 return a < b ? -1 : a == b ? 0 : +1;
104 bool sanitize (hb_sanitize_context_t *c) const
106 TRACE_SANITIZE (this);
107 return_trace (likely (c->check_struct (this)));
109 protected:
110 BEInt<Type, Size> v;
111 public:
112 DEFINE_SIZE_STATIC (Size);
115 typedef IntType<uint8_t> HBUINT8; /* 8-bit unsigned integer. */
116 typedef IntType<int8_t> HBINT8; /* 8-bit signed integer. */
117 typedef IntType<uint16_t> HBUINT16; /* 16-bit unsigned integer. */
118 typedef IntType<int16_t> HBINT16; /* 16-bit signed integer. */
119 typedef IntType<uint32_t> HBUINT32; /* 32-bit unsigned integer. */
120 typedef IntType<int32_t> HBINT32; /* 32-bit signed integer. */
121 /* Note: we cannot defined a signed HBINT24 because there's no corresponding C type.
122 * Works for unsigned, but not signed, since we rely on compiler for sign-extension. */
123 typedef IntType<uint32_t, 3> HBUINT24; /* 24-bit unsigned integer. */
125 /* 15-bit unsigned number; top bit used for extension. */
126 struct HBUINT15 : HBUINT16
128 /* TODO Flesh out; actually mask top bit. */
129 HBUINT15& operator = (uint16_t i ) { HBUINT16::operator= (i); return *this; }
130 public:
131 DEFINE_SIZE_STATIC (2);
134 /* 16-bit signed integer (HBINT16) that describes a quantity in FUnits. */
135 typedef HBINT16 FWORD;
137 /* 32-bit signed integer (HBINT32) that describes a quantity in FUnits. */
138 typedef HBINT32 FWORD32;
140 /* 16-bit unsigned integer (HBUINT16) that describes a quantity in FUnits. */
141 typedef HBUINT16 UFWORD;
143 /* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */
144 struct F2DOT14 : HBINT16
146 F2DOT14& operator = (uint16_t i ) { HBINT16::operator= (i); return *this; }
147 // 16384 means 1<<14
148 float to_float () const { return ((int32_t) v) / 16384.f; }
149 void set_float (float f) { v = roundf (f * 16384.f); }
150 public:
151 DEFINE_SIZE_STATIC (2);
154 /* 32-bit signed fixed-point number (16.16). */
155 struct HBFixed : HBINT32
157 HBFixed& operator = (uint32_t i) { HBINT32::operator= (i); return *this; }
158 // 65536 means 1<<16
159 float to_float () const { return ((int32_t) v) / 65536.f; }
160 void set_float (float f) { v = roundf (f * 65536.f); }
161 public:
162 DEFINE_SIZE_STATIC (4);
165 /* Date represented in number of seconds since 12:00 midnight, January 1,
166 * 1904. The value is represented as a signed 64-bit integer. */
167 struct LONGDATETIME
169 bool sanitize (hb_sanitize_context_t *c) const
171 TRACE_SANITIZE (this);
172 return_trace (likely (c->check_struct (this)));
174 protected:
175 HBINT32 major;
176 HBUINT32 minor;
177 public:
178 DEFINE_SIZE_STATIC (8);
181 /* Array of four uint8s (length = 32 bits) used to identify a script, language
182 * system, feature, or baseline */
183 struct Tag : HBUINT32
185 Tag& operator = (hb_tag_t i) { HBUINT32::operator= (i); return *this; }
186 /* What the char* converters return is NOT nul-terminated. Print using "%.4s" */
187 operator const char* () const { return reinterpret_cast<const char *> (this); }
188 operator char* () { return reinterpret_cast<char *> (this); }
189 public:
190 DEFINE_SIZE_STATIC (4);
193 /* Glyph index number, same as uint16 (length = 16 bits) */
194 struct HBGlyphID16 : HBUINT16
196 HBGlyphID16& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; }
199 /* Script/language-system/feature index */
200 struct Index : HBUINT16 {
201 static constexpr unsigned NOT_FOUND_INDEX = 0xFFFFu;
202 Index& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; }
204 DECLARE_NULL_NAMESPACE_BYTES (OT, Index);
206 typedef Index NameID;
208 struct VarIdx : HBUINT32 {
209 static constexpr unsigned NO_VARIATION = 0xFFFFFFFFu;
210 VarIdx& operator = (uint32_t i) { HBUINT32::operator= (i); return *this; }
212 DECLARE_NULL_NAMESPACE_BYTES (OT, VarIdx);
214 /* Offset, Null offset = 0 */
215 template <typename Type, bool has_null=true>
216 struct Offset : Type
218 Offset& operator = (typename Type::type i) { Type::operator= (i); return *this; }
220 typedef Type type;
222 bool is_null () const { return has_null && 0 == *this; }
224 public:
225 DEFINE_SIZE_STATIC (sizeof (Type));
228 typedef Offset<HBUINT16> Offset16;
229 typedef Offset<HBUINT24> Offset24;
230 typedef Offset<HBUINT32> Offset32;
233 /* CheckSum */
234 struct CheckSum : HBUINT32
236 CheckSum& operator = (uint32_t i) { HBUINT32::operator= (i); return *this; }
238 /* This is reference implementation from the spec. */
239 static uint32_t CalcTableChecksum (const HBUINT32 *Table, uint32_t Length)
241 uint32_t Sum = 0L;
242 assert (0 == (Length & 3));
243 const HBUINT32 *EndPtr = Table + Length / HBUINT32::static_size;
245 while (Table < EndPtr)
246 Sum += *Table++;
247 return Sum;
250 /* Note: data should be 4byte aligned and have 4byte padding at the end. */
251 void set_for_data (const void *data, unsigned int length)
252 { *this = CalcTableChecksum ((const HBUINT32 *) data, length); }
254 public:
255 DEFINE_SIZE_STATIC (4);
260 * Version Numbers
263 template <typename FixedType=HBUINT16>
264 struct FixedVersion
266 uint32_t to_int () const { return (major << (sizeof (FixedType) * 8)) + minor; }
268 bool sanitize (hb_sanitize_context_t *c) const
270 TRACE_SANITIZE (this);
271 return_trace (c->check_struct (this));
274 FixedType major;
275 FixedType minor;
276 public:
277 DEFINE_SIZE_STATIC (2 * sizeof (FixedType));
282 * Template subclasses of Offset that do the dereferencing.
283 * Use: (base+offset)
286 template <typename Type, bool has_null>
287 struct _hb_has_null
289 static const Type *get_null () { return nullptr; }
290 static Type *get_crap () { return nullptr; }
292 template <typename Type>
293 struct _hb_has_null<Type, true>
295 static const Type *get_null () { return &Null (Type); }
296 static Type *get_crap () { return &Crap (Type); }
299 template <typename Type, typename OffsetType, bool has_null=true>
300 struct OffsetTo : Offset<OffsetType, has_null>
302 HB_DELETE_COPY_ASSIGN (OffsetTo);
303 OffsetTo () = default;
305 OffsetTo& operator = (typename OffsetType::type i) { OffsetType::operator= (i); return *this; }
307 const Type& operator () (const void *base) const
309 if (unlikely (this->is_null ())) return *_hb_has_null<Type, has_null>::get_null ();
310 return StructAtOffset<const Type> (base, *this);
312 Type& operator () (void *base) const
314 if (unlikely (this->is_null ())) return *_hb_has_null<Type, has_null>::get_crap ();
315 return StructAtOffset<Type> (base, *this);
318 template <typename Base,
319 hb_enable_if (hb_is_convertible (const Base, const void *))>
320 friend const Type& operator + (const Base &base, const OffsetTo &offset) { return offset ((const void *) base); }
321 template <typename Base,
322 hb_enable_if (hb_is_convertible (const Base, const void *))>
323 friend const Type& operator + (const OffsetTo &offset, const Base &base) { return offset ((const void *) base); }
324 template <typename Base,
325 hb_enable_if (hb_is_convertible (Base, void *))>
326 friend Type& operator + (Base &&base, OffsetTo &offset) { return offset ((void *) base); }
327 template <typename Base,
328 hb_enable_if (hb_is_convertible (Base, void *))>
329 friend Type& operator + (OffsetTo &offset, Base &&base) { return offset ((void *) base); }
332 template <typename ...Ts>
333 bool serialize_subset (hb_subset_context_t *c, const OffsetTo& src,
334 const void *src_base, Ts&&... ds)
336 *this = 0;
337 if (src.is_null ())
338 return false;
340 auto *s = c->serializer;
342 s->push ();
344 bool ret = c->dispatch (src_base+src, std::forward<Ts> (ds)...);
346 if (ret || !has_null)
347 s->add_link (*this, s->pop_pack ());
348 else
349 s->pop_discard ();
351 return ret;
355 template <typename ...Ts>
356 bool serialize_serialize (hb_serialize_context_t *c, Ts&&... ds)
358 *this = 0;
360 Type* obj = c->push<Type> ();
361 bool ret = obj->serialize (c, std::forward<Ts> (ds)...);
363 if (ret)
364 c->add_link (*this, c->pop_pack ());
365 else
366 c->pop_discard ();
368 return ret;
371 /* TODO: Somehow merge this with previous function into a serialize_dispatch(). */
372 /* Workaround clang bug: https://bugs.llvm.org/show_bug.cgi?id=23029
373 * Can't compile: whence = hb_serialize_context_t::Head followed by Ts&&...
375 template <typename ...Ts>
376 bool serialize_copy (hb_serialize_context_t *c, const OffsetTo& src,
377 const void *src_base, unsigned dst_bias,
378 hb_serialize_context_t::whence_t whence,
379 Ts&&... ds)
381 *this = 0;
382 if (src.is_null ())
383 return false;
385 c->push ();
387 bool ret = c->copy (src_base+src, std::forward<Ts> (ds)...);
389 c->add_link (*this, c->pop_pack (), whence, dst_bias);
391 return ret;
394 bool serialize_copy (hb_serialize_context_t *c, const OffsetTo& src,
395 const void *src_base, unsigned dst_bias = 0)
396 { return serialize_copy (c, src, src_base, dst_bias, hb_serialize_context_t::Head); }
398 bool sanitize_shallow (hb_sanitize_context_t *c, const void *base) const
400 TRACE_SANITIZE (this);
401 if (unlikely (!c->check_struct (this))) return_trace (false);
402 if (unlikely (this->is_null ())) return_trace (true);
403 if (unlikely ((const char *) base + (unsigned) *this < (const char *) base)) return_trace (false);
404 return_trace (true);
407 template <typename ...Ts>
408 bool sanitize (hb_sanitize_context_t *c, const void *base, Ts&&... ds) const
410 TRACE_SANITIZE (this);
411 return_trace (sanitize_shallow (c, base) &&
412 (this->is_null () ||
413 c->dispatch (StructAtOffset<Type> (base, *this), std::forward<Ts> (ds)...) ||
414 neuter (c)));
417 /* Set the offset to Null */
418 bool neuter (hb_sanitize_context_t *c) const
420 if (!has_null) return false;
421 return c->try_set (this, 0);
423 DEFINE_SIZE_STATIC (sizeof (OffsetType));
425 /* Partial specializations. */
426 template <typename Type, bool has_null=true> using Offset16To = OffsetTo<Type, HBUINT16, has_null>;
427 template <typename Type, bool has_null=true> using Offset24To = OffsetTo<Type, HBUINT24, has_null>;
428 template <typename Type, bool has_null=true> using Offset32To = OffsetTo<Type, HBUINT32, has_null>;
430 template <typename Type, typename OffsetType> using NNOffsetTo = OffsetTo<Type, OffsetType, false>;
431 template <typename Type> using NNOffset16To = Offset16To<Type, false>;
432 template <typename Type> using NNOffset24To = Offset24To<Type, false>;
433 template <typename Type> using NNOffset32To = Offset32To<Type, false>;
437 * Array Types
440 template <typename Type>
441 struct UnsizedArrayOf
443 typedef Type item_t;
444 static constexpr unsigned item_size = hb_static_size (Type);
446 HB_DELETE_CREATE_COPY_ASSIGN (UnsizedArrayOf);
448 const Type& operator [] (int i_) const
450 unsigned int i = (unsigned int) i_;
451 const Type *p = &arrayZ[i];
452 if (unlikely (p < arrayZ)) return Null (Type); /* Overflowed. */
453 return *p;
455 Type& operator [] (int i_)
457 unsigned int i = (unsigned int) i_;
458 Type *p = &arrayZ[i];
459 if (unlikely (p < arrayZ)) return Crap (Type); /* Overflowed. */
460 return *p;
463 unsigned int get_size (unsigned int len) const
464 { return len * Type::static_size; }
466 template <typename T> operator T * () { return arrayZ; }
467 template <typename T> operator const T * () const { return arrayZ; }
468 hb_array_t<Type> as_array (unsigned int len)
469 { return hb_array (arrayZ, len); }
470 hb_array_t<const Type> as_array (unsigned int len) const
471 { return hb_array (arrayZ, len); }
473 template <typename T>
474 Type &lsearch (unsigned int len, const T &x, Type &not_found = Crap (Type))
475 { return *as_array (len).lsearch (x, &not_found); }
476 template <typename T>
477 const Type &lsearch (unsigned int len, const T &x, const Type &not_found = Null (Type)) const
478 { return *as_array (len).lsearch (x, &not_found); }
479 template <typename T>
480 bool lfind (unsigned int len, const T &x, unsigned int *i = nullptr,
481 hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE,
482 unsigned int to_store = (unsigned int) -1) const
483 { return as_array (len).lfind (x, i, not_found, to_store); }
485 void qsort (unsigned int len, unsigned int start = 0, unsigned int end = (unsigned int) -1)
486 { as_array (len).qsort (start, end); }
488 bool serialize (hb_serialize_context_t *c, unsigned int items_len)
490 TRACE_SERIALIZE (this);
491 if (unlikely (!c->extend (this, items_len))) return_trace (false);
492 return_trace (true);
494 template <typename Iterator,
495 hb_requires (hb_is_source_of (Iterator, Type))>
496 bool serialize (hb_serialize_context_t *c, Iterator items)
498 TRACE_SERIALIZE (this);
499 unsigned count = items.len ();
500 if (unlikely (!serialize (c, count))) return_trace (false);
501 /* TODO Umm. Just exhaust the iterator instead? Being extra
502 * cautious right now.. */
503 for (unsigned i = 0; i < count; i++, ++items)
504 arrayZ[i] = *items;
505 return_trace (true);
508 UnsizedArrayOf* copy (hb_serialize_context_t *c, unsigned count) const
510 TRACE_SERIALIZE (this);
511 auto *out = c->start_embed (this);
512 if (unlikely (!as_array (count).copy (c))) return_trace (nullptr);
513 return_trace (out);
516 template <typename ...Ts>
517 bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const
519 TRACE_SANITIZE (this);
520 if (unlikely (!sanitize_shallow (c, count))) return_trace (false);
521 if (!sizeof... (Ts) && std::is_trivially_copyable<Type>::value) return_trace (true);
522 for (unsigned int i = 0; i < count; i++)
523 if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...)))
524 return_trace (false);
525 return_trace (true);
528 bool sanitize_shallow (hb_sanitize_context_t *c, unsigned int count) const
530 TRACE_SANITIZE (this);
531 return_trace (c->check_array (arrayZ, count));
534 public:
535 Type arrayZ[HB_VAR_ARRAY];
536 public:
537 DEFINE_SIZE_UNBOUNDED (0);
540 /* Unsized array of offset's */
541 template <typename Type, typename OffsetType, bool has_null=true>
542 using UnsizedArray16OfOffsetTo = UnsizedArrayOf<OffsetTo<Type, OffsetType, has_null>>;
544 /* Unsized array of offsets relative to the beginning of the array itself. */
545 template <typename Type, typename OffsetType, bool has_null=true>
546 struct UnsizedListOfOffset16To : UnsizedArray16OfOffsetTo<Type, OffsetType, has_null>
548 const Type& operator [] (int i_) const
550 unsigned int i = (unsigned int) i_;
551 const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i];
552 if (unlikely (p < this->arrayZ)) return Null (Type); /* Overflowed. */
553 return this+*p;
555 Type& operator [] (int i_)
557 unsigned int i = (unsigned int) i_;
558 const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i];
559 if (unlikely (p < this->arrayZ)) return Crap (Type); /* Overflowed. */
560 return this+*p;
563 template <typename ...Ts>
564 bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const
566 TRACE_SANITIZE (this);
567 return_trace ((UnsizedArray16OfOffsetTo<Type, OffsetType, has_null>
568 ::sanitize (c, count, this, std::forward<Ts> (ds)...)));
572 /* An array with sorted elements. Supports binary searching. */
573 template <typename Type>
574 struct SortedUnsizedArrayOf : UnsizedArrayOf<Type>
576 hb_sorted_array_t<Type> as_array (unsigned int len)
577 { return hb_sorted_array (this->arrayZ, len); }
578 hb_sorted_array_t<const Type> as_array (unsigned int len) const
579 { return hb_sorted_array (this->arrayZ, len); }
580 operator hb_sorted_array_t<Type> () { return as_array (); }
581 operator hb_sorted_array_t<const Type> () const { return as_array (); }
583 template <typename T>
584 Type &bsearch (unsigned int len, const T &x, Type &not_found = Crap (Type))
585 { return *as_array (len).bsearch (x, &not_found); }
586 template <typename T>
587 const Type &bsearch (unsigned int len, const T &x, const Type &not_found = Null (Type)) const
588 { return *as_array (len).bsearch (x, &not_found); }
589 template <typename T>
590 bool bfind (unsigned int len, const T &x, unsigned int *i = nullptr,
591 hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE,
592 unsigned int to_store = (unsigned int) -1) const
593 { return as_array (len).bfind (x, i, not_found, to_store); }
597 /* An array with a number of elements. */
598 template <typename Type, typename LenType>
599 struct ArrayOf
601 typedef Type item_t;
602 static constexpr unsigned item_size = hb_static_size (Type);
604 HB_DELETE_CREATE_COPY_ASSIGN (ArrayOf);
606 const Type& operator [] (int i_) const
608 unsigned int i = (unsigned int) i_;
609 if (unlikely (i >= len)) return Null (Type);
610 return arrayZ[i];
612 Type& operator [] (int i_)
614 unsigned int i = (unsigned int) i_;
615 if (unlikely (i >= len)) return Crap (Type);
616 return arrayZ[i];
619 unsigned int get_size () const
620 { return len.static_size + len * Type::static_size; }
622 explicit operator bool () const { return len; }
624 void pop () { len--; }
626 hb_array_t< Type> as_array () { return hb_array (arrayZ, len); }
627 hb_array_t<const Type> as_array () const { return hb_array (arrayZ, len); }
629 /* Iterator. */
630 typedef hb_array_t<const Type> iter_t;
631 typedef hb_array_t< Type> writer_t;
632 iter_t iter () const { return as_array (); }
633 writer_t writer () { return as_array (); }
634 operator iter_t () const { return iter (); }
635 operator writer_t () { return writer (); }
637 hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const
638 { return as_array ().sub_array (start_offset, count); }
639 hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const
640 { return as_array ().sub_array (start_offset, count); }
641 hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int count)
642 { return as_array ().sub_array (start_offset, count); }
643 hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */)
644 { return as_array ().sub_array (start_offset, count); }
646 template <typename T>
647 Type &lsearch (const T &x, Type &not_found = Crap (Type))
648 { return *as_array ().lsearch (x, &not_found); }
649 template <typename T>
650 const Type &lsearch (const T &x, const Type &not_found = Null (Type)) const
651 { return *as_array ().lsearch (x, &not_found); }
652 template <typename T>
653 bool lfind (const T &x, unsigned int *i = nullptr,
654 hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE,
655 unsigned int to_store = (unsigned int) -1) const
656 { return as_array ().lfind (x, i, not_found, to_store); }
658 void qsort (unsigned int start = 0, unsigned int end = (unsigned int) -1)
659 { as_array ().qsort (start, end); }
661 HB_NODISCARD bool serialize (hb_serialize_context_t *c, unsigned items_len)
663 TRACE_SERIALIZE (this);
664 if (unlikely (!c->extend_min (this))) return_trace (false);
665 c->check_assign (len, items_len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW);
666 if (unlikely (!c->extend (this))) return_trace (false);
667 return_trace (true);
669 template <typename Iterator,
670 hb_requires (hb_is_source_of (Iterator, Type))>
671 HB_NODISCARD bool serialize (hb_serialize_context_t *c, Iterator items)
673 TRACE_SERIALIZE (this);
674 unsigned count = items.len ();
675 if (unlikely (!serialize (c, count))) return_trace (false);
676 /* TODO Umm. Just exhaust the iterator instead? Being extra
677 * cautious right now.. */
678 for (unsigned i = 0; i < count; i++, ++items)
679 arrayZ[i] = *items;
680 return_trace (true);
683 Type* serialize_append (hb_serialize_context_t *c)
685 TRACE_SERIALIZE (this);
686 len++;
687 if (unlikely (!len || !c->extend (this)))
689 len--;
690 return_trace (nullptr);
692 return_trace (&arrayZ[len - 1]);
695 ArrayOf* copy (hb_serialize_context_t *c) const
697 TRACE_SERIALIZE (this);
698 auto *out = c->start_embed (this);
699 if (unlikely (!c->extend_min (out))) return_trace (nullptr);
700 c->check_assign (out->len, len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW);
701 if (unlikely (!as_array ().copy (c))) return_trace (nullptr);
702 return_trace (out);
705 template <typename ...Ts>
706 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
708 TRACE_SANITIZE (this);
709 if (unlikely (!sanitize_shallow (c))) return_trace (false);
710 if (!sizeof... (Ts) && std::is_trivially_copyable<Type>::value) return_trace (true);
711 unsigned int count = len;
712 for (unsigned int i = 0; i < count; i++)
713 if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...)))
714 return_trace (false);
715 return_trace (true);
718 bool sanitize_shallow (hb_sanitize_context_t *c) const
720 TRACE_SANITIZE (this);
721 return_trace (len.sanitize (c) && c->check_array (arrayZ, len));
724 public:
725 LenType len;
726 Type arrayZ[HB_VAR_ARRAY];
727 public:
728 DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
730 template <typename Type> using Array16Of = ArrayOf<Type, HBUINT16>;
731 template <typename Type> using Array32Of = ArrayOf<Type, HBUINT32>;
732 using PString = ArrayOf<HBUINT8, HBUINT8>;
734 /* Array of Offset's */
735 template <typename Type> using Array16OfOffset16To = ArrayOf<OffsetTo<Type, HBUINT16>, HBUINT16>;
736 template <typename Type> using Array16OfOffset32To = ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT16>;
737 template <typename Type> using Array32OfOffset32To = ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT32>;
739 /* Array of offsets relative to the beginning of the array itself. */
740 template <typename Type>
741 struct List16OfOffset16To : Array16OfOffset16To<Type>
743 const Type& operator [] (int i_) const
745 unsigned int i = (unsigned int) i_;
746 if (unlikely (i >= this->len)) return Null (Type);
747 return this+this->arrayZ[i];
749 const Type& operator [] (int i_)
751 unsigned int i = (unsigned int) i_;
752 if (unlikely (i >= this->len)) return Crap (Type);
753 return this+this->arrayZ[i];
756 bool subset (hb_subset_context_t *c) const
758 TRACE_SUBSET (this);
759 struct List16OfOffset16To<Type> *out = c->serializer->embed (*this);
760 if (unlikely (!out)) return_trace (false);
761 unsigned int count = this->len;
762 for (unsigned int i = 0; i < count; i++)
763 out->arrayZ[i].serialize_subset (c, this->arrayZ[i], this, out);
764 return_trace (true);
767 template <typename ...Ts>
768 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
770 TRACE_SANITIZE (this);
771 return_trace (Array16OfOffset16To<Type>::sanitize (c, this, std::forward<Ts> (ds)...));
775 /* An array starting at second element. */
776 template <typename Type, typename LenType=HBUINT16>
777 struct HeadlessArrayOf
779 static constexpr unsigned item_size = Type::static_size;
781 HB_DELETE_CREATE_COPY_ASSIGN (HeadlessArrayOf);
783 const Type& operator [] (int i_) const
785 unsigned int i = (unsigned int) i_;
786 if (unlikely (i >= lenP1 || !i)) return Null (Type);
787 return arrayZ[i-1];
789 Type& operator [] (int i_)
791 unsigned int i = (unsigned int) i_;
792 if (unlikely (i >= lenP1 || !i)) return Crap (Type);
793 return arrayZ[i-1];
795 unsigned int get_size () const
796 { return lenP1.static_size + get_length () * Type::static_size; }
798 unsigned get_length () const { return lenP1 ? lenP1 - 1 : 0; }
800 hb_array_t< Type> as_array () { return hb_array (arrayZ, get_length ()); }
801 hb_array_t<const Type> as_array () const { return hb_array (arrayZ, get_length ()); }
803 /* Iterator. */
804 typedef hb_array_t<const Type> iter_t;
805 typedef hb_array_t< Type> writer_t;
806 iter_t iter () const { return as_array (); }
807 writer_t writer () { return as_array (); }
808 operator iter_t () const { return iter (); }
809 operator writer_t () { return writer (); }
811 bool serialize (hb_serialize_context_t *c, unsigned int items_len)
813 TRACE_SERIALIZE (this);
814 if (unlikely (!c->extend_min (this))) return_trace (false);
815 c->check_assign (lenP1, items_len + 1, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW);
816 if (unlikely (!c->extend (this))) return_trace (false);
817 return_trace (true);
819 template <typename Iterator,
820 hb_requires (hb_is_source_of (Iterator, Type))>
821 bool serialize (hb_serialize_context_t *c, Iterator items)
823 TRACE_SERIALIZE (this);
824 unsigned count = items.len ();
825 if (unlikely (!serialize (c, count))) return_trace (false);
826 /* TODO Umm. Just exhaust the iterator instead? Being extra
827 * cautious right now.. */
828 for (unsigned i = 0; i < count; i++, ++items)
829 arrayZ[i] = *items;
830 return_trace (true);
833 template <typename ...Ts>
834 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
836 TRACE_SANITIZE (this);
837 if (unlikely (!sanitize_shallow (c))) return_trace (false);
838 if (!sizeof... (Ts) && std::is_trivially_copyable<Type>::value) return_trace (true);
839 unsigned int count = get_length ();
840 for (unsigned int i = 0; i < count; i++)
841 if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...)))
842 return_trace (false);
843 return_trace (true);
846 private:
847 bool sanitize_shallow (hb_sanitize_context_t *c) const
849 TRACE_SANITIZE (this);
850 return_trace (lenP1.sanitize (c) &&
851 (!lenP1 || c->check_array (arrayZ, lenP1 - 1)));
854 public:
855 LenType lenP1;
856 Type arrayZ[HB_VAR_ARRAY];
857 public:
858 DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
861 /* An array storing length-1. */
862 template <typename Type, typename LenType=HBUINT16>
863 struct ArrayOfM1
865 HB_DELETE_CREATE_COPY_ASSIGN (ArrayOfM1);
867 const Type& operator [] (int i_) const
869 unsigned int i = (unsigned int) i_;
870 if (unlikely (i > lenM1)) return Null (Type);
871 return arrayZ[i];
873 Type& operator [] (int i_)
875 unsigned int i = (unsigned int) i_;
876 if (unlikely (i > lenM1)) return Crap (Type);
877 return arrayZ[i];
879 unsigned int get_size () const
880 { return lenM1.static_size + (lenM1 + 1) * Type::static_size; }
882 template <typename ...Ts>
883 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
885 TRACE_SANITIZE (this);
886 if (unlikely (!sanitize_shallow (c))) return_trace (false);
887 if (!sizeof... (Ts) && std::is_trivially_copyable<Type>::value) return_trace (true);
888 unsigned int count = lenM1 + 1;
889 for (unsigned int i = 0; i < count; i++)
890 if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...)))
891 return_trace (false);
892 return_trace (true);
895 private:
896 bool sanitize_shallow (hb_sanitize_context_t *c) const
898 TRACE_SANITIZE (this);
899 return_trace (lenM1.sanitize (c) &&
900 (c->check_array (arrayZ, lenM1 + 1)));
903 public:
904 LenType lenM1;
905 Type arrayZ[HB_VAR_ARRAY];
906 public:
907 DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
910 /* An array with sorted elements. Supports binary searching. */
911 template <typename Type, typename LenType>
912 struct SortedArrayOf : ArrayOf<Type, LenType>
914 hb_sorted_array_t< Type> as_array () { return hb_sorted_array (this->arrayZ, this->len); }
915 hb_sorted_array_t<const Type> as_array () const { return hb_sorted_array (this->arrayZ, this->len); }
917 /* Iterator. */
918 typedef hb_sorted_array_t<const Type> iter_t;
919 typedef hb_sorted_array_t< Type> writer_t;
920 iter_t iter () const { return as_array (); }
921 writer_t writer () { return as_array (); }
922 operator iter_t () const { return iter (); }
923 operator writer_t () { return writer (); }
925 hb_sorted_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const
926 { return as_array ().sub_array (start_offset, count); }
927 hb_sorted_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const
928 { return as_array ().sub_array (start_offset, count); }
929 hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int count)
930 { return as_array ().sub_array (start_offset, count); }
931 hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */)
932 { return as_array ().sub_array (start_offset, count); }
934 bool serialize (hb_serialize_context_t *c, unsigned int items_len)
936 TRACE_SERIALIZE (this);
937 bool ret = ArrayOf<Type, LenType>::serialize (c, items_len);
938 return_trace (ret);
940 template <typename Iterator,
941 hb_requires (hb_is_sorted_source_of (Iterator, Type))>
942 bool serialize (hb_serialize_context_t *c, Iterator items)
944 TRACE_SERIALIZE (this);
945 bool ret = ArrayOf<Type, LenType>::serialize (c, items);
946 return_trace (ret);
949 template <typename T>
950 Type &bsearch (const T &x, Type &not_found = Crap (Type))
951 { return *as_array ().bsearch (x, &not_found); }
952 template <typename T>
953 const Type &bsearch (const T &x, const Type &not_found = Null (Type)) const
954 { return *as_array ().bsearch (x, &not_found); }
955 template <typename T>
956 bool bfind (const T &x, unsigned int *i = nullptr,
957 hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE,
958 unsigned int to_store = (unsigned int) -1) const
959 { return as_array ().bfind (x, i, not_found, to_store); }
962 template <typename Type> using SortedArray16Of = SortedArrayOf<Type, HBUINT16>;
963 template <typename Type> using SortedArray32Of = SortedArrayOf<Type, HBUINT32>;
966 * Binary-search arrays
969 template <typename LenType=HBUINT16>
970 struct BinSearchHeader
972 operator uint32_t () const { return len; }
974 bool sanitize (hb_sanitize_context_t *c) const
976 TRACE_SANITIZE (this);
977 return_trace (c->check_struct (this));
980 BinSearchHeader& operator = (unsigned int v)
982 len = v;
983 assert (len == v);
984 entrySelector = hb_max (1u, hb_bit_storage (v)) - 1;
985 searchRange = 16 * (1u << entrySelector);
986 rangeShift = v * 16 > searchRange
987 ? 16 * v - searchRange
988 : 0;
989 return *this;
992 protected:
993 LenType len;
994 LenType searchRange;
995 LenType entrySelector;
996 LenType rangeShift;
998 public:
999 DEFINE_SIZE_STATIC (8);
1002 template <typename Type, typename LenType=HBUINT16>
1003 using BinSearchArrayOf = SortedArrayOf<Type, BinSearchHeader<LenType>>;
1006 struct VarSizedBinSearchHeader
1009 bool sanitize (hb_sanitize_context_t *c) const
1011 TRACE_SANITIZE (this);
1012 return_trace (c->check_struct (this));
1015 HBUINT16 unitSize; /* Size of a lookup unit for this search in bytes. */
1016 HBUINT16 nUnits; /* Number of units of the preceding size to be searched. */
1017 HBUINT16 searchRange; /* The value of unitSize times the largest power of 2
1018 * that is less than or equal to the value of nUnits. */
1019 HBUINT16 entrySelector; /* The log base 2 of the largest power of 2 less than
1020 * or equal to the value of nUnits. */
1021 HBUINT16 rangeShift; /* The value of unitSize times the difference of the
1022 * value of nUnits minus the largest power of 2 less
1023 * than or equal to the value of nUnits. */
1024 public:
1025 DEFINE_SIZE_STATIC (10);
1028 template <typename Type>
1029 struct VarSizedBinSearchArrayOf
1031 static constexpr unsigned item_size = Type::static_size;
1033 HB_DELETE_CREATE_COPY_ASSIGN (VarSizedBinSearchArrayOf);
1035 bool last_is_terminator () const
1037 if (unlikely (!header.nUnits)) return false;
1039 /* Gah.
1041 * "The number of termination values that need to be included is table-specific.
1042 * The value that indicates binary search termination is 0xFFFF." */
1043 const HBUINT16 *words = &StructAtOffset<HBUINT16> (&bytesZ, (header.nUnits - 1) * header.unitSize);
1044 unsigned int count = Type::TerminationWordCount;
1045 for (unsigned int i = 0; i < count; i++)
1046 if (words[i] != 0xFFFFu)
1047 return false;
1048 return true;
1051 const Type& operator [] (int i_) const
1053 unsigned int i = (unsigned int) i_;
1054 if (unlikely (i >= get_length ())) return Null (Type);
1055 return StructAtOffset<Type> (&bytesZ, i * header.unitSize);
1057 Type& operator [] (int i_)
1059 unsigned int i = (unsigned int) i_;
1060 if (unlikely (i >= get_length ())) return Crap (Type);
1061 return StructAtOffset<Type> (&bytesZ, i * header.unitSize);
1063 unsigned int get_length () const
1064 { return header.nUnits - last_is_terminator (); }
1065 unsigned int get_size () const
1066 { return header.static_size + header.nUnits * header.unitSize; }
1068 template <typename ...Ts>
1069 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
1071 TRACE_SANITIZE (this);
1072 if (unlikely (!sanitize_shallow (c))) return_trace (false);
1073 if (!sizeof... (Ts) && std::is_trivially_copyable<Type>::value) return_trace (true);
1074 unsigned int count = get_length ();
1075 for (unsigned int i = 0; i < count; i++)
1076 if (unlikely (!(*this)[i].sanitize (c, std::forward<Ts> (ds)...)))
1077 return_trace (false);
1078 return_trace (true);
1081 template <typename T>
1082 const Type *bsearch (const T &key) const
1084 unsigned pos;
1085 return hb_bsearch_impl (&pos,
1086 key,
1087 (const void *) bytesZ,
1088 get_length (),
1089 header.unitSize,
1090 _hb_cmp_method<T, Type>)
1091 ? (const Type *) (((const char *) &bytesZ) + (pos * header.unitSize))
1092 : nullptr;
1095 private:
1096 bool sanitize_shallow (hb_sanitize_context_t *c) const
1098 TRACE_SANITIZE (this);
1099 return_trace (header.sanitize (c) &&
1100 Type::static_size <= header.unitSize &&
1101 c->check_range (bytesZ.arrayZ,
1102 header.nUnits,
1103 header.unitSize));
1106 protected:
1107 VarSizedBinSearchHeader header;
1108 UnsizedArrayOf<HBUINT8> bytesZ;
1109 public:
1110 DEFINE_SIZE_ARRAY (10, bytesZ);
1114 } /* namespace OT */
1117 #endif /* HB_OPEN_TYPE_HH */