< prev index next >

src/java.desktop/share/native/libfontmanager/harfbuzz/hb-open-type.hh

Print this page

        

@@ -24,495 +24,23 @@
  *
  * Red Hat Author(s): Behdad Esfahbod
  * Google Author(s): Behdad Esfahbod
  */
 
-#ifndef HB_OPEN_TYPE_PRIVATE_HH
-#define HB_OPEN_TYPE_PRIVATE_HH
+#ifndef HB_OPEN_TYPE_HH
+#define HB_OPEN_TYPE_HH
 
-#include "hb-private.hh"
-#include "hb-debug.hh"
-#include "hb-blob-private.hh"
-#include "hb-face-private.hh"
+#include "hb.hh"
+#include "hb-blob.hh"
+#include "hb-face.hh"
+#include "hb-machinery.hh"
+#include "hb-subset.hh"
 
 
 namespace OT {
 
 
-
-/*
- * Casts
- */
-
-/* Cast to struct T, reference to reference */
-template<typename Type, typename TObject>
-static inline const Type& CastR(const TObject &X)
-{ return reinterpret_cast<const Type&> (X); }
-template<typename Type, typename TObject>
-static inline Type& CastR(TObject &X)
-{ return reinterpret_cast<Type&> (X); }
-
-/* Cast to struct T, pointer to pointer */
-template<typename Type, typename TObject>
-static inline const Type* CastP(const TObject *X)
-{ return reinterpret_cast<const Type*> (X); }
-template<typename Type, typename TObject>
-static inline Type* CastP(TObject *X)
-{ return reinterpret_cast<Type*> (X); }
-
-/* StructAtOffset<T>(P,Ofs) returns the struct T& that is placed at memory
- * location pointed to by P plus Ofs bytes. */
-template<typename Type>
-static inline const Type& StructAtOffset(const void *P, unsigned int offset)
-{ return * reinterpret_cast<const Type*> ((const char *) P + offset); }
-template<typename Type>
-static inline Type& StructAtOffset(void *P, unsigned int offset)
-{ return * reinterpret_cast<Type*> ((char *) P + offset); }
-
-/* StructAfter<T>(X) returns the struct T& that is placed after X.
- * Works with X of variable size also.  X must implement get_size() */
-template<typename Type, typename TObject>
-static inline const Type& StructAfter(const TObject &X)
-{ return StructAtOffset<Type>(&X, X.get_size()); }
-template<typename Type, typename TObject>
-static inline Type& StructAfter(TObject &X)
-{ return StructAtOffset<Type>(&X, X.get_size()); }
-
-
-
-/*
- * Size checking
- */
-
-/* Check _assertion in a method environment */
-#define _DEFINE_INSTANCE_ASSERTION1(_line, _assertion) \
-  inline void _instance_assertion_on_line_##_line (void) const \
-  { \
-    static_assert ((_assertion), ""); \
-    ASSERT_INSTANCE_POD (*this); /* Make sure it's POD. */ \
-  }
-# define _DEFINE_INSTANCE_ASSERTION0(_line, _assertion) _DEFINE_INSTANCE_ASSERTION1 (_line, _assertion)
-# define DEFINE_INSTANCE_ASSERTION(_assertion) _DEFINE_INSTANCE_ASSERTION0 (__LINE__, _assertion)
-
-/* Check that _code compiles in a method environment */
-#define _DEFINE_COMPILES_ASSERTION1(_line, _code) \
-  inline void _compiles_assertion_on_line_##_line (void) const \
-  { _code; }
-# define _DEFINE_COMPILES_ASSERTION0(_line, _code) _DEFINE_COMPILES_ASSERTION1 (_line, _code)
-# define DEFINE_COMPILES_ASSERTION(_code) _DEFINE_COMPILES_ASSERTION0 (__LINE__, _code)
-
-
-#define DEFINE_SIZE_STATIC(size) \
-  DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size)); \
-  static const unsigned int static_size = (size); \
-  static const unsigned int min_size = (size); \
-  inline unsigned int get_size (void) const { return (size); }
-
-#define DEFINE_SIZE_UNION(size, _member) \
-  DEFINE_INSTANCE_ASSERTION (0*sizeof(this->u._member.static_size) + sizeof(this->u._member) == (size)); \
-  static const unsigned int min_size = (size)
-
-#define DEFINE_SIZE_MIN(size) \
-  DEFINE_INSTANCE_ASSERTION (sizeof (*this) >= (size)); \
-  static const unsigned int min_size = (size)
-
-#define DEFINE_SIZE_ARRAY(size, array) \
-  DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + sizeof (array[0])); \
-  DEFINE_COMPILES_ASSERTION ((void) array[0].static_size) \
-  static const unsigned int min_size = (size)
-
-#define DEFINE_SIZE_ARRAY2(size, array1, array2) \
-  DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + sizeof (this->array1[0]) + sizeof (this->array2[0])); \
-  DEFINE_COMPILES_ASSERTION ((void) array1[0].static_size; (void) array2[0].static_size) \
-  static const unsigned int min_size = (size)
-
-
-
-/*
- * Dispatch
- */
-
-template <typename Context, typename Return, unsigned int MaxDebugDepth>
-struct hb_dispatch_context_t
-{
-  static const unsigned int max_debug_depth = MaxDebugDepth;
-  typedef Return return_t;
-  template <typename T, typename F>
-  inline bool may_dispatch (const T *obj, const F *format) { return true; }
-  static return_t no_dispatch_return_value (void) { return Context::default_return_value (); }
-};
-
-
-/*
- * Sanitize
- */
-
-/* This limits sanitizing time on really broken fonts. */
-#ifndef HB_SANITIZE_MAX_EDITS
-#define HB_SANITIZE_MAX_EDITS 32
-#endif
-#ifndef HB_SANITIZE_MAX_OPS_FACTOR
-#define HB_SANITIZE_MAX_OPS_FACTOR 8
-#endif
-#ifndef HB_SANITIZE_MAX_OPS_MIN
-#define HB_SANITIZE_MAX_OPS_MIN 16384
-#endif
-
-struct hb_sanitize_context_t :
-       hb_dispatch_context_t<hb_sanitize_context_t, bool, HB_DEBUG_SANITIZE>
-{
-  inline hb_sanitize_context_t (void) :
-        debug_depth (0),
-        start (nullptr), end (nullptr),
-        writable (false), edit_count (0), max_ops (0),
-        blob (nullptr),
-        num_glyphs (0) {}
-
-  inline const char *get_name (void) { return "SANITIZE"; }
-  template <typename T, typename F>
-  inline bool may_dispatch (const T *obj, const F *format)
-  { return format->sanitize (this); }
-  template <typename T>
-  inline return_t dispatch (const T &obj) { return obj.sanitize (this); }
-  static return_t default_return_value (void) { return true; }
-  static return_t no_dispatch_return_value (void) { return false; }
-  bool stop_sublookup_iteration (const return_t r) const { return !r; }
-
-  inline void init (hb_blob_t *b)
-  {
-    this->blob = hb_blob_reference (b);
-    this->writable = false;
-  }
-
-  inline void start_processing (void)
-  {
-    this->start = hb_blob_get_data (this->blob, nullptr);
-    this->end = this->start + this->blob->length;
-    assert (this->start <= this->end); /* Must not overflow. */
-    this->max_ops = MAX ((unsigned int) (this->end - this->start) * HB_SANITIZE_MAX_OPS_FACTOR,
-                         (unsigned) HB_SANITIZE_MAX_OPS_MIN);
-    this->edit_count = 0;
-    this->debug_depth = 0;
-
-    DEBUG_MSG_LEVEL (SANITIZE, start, 0, +1,
-                     "start [%p..%p] (%lu bytes)",
-                     this->start, this->end,
-                     (unsigned long) (this->end - this->start));
-  }
-
-  inline void end_processing (void)
-  {
-    DEBUG_MSG_LEVEL (SANITIZE, this->start, 0, -1,
-                     "end [%p..%p] %u edit requests",
-                     this->start, this->end, this->edit_count);
-
-    hb_blob_destroy (this->blob);
-    this->blob = nullptr;
-    this->start = this->end = nullptr;
-  }
-
-  inline bool check_range (const void *base, unsigned int len) const
-  {
-    const char *p = (const char *) base;
-    bool ok = this->max_ops-- > 0 &&
-              this->start <= p &&
-              p <= this->end &&
-              (unsigned int) (this->end - p) >= len;
-
-    DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
-       "check_range [%p..%p] (%d bytes) in [%p..%p] -> %s",
-       p, p + len, len,
-       this->start, this->end,
-       ok ? "OK" : "OUT-OF-RANGE");
-
-    return likely (ok);
-  }
-
-  inline bool check_array (const void *base, unsigned int record_size, unsigned int len) const
-  {
-    const char *p = (const char *) base;
-    bool overflows = _hb_unsigned_int_mul_overflows (len, record_size);
-    unsigned int array_size = record_size * len;
-    bool ok = !overflows && this->check_range (base, array_size);
-
-    DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
-       "check_array [%p..%p] (%d*%d=%d bytes) in [%p..%p] -> %s",
-       p, p + (record_size * len), record_size, len, (unsigned int) array_size,
-       this->start, this->end,
-       overflows ? "OVERFLOWS" : ok ? "OK" : "OUT-OF-RANGE");
-
-    return likely (ok);
-  }
-
-  template <typename Type>
-  inline bool check_struct (const Type *obj) const
-  {
-    return likely (this->check_range (obj, obj->min_size));
-  }
-
-  inline bool may_edit (const void *base, unsigned int len)
-  {
-    if (this->edit_count >= HB_SANITIZE_MAX_EDITS)
-      return false;
-
-    const char *p = (const char *) base;
-    this->edit_count++;
-
-    DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
-       "may_edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s",
-       this->edit_count,
-       p, p + len, len,
-       this->start, this->end,
-       this->writable ? "GRANTED" : "DENIED");
-
-    return this->writable;
-  }
-
-  template <typename Type, typename ValueType>
-  inline bool try_set (const Type *obj, const ValueType &v) {
-    if (this->may_edit (obj, obj->static_size)) {
-      const_cast<Type *> (obj)->set (v);
-      return true;
-    }
-    return false;
-  }
-
-  mutable unsigned int debug_depth;
-  const char *start, *end;
-  bool writable;
-  unsigned int edit_count;
-  mutable int max_ops;
-  hb_blob_t *blob;
-  unsigned int num_glyphs;
-};
-
-
-
-/* Template to sanitize an object. */
-template <typename Type>
-struct Sanitizer
-{
-  inline Sanitizer (void) {}
-
-  inline hb_blob_t *sanitize (hb_blob_t *blob) {
-    bool sane;
-
-    /* TODO is_sane() stuff */
-
-    c->init (blob);
-
-  retry:
-    DEBUG_MSG_FUNC (SANITIZE, c->start, "start");
-
-    c->start_processing ();
-
-    if (unlikely (!c->start)) {
-      c->end_processing ();
-      return blob;
-    }
-
-    Type *t = CastP<Type> (const_cast<char *> (c->start));
-
-    sane = t->sanitize (c);
-    if (sane) {
-      if (c->edit_count) {
-        DEBUG_MSG_FUNC (SANITIZE, c->start, "passed first round with %d edits; going for second round", c->edit_count);
-
-        /* sanitize again to ensure no toe-stepping */
-        c->edit_count = 0;
-        sane = t->sanitize (c);
-        if (c->edit_count) {
-          DEBUG_MSG_FUNC (SANITIZE, c->start, "requested %d edits in second round; FAILLING", c->edit_count);
-          sane = false;
-        }
-      }
-    } else {
-      unsigned int edit_count = c->edit_count;
-      if (edit_count && !c->writable) {
-        c->start = hb_blob_get_data_writable (blob, nullptr);
-        c->end = c->start + blob->length;
-
-        if (c->start) {
-          c->writable = true;
-          /* ok, we made it writable by relocating.  try again */
-          DEBUG_MSG_FUNC (SANITIZE, c->start, "retry");
-          goto retry;
-        }
-      }
-    }
-
-    c->end_processing ();
-
-    DEBUG_MSG_FUNC (SANITIZE, c->start, sane ? "PASSED" : "FAILED");
-    if (sane)
-    {
-      blob->lock ();
-      return blob;
-    }
-    else
-    {
-      hb_blob_destroy (blob);
-      return hb_blob_get_empty ();
-    }
-  }
-
-  inline void set_num_glyphs (unsigned int num_glyphs) { c->num_glyphs = num_glyphs; }
-
-  private:
-  hb_sanitize_context_t c[1];
-};
-
-
-
-/*
- * Serialize
- */
-
-
-struct hb_serialize_context_t
-{
-  inline hb_serialize_context_t (void *start_, unsigned int size)
-  {
-    this->start = (char *) start_;
-    this->end = this->start + size;
-
-    this->ran_out_of_room = false;
-    this->head = this->start;
-    this->debug_depth = 0;
-  }
-
-  template <typename Type>
-  inline Type *start_serialize (void)
-  {
-    DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, +1,
-                     "start [%p..%p] (%lu bytes)",
-                     this->start, this->end,
-                     (unsigned long) (this->end - this->start));
-
-    return start_embed<Type> ();
-  }
-
-  inline void end_serialize (void)
-  {
-    DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, -1,
-                     "end [%p..%p] serialized %d bytes; %s",
-                     this->start, this->end,
-                     (int) (this->head - this->start),
-                     this->ran_out_of_room ? "RAN OUT OF ROOM" : "did not ran out of room");
-
-  }
-
-  template <typename Type>
-  inline Type *copy (void)
-  {
-    assert (!this->ran_out_of_room);
-    unsigned int len = this->head - this->start;
-    void *p = malloc (len);
-    if (p)
-      memcpy (p, this->start, len);
-    return reinterpret_cast<Type *> (p);
-  }
-
-  template <typename Type>
-  inline Type *allocate_size (unsigned int size)
-  {
-    if (unlikely (this->ran_out_of_room || this->end - this->head < ptrdiff_t (size))) {
-      this->ran_out_of_room = true;
-      return nullptr;
-    }
-    memset (this->head, 0, size);
-    char *ret = this->head;
-    this->head += size;
-    return reinterpret_cast<Type *> (ret);
-  }
-
-  template <typename Type>
-  inline Type *allocate_min (void)
-  {
-    return this->allocate_size<Type> (Type::min_size);
-  }
-
-  template <typename Type>
-  inline Type *start_embed (void)
-  {
-    Type *ret = reinterpret_cast<Type *> (this->head);
-    return ret;
-  }
-
-  template <typename Type>
-  inline Type *embed (const Type &obj)
-  {
-    unsigned int size = obj.get_size ();
-    Type *ret = this->allocate_size<Type> (size);
-    if (unlikely (!ret)) return nullptr;
-    memcpy (ret, obj, size);
-    return ret;
-  }
-
-  template <typename Type>
-  inline Type *extend_min (Type &obj)
-  {
-    unsigned int size = obj.min_size;
-    assert (this->start <= (char *) &obj && (char *) &obj <= this->head && (char *) &obj + size >= this->head);
-    if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->head))) return nullptr;
-    return reinterpret_cast<Type *> (&obj);
-  }
-
-  template <typename Type>
-  inline Type *extend (Type &obj)
-  {
-    unsigned int size = obj.get_size ();
-    assert (this->start < (char *) &obj && (char *) &obj <= this->head && (char *) &obj + size >= this->head);
-    if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->head))) return nullptr;
-    return reinterpret_cast<Type *> (&obj);
-  }
-
-  inline void truncate (void *new_head)
-  {
-    assert (this->start < new_head && new_head <= this->head);
-    this->head = (char *) new_head;
-  }
-
-  unsigned int debug_depth;
-  char *start, *end, *head;
-  bool ran_out_of_room;
-};
-
-template <typename Type>
-struct Supplier
-{
-  inline Supplier (const Type *array, unsigned int len_, unsigned int stride_=sizeof(Type))
-  {
-    head = array;
-    len = len_;
-    stride = stride_;
-  }
-  inline const Type operator [] (unsigned int i) const
-  {
-    if (unlikely (i >= len)) return Type ();
-    return * (const Type *) (const void *) ((const char *) head + stride * i);
-  }
-
-  inline Supplier<Type> & operator += (unsigned int count)
-  {
-    if (unlikely (count > len))
-      count = len;
-    len -= count;
-    head = (const Type *) (const void *) ((const char *) head + stride * count);
-    return *this;
-  }
-
-  private:
-  inline Supplier (const Supplier<Type> &); /* Disallow copy */
-  inline Supplier<Type>& operator= (const Supplier<Type> &); /* Disallow copy */
-
-  unsigned int len;
-  unsigned int stride;
-  const Type *head;
-};
-
-
 /*
  *
  * The OpenType Font File: Data Types
  */
 

@@ -522,101 +50,36 @@
 
 /*
  * Int types
  */
 
-
-template <typename Type, int Bytes> struct BEInt;
-
-template <typename Type>
-struct BEInt<Type, 1>
-{
-  public:
-  inline void set (Type V)
-  {
-    v = V;
-  }
-  inline operator Type (void) const
-  {
-    return v;
-  }
-  private: uint8_t v;
-};
-template <typename Type>
-struct BEInt<Type, 2>
-{
-  public:
-  inline void set (Type V)
-  {
-    v[0] = (V >>  8) & 0xFF;
-    v[1] = (V      ) & 0xFF;
-  }
-  inline operator Type (void) const
-  {
-    return (v[0] <<  8)
-         + (v[1]      );
-  }
-  private: uint8_t v[2];
-};
-template <typename Type>
-struct BEInt<Type, 3>
-{
-  public:
-  inline void set (Type V)
-  {
-    v[0] = (V >> 16) & 0xFF;
-    v[1] = (V >>  8) & 0xFF;
-    v[2] = (V      ) & 0xFF;
-  }
-  inline operator Type (void) const
-  {
-    return (v[0] << 16)
-         + (v[1] <<  8)
-         + (v[2]      );
-  }
-  private: uint8_t v[3];
-};
-template <typename Type>
-struct BEInt<Type, 4>
-{
-  public:
-  inline void set (Type V)
-  {
-    v[0] = (V >> 24) & 0xFF;
-    v[1] = (V >> 16) & 0xFF;
-    v[2] = (V >>  8) & 0xFF;
-    v[3] = (V      ) & 0xFF;
-  }
-  inline operator Type (void) const
-  {
-    return (v[0] << 24)
-         + (v[1] << 16)
-         + (v[2] <<  8)
-         + (v[3]      );
-  }
-  private: uint8_t v[4];
-};
+template <bool is_signed> struct hb_signedness_int;
+template <> struct hb_signedness_int<false> { typedef unsigned int value; };
+template <> struct hb_signedness_int<true>  { typedef   signed int value; };
 
 /* Integer types in big-endian order and no alignment requirement */
 template <typename Type, unsigned int Size>
 struct IntType
 {
-  inline void set (Type i) { v.set (i); }
-  inline operator Type(void) const { return v; }
-  inline bool operator == (const IntType<Type,Size> &o) const { return (Type) v == (Type) o.v; }
-  inline bool operator != (const IntType<Type,Size> &o) const { return !(*this == o); }
-  static inline int cmp (const IntType<Type,Size> *a, const IntType<Type,Size> *b) { return b->cmp (*a); }
+  typedef Type type;
+  typedef typename hb_signedness_int<hb_is_signed<Type>::value>::value wide_type;
+
+  void set (wide_type i) { v.set (i); }
+  operator wide_type () const { return v; }
+  bool operator == (const IntType<Type,Size> &o) const { return (Type) v == (Type) o.v; }
+  bool operator != (const IntType<Type,Size> &o) const { return !(*this == o); }
+  static int cmp (const IntType<Type,Size> *a, const IntType<Type,Size> *b) { return b->cmp (*a); }
   template <typename Type2>
-  inline int cmp (Type2 a) const
+  int cmp (Type2 a) const
   {
     Type b = v;
     if (sizeof (Type) < sizeof (int) && sizeof (Type2) < sizeof (int))
       return (int) a - (int) b;
     else
       return a < b ? -1 : a == b ? 0 : +1;
   }
-  inline bool sanitize (hb_sanitize_context_t *c) const
+  bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (likely (c->check_struct (this)));
   }
   protected:

@@ -629,43 +92,48 @@
 typedef IntType<int8_t,   1> HBINT8;    /* 8-bit signed integer. */
 typedef IntType<uint16_t, 2> HBUINT16;  /* 16-bit unsigned integer. */
 typedef IntType<int16_t,  2> HBINT16;   /* 16-bit signed integer. */
 typedef IntType<uint32_t, 4> HBUINT32;  /* 32-bit unsigned integer. */
 typedef IntType<int32_t,  4> HBINT32;   /* 32-bit signed integer. */
+/* Note: we cannot defined a signed HBINT24 because there's no corresponding C type.
+ * Works for unsigned, but not signed, since we rely on compiler for sign-extension. */
 typedef IntType<uint32_t, 3> HBUINT24;  /* 24-bit unsigned integer. */
 
 /* 16-bit signed integer (HBINT16) that describes a quantity in FUnits. */
 typedef HBINT16 FWORD;
 
+/* 32-bit signed integer (HBINT32) that describes a quantity in FUnits. */
+typedef HBINT32 FWORD32;
+
 /* 16-bit unsigned integer (HBUINT16) that describes a quantity in FUnits. */
 typedef HBUINT16 UFWORD;
 
 /* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */
 struct F2DOT14 : HBINT16
 {
   // 16384 means 1<<14
-  inline float to_float (void) const { return ((int32_t) v) / 16384.f; }
-  inline void set_float (float f) { v.set (round (f * 16384.f)); }
+  float to_float () const  { return ((int32_t) v) / 16384.f; }
+  void set_float (float f) { v.set (round (f * 16384.f)); }
   public:
   DEFINE_SIZE_STATIC (2);
 };
 
 /* 32-bit signed fixed-point number (16.16). */
 struct Fixed : HBINT32
 {
   // 65536 means 1<<16
-  inline float to_float (void) const { return ((int32_t) v) / 65536.f; }
-  inline void set_float (float f) { v.set (round (f * 65536.f)); }
+  float to_float () const  { return ((int32_t) v) / 65536.f; }
+  void set_float (float f) { v.set (round (f * 65536.f)); }
   public:
   DEFINE_SIZE_STATIC (4);
 };
 
 /* Date represented in number of seconds since 12:00 midnight, January 1,
  * 1904. The value is represented as a signed 64-bit integer. */
 struct LONGDATETIME
 {
-  inline bool sanitize (hb_sanitize_context_t *c) const
+  bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (likely (c->check_struct (this)));
   }
   protected:

@@ -678,55 +146,55 @@
 /* Array of four uint8s (length = 32 bits) used to identify a script, language
  * system, feature, or baseline */
 struct Tag : HBUINT32
 {
   /* What the char* converters return is NOT nul-terminated.  Print using "%.4s" */
-  inline operator const char* (void) const { return reinterpret_cast<const char *> (&this->v); }
-  inline operator char* (void) { return reinterpret_cast<char *> (&this->v); }
+  operator const char* () const { return reinterpret_cast<const char *> (&this->v); }
+  operator char* ()             { return reinterpret_cast<char *> (&this->v); }
   public:
   DEFINE_SIZE_STATIC (4);
 };
-DEFINE_NULL_DATA (OT, Tag, "    ");
 
 /* Glyph index number, same as uint16 (length = 16 bits) */
 typedef HBUINT16 GlyphID;
 
-/* Name-table index, same as uint16 (length = 16 bits) */
-typedef HBUINT16 NameID;
-
 /* Script/language-system/feature index */
 struct Index : HBUINT16 {
-  static const unsigned int NOT_FOUND_INDEX = 0xFFFFu;
+  static constexpr unsigned NOT_FOUND_INDEX = 0xFFFFu;
 };
-DEFINE_NULL_DATA (OT, Index, "\xff\xff");
+DECLARE_NULL_NAMESPACE_BYTES (OT, Index);
+
+typedef Index NameID;
 
 /* Offset, Null offset = 0 */
-template <typename Type>
+template <typename Type, bool has_null=true>
 struct Offset : Type
 {
-  inline bool is_null (void) const { return 0 == *this; }
+  typedef Type type;
+
+  bool is_null () const { return has_null && 0 == *this; }
 
-  inline void *serialize (hb_serialize_context_t *c, const void *base)
+  void *serialize (hb_serialize_context_t *c, const void *base)
   {
     void *t = c->start_embed<void> ();
     this->set ((char *) t - (char *) base); /* TODO(serialize) Overflow? */
     return t;
   }
 
   public:
-  DEFINE_SIZE_STATIC (sizeof(Type));
+  DEFINE_SIZE_STATIC (sizeof (Type));
 };
 
 typedef Offset<HBUINT16> Offset16;
 typedef Offset<HBUINT32> Offset32;
 
 
 /* CheckSum */
 struct CheckSum : HBUINT32
 {
   /* This is reference implementation from the spec. */
-  static inline uint32_t CalcTableChecksum (const HBUINT32 *Table, uint32_t Length)
+  static uint32_t CalcTableChecksum (const HBUINT32 *Table, uint32_t Length)
   {
     uint32_t Sum = 0L;
     assert (0 == (Length & 3));
     const HBUINT32 *EndPtr = Table + Length / HBUINT32::static_size;
 

@@ -734,11 +202,11 @@
       Sum += *Table++;
     return Sum;
   }
 
   /* Note: data should be 4byte aligned and have 4byte padding at the end. */
-  inline void set_for_data (const void *data, unsigned int length)
+  void set_for_data (const void *data, unsigned int length)
   { set (CalcTableChecksum ((const HBUINT32 *) data, length)); }
 
   public:
   DEFINE_SIZE_STATIC (4);
 };

@@ -749,100 +217,189 @@
  */
 
 template <typename FixedType=HBUINT16>
 struct FixedVersion
 {
-  inline uint32_t to_int (void) const { return (major << (sizeof(FixedType) * 8)) + minor; }
+  uint32_t to_int () const { return (major << (sizeof (FixedType) * 8)) + minor; }
 
-  inline bool sanitize (hb_sanitize_context_t *c) const
+  bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
   }
 
   FixedType major;
   FixedType minor;
   public:
-  DEFINE_SIZE_STATIC (2 * sizeof(FixedType));
+  DEFINE_SIZE_STATIC (2 * sizeof (FixedType));
 };
 
 
-
 /*
  * Template subclasses of Offset that do the dereferencing.
  * Use: (base+offset)
  */
 
-template <typename Type, typename OffsetType=HBUINT16>
-struct OffsetTo : Offset<OffsetType>
+template <typename Type, bool has_null>
+struct _hb_has_null
+{
+  static const Type *get_null () { return nullptr; }
+  static Type *get_crap ()       { return nullptr; }
+};
+template <typename Type>
+struct _hb_has_null<Type, true>
+{
+  static const Type *get_null () { return &Null(Type); }
+  static Type *get_crap ()       { return &Crap(Type); }
+};
+
+template <typename Type, typename OffsetType=HBUINT16, bool has_null=true>
+struct OffsetTo : Offset<OffsetType, has_null>
 {
-  inline const Type& operator () (const void *base) const
+  const Type& operator () (const void *base) const
   {
-    unsigned int offset = *this;
-    if (unlikely (!offset)) return Null(Type);
-    return StructAtOffset<const Type> (base, offset);
+    if (unlikely (this->is_null ())) return *_hb_has_null<Type, has_null>::get_null ();
+    return StructAtOffset<const Type> (base, *this);
   }
-  inline Type& operator () (void *base) const
+  Type& operator () (void *base) const
   {
-    unsigned int offset = *this;
-    if (unlikely (!offset)) return Crap(Type);
-    return StructAtOffset<Type> (base, offset);
+    if (unlikely (this->is_null ())) return *_hb_has_null<Type, has_null>::get_crap ();
+    return StructAtOffset<Type> (base, *this);
   }
 
-  inline Type& serialize (hb_serialize_context_t *c, const void *base)
+  Type& serialize (hb_serialize_context_t *c, const void *base)
   {
     return * (Type *) Offset<OffsetType>::serialize (c, base);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  template <typename T>
+  void serialize_subset (hb_subset_context_t *c, const T &src, const void *base)
+  {
+    if (&src == &Null (T))
+    {
+      this->set (0);
+      return;
+    }
+    serialize (c->serializer, base);
+    if (!src.subset (c))
+      this->set (0);
+  }
+
+  bool sanitize_shallow (hb_sanitize_context_t *c, const void *base) const
   {
     TRACE_SANITIZE (this);
     if (unlikely (!c->check_struct (this))) return_trace (false);
-    unsigned int offset = *this;
-    if (unlikely (!offset)) return_trace (true);
-    if (unlikely (!c->check_range (base, offset))) return_trace (false);
-    const Type &obj = StructAtOffset<Type> (base, offset);
-    return_trace (likely (obj.sanitize (c)) || neuter (c));
+    if (unlikely (this->is_null ())) return_trace (true);
+    if (unlikely (!c->check_range (base, *this))) return_trace (false);
+    return_trace (true);
   }
-  template <typename T>
-  inline bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const
+
+  bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
     TRACE_SANITIZE (this);
-    if (unlikely (!c->check_struct (this))) return_trace (false);
-    unsigned int offset = *this;
-    if (unlikely (!offset)) return_trace (true);
-    if (unlikely (!c->check_range (base, offset))) return_trace (false);
-    const Type &obj = StructAtOffset<Type> (base, offset);
-    return_trace (likely (obj.sanitize (c, user_data)) || neuter (c));
+    return_trace (sanitize_shallow (c, base) &&
+                  (this->is_null () ||
+                   StructAtOffset<Type> (base, *this).sanitize (c) ||
+                   neuter (c)));
+  }
+  template <typename T1>
+  bool sanitize (hb_sanitize_context_t *c, const void *base, T1 d1) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (sanitize_shallow (c, base) &&
+                  (this->is_null () ||
+                   StructAtOffset<Type> (base, *this).sanitize (c, d1) ||
+                   neuter (c)));
+  }
+  template <typename T1, typename T2>
+  bool sanitize (hb_sanitize_context_t *c, const void *base, T1 d1, T2 d2) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (sanitize_shallow (c, base) &&
+                  (this->is_null () ||
+                   StructAtOffset<Type> (base, *this).sanitize (c, d1, d2) ||
+                   neuter (c)));
+  }
+  template <typename T1, typename T2, typename T3>
+  bool sanitize (hb_sanitize_context_t *c, const void *base, T1 d1, T2 d2, T3 d3) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (sanitize_shallow (c, base) &&
+                  (this->is_null () ||
+                   StructAtOffset<Type> (base, *this).sanitize (c, d1, d2, d3) ||
+                   neuter (c)));
   }
 
   /* Set the offset to Null */
-  inline bool neuter (hb_sanitize_context_t *c) const {
+  bool neuter (hb_sanitize_context_t *c) const
+  {
+    if (!has_null) return false;
     return c->try_set (this, 0);
   }
-  DEFINE_SIZE_STATIC (sizeof(OffsetType));
+  DEFINE_SIZE_STATIC (sizeof (OffsetType));
 };
-template <typename Type> struct LOffsetTo : OffsetTo<Type, HBUINT32> {};
-template <typename Base, typename OffsetType, typename Type>
-static inline const Type& operator + (const Base &base, const OffsetTo<Type, OffsetType> &offset) { return offset (base); }
-template <typename Base, typename OffsetType, typename Type>
-static inline Type& operator + (Base &base, OffsetTo<Type, OffsetType> &offset) { return offset (base); }
+/* Partial specializations. */
+template <typename Type,                               bool has_null=true> struct   LOffsetTo : OffsetTo<Type, HBUINT32,   has_null> {};
+template <typename Type, typename OffsetType=HBUINT16                    > struct  NNOffsetTo : OffsetTo<Type, OffsetType, false> {};
+template <typename Type                                                  > struct LNNOffsetTo : OffsetTo<Type, HBUINT32,   false> {};
+
+template <typename Base, typename OffsetType, bool has_null, typename Type>
+static inline const Type& operator + (const Base &base, const OffsetTo<Type, OffsetType, has_null> &offset) { return offset (base); }
+template <typename Base, typename OffsetType, bool has_null, typename Type>
+static inline Type& operator + (Base &base, OffsetTo<Type, OffsetType, has_null> &offset) { return offset (base); }
 
 
 /*
  * Array Types
  */
 
-
-/* TODO Use it in ArrayOf, HeadlessArrayOf, and other places around the code base?? */
 template <typename Type>
 struct UnsizedArrayOf
 {
-  inline const Type& operator [] (unsigned int i) const { return arrayZ[i]; }
-  inline Type& operator [] (unsigned int i) { return arrayZ[i]; }
+  typedef Type item_t;
+  static constexpr unsigned item_size = hb_static_size (Type);
+
+  HB_NO_CREATE_COPY_ASSIGN_TEMPLATE (UnsizedArrayOf, Type);
+
+  const Type& operator [] (int i_) const
+  {
+    unsigned int i = (unsigned int) i_;
+    const Type *p = &arrayZ[i];
+    if (unlikely (p < arrayZ)) return Null (Type); /* Overflowed. */
+    return *p;
+  }
+  Type& operator [] (int i_)
+  {
+    unsigned int i = (unsigned int) i_;
+    Type *p = &arrayZ[i];
+    if (unlikely (p < arrayZ)) return Crap (Type); /* Overflowed. */
+    return *p;
+  }
+
+  unsigned int get_size (unsigned int len) const
+  { return len * Type::static_size; }
+
+  template <typename T> operator T * () { return arrayZ; }
+  template <typename T> operator const T * () const { return arrayZ; }
+  hb_array_t<Type> as_array (unsigned int len)
+  { return hb_array (arrayZ, len); }
+  hb_array_t<const Type> as_array (unsigned int len) const
+  { return hb_array (arrayZ, len); }
+  operator hb_array_t<Type> ()             { return as_array (); }
+  operator hb_array_t<const Type> () const { return as_array (); }
+
+  template <typename T>
+  Type &lsearch (unsigned int len, const T &x, Type &not_found = Crap (Type))
+  { return *as_array (len).lsearch (x, &not_found); }
+  template <typename T>
+  const Type &lsearch (unsigned int len, const T &x, const Type &not_found = Null (Type)) const
+  { return *as_array (len).lsearch (x, &not_found); }
+
+  void qsort (unsigned int len, unsigned int start = 0, unsigned int end = (unsigned int) -1)
+  { as_array (len).qsort (start, end); }
 
-  inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
+  bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
   {
     TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c, count))) return_trace (false);
 
     /* Note: for structs that do not reference other structs,

@@ -854,121 +411,164 @@
      */
     (void) (false && arrayZ[0].sanitize (c));
 
     return_trace (true);
   }
-  inline bool sanitize (hb_sanitize_context_t *c, unsigned int count, const void *base) const
+  bool sanitize (hb_sanitize_context_t *c, unsigned int count, const void *base) const
   {
     TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c, count))) return_trace (false);
     for (unsigned int i = 0; i < count; i++)
       if (unlikely (!arrayZ[i].sanitize (c, base)))
         return_trace (false);
     return_trace (true);
   }
   template <typename T>
-  inline bool sanitize (hb_sanitize_context_t *c, unsigned int count, const void *base, T user_data) const
+  bool sanitize (hb_sanitize_context_t *c, unsigned int count, const void *base, T user_data) const
   {
     TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c, count))) return_trace (false);
     for (unsigned int i = 0; i < count; i++)
       if (unlikely (!arrayZ[i].sanitize (c, base, user_data)))
         return_trace (false);
     return_trace (true);
   }
 
-  inline bool sanitize_shallow (hb_sanitize_context_t *c, unsigned int count) const
+  bool sanitize_shallow (hb_sanitize_context_t *c, unsigned int count) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_array (arrayZ, arrayZ[0].static_size, count));
+    return_trace (c->check_array (arrayZ, count));
   }
 
   public:
   Type  arrayZ[VAR];
   public:
-  DEFINE_SIZE_ARRAY (0, arrayZ);
+  DEFINE_SIZE_UNBOUNDED (0);
 };
 
 /* Unsized array of offset's */
-template <typename Type, typename OffsetType>
-struct UnsizedOffsetArrayOf : UnsizedArrayOf<OffsetTo<Type, OffsetType> > {};
+template <typename Type, typename OffsetType, bool has_null=true>
+struct UnsizedOffsetArrayOf : UnsizedArrayOf<OffsetTo<Type, OffsetType, has_null> > {};
 
 /* Unsized array of offsets relative to the beginning of the array itself. */
-template <typename Type, typename OffsetType>
-struct UnsizedOffsetListOf : UnsizedOffsetArrayOf<Type, OffsetType>
+template <typename Type, typename OffsetType, bool has_null=true>
+struct UnsizedOffsetListOf : UnsizedOffsetArrayOf<Type, OffsetType, has_null>
 {
-  inline const Type& operator [] (unsigned int i) const
+  const Type& operator [] (int i_) const
   {
-    return this+this->arrayZ[i];
+    unsigned int i = (unsigned int) i_;
+    const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i];
+    if (unlikely (p < this->arrayZ)) return Null (Type); /* Overflowed. */
+    return this+*p;
+  }
+  Type& operator [] (int i_)
+  {
+    unsigned int i = (unsigned int) i_;
+    const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i];
+    if (unlikely (p < this->arrayZ)) return Crap (Type); /* Overflowed. */
+    return this+*p;
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
+
+  bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
   {
     TRACE_SANITIZE (this);
-    return_trace ((UnsizedOffsetArrayOf<Type, OffsetType>::sanitize (c, count, this)));
+    return_trace ((UnsizedOffsetArrayOf<Type, OffsetType, has_null>::sanitize (c, count, this)));
   }
   template <typename T>
-  inline bool sanitize (hb_sanitize_context_t *c, unsigned int count, T user_data) const
+  bool sanitize (hb_sanitize_context_t *c, unsigned int count, T user_data) const
   {
     TRACE_SANITIZE (this);
-    return_trace ((UnsizedOffsetArrayOf<Type, OffsetType>::sanitize (c, count, this, user_data)));
+    return_trace ((UnsizedOffsetArrayOf<Type, OffsetType, has_null>::sanitize (c, count, this, user_data)));
   }
 };
 
+/* An array with sorted elements.  Supports binary searching. */
+template <typename Type>
+struct SortedUnsizedArrayOf : UnsizedArrayOf<Type>
+{
+  hb_sorted_array_t<Type> as_array (unsigned int len)
+  { return hb_sorted_array (this->arrayZ, len); }
+  hb_sorted_array_t<const Type> as_array (unsigned int len) const
+  { return hb_sorted_array (this->arrayZ, len); }
+  operator hb_sorted_array_t<Type> ()             { return as_array (); }
+  operator hb_sorted_array_t<const Type> () const { return as_array (); }
+
+  template <typename T>
+  Type &bsearch (unsigned int len, const T &x, Type &not_found = Crap (Type))
+  { return *as_array (len).bsearch (x, &not_found); }
+  template <typename T>
+  const Type &bsearch (unsigned int len, const T &x, const Type &not_found = Null (Type)) const
+  { return *as_array (len).bsearch (x, &not_found); }
+  template <typename T>
+  bool bfind (unsigned int len, const T &x, unsigned int *i = nullptr,
+                     hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
+                     unsigned int to_store = (unsigned int) -1) const
+  { return as_array (len).bfind (x, i, not_found, to_store); }
+};
+
 
 /* An array with a number of elements. */
 template <typename Type, typename LenType=HBUINT16>
 struct ArrayOf
 {
-  const Type *sub_array (unsigned int start_offset, unsigned int *pcount /* IN/OUT */) const
-  {
-    unsigned int count = len;
-    if (unlikely (start_offset > count))
-      count = 0;
-    else
-      count -= start_offset;
-    count = MIN (count, *pcount);
-    *pcount = count;
-    return arrayZ + start_offset;
-  }
+  typedef Type item_t;
+  static constexpr unsigned item_size = hb_static_size (Type);
+
+  HB_NO_CREATE_COPY_ASSIGN_TEMPLATE2 (ArrayOf, Type, LenType);
 
-  inline const Type& operator [] (unsigned int i) const
+  const Type& operator [] (int i_) const
   {
-    if (unlikely (i >= len)) return Null(Type);
+    unsigned int i = (unsigned int) i_;
+    if (unlikely (i >= len)) return Null (Type);
     return arrayZ[i];
   }
-  inline Type& operator [] (unsigned int i)
+  Type& operator [] (int i_)
   {
-    if (unlikely (i >= len)) return Crap(Type);
+    unsigned int i = (unsigned int) i_;
+    if (unlikely (i >= len)) return Crap (Type);
     return arrayZ[i];
   }
-  inline unsigned int get_size (void) const
+
+  unsigned int get_size () const
   { return len.static_size + len * Type::static_size; }
 
-  inline bool serialize (hb_serialize_context_t *c,
-                         unsigned int items_len)
+  hb_array_t<Type> as_array ()
+  { return hb_array (arrayZ, len); }
+  hb_array_t<const Type> as_array () const
+  { return hb_array (arrayZ, len); }
+  operator hb_array_t<Type> (void)             { return as_array (); }
+  operator hb_array_t<const Type> (void) const { return as_array (); }
+
+  hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const
+  { return as_array ().sub_array (start_offset, count);}
+  hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const
+  { return as_array ().sub_array (start_offset, count);}
+  hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int count)
+  { return as_array ().sub_array (start_offset, count);}
+  hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */)
+  { return as_array ().sub_array (start_offset, count);}
+
+  bool serialize (hb_serialize_context_t *c, unsigned int items_len)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return_trace (false);
     len.set (items_len); /* TODO(serialize) Overflow? */
     if (unlikely (!c->extend (*this))) return_trace (false);
     return_trace (true);
   }
-
-  inline bool serialize (hb_serialize_context_t *c,
-                         Supplier<Type> &items,
-                         unsigned int items_len)
+  template <typename T>
+  bool serialize (hb_serialize_context_t *c, hb_array_t<const T> items)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!serialize (c, items_len))) return_trace (false);
-    for (unsigned int i = 0; i < items_len; i++)
-      arrayZ[i] = items[i];
-    items += items_len;
+    if (unlikely (!serialize (c, items.length))) return_trace (false);
+    for (unsigned int i = 0; i < items.length; i++)
+      hb_assign (arrayZ[i], items[i]);
     return_trace (true);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) const
+  bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c))) return_trace (false);
 
     /* Note: for structs that do not reference other structs,

@@ -980,52 +580,46 @@
      */
     (void) (false && arrayZ[0].sanitize (c));
 
     return_trace (true);
   }
-  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
     TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c))) return_trace (false);
     unsigned int count = len;
     for (unsigned int i = 0; i < count; i++)
       if (unlikely (!arrayZ[i].sanitize (c, base)))
         return_trace (false);
     return_trace (true);
   }
   template <typename T>
-  inline bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const
+  bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const
   {
     TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c))) return_trace (false);
     unsigned int count = len;
     for (unsigned int i = 0; i < count; i++)
       if (unlikely (!arrayZ[i].sanitize (c, base, user_data)))
         return_trace (false);
     return_trace (true);
   }
 
-  template <typename SearchType>
-  inline int lsearch (const SearchType &x) const
-  {
-    unsigned int count = len;
-    for (unsigned int i = 0; i < count; i++)
-      if (!this->arrayZ[i].cmp (x))
-        return i;
-    return -1;
-  }
+  template <typename T>
+  Type &lsearch (const T &x, Type &not_found = Crap (Type))
+  { return *as_array ().lsearch (x, &not_found); }
+  template <typename T>
+  const Type &lsearch (const T &x, const Type &not_found = Null (Type)) const
+  { return *as_array ().lsearch (x, &not_found); }
 
-  inline void qsort (void)
-  {
-    ::qsort (arrayZ, len, sizeof (Type), Type::cmp);
-  }
+  void qsort (unsigned int start = 0, unsigned int end = (unsigned int) -1)
+  { as_array ().qsort (start, end); }
 
-  private:
-  inline bool sanitize_shallow (hb_sanitize_context_t *c) const
+  bool sanitize_shallow (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (len.sanitize (c) && c->check_array (arrayZ, Type::static_size, len));
+    return_trace (len.sanitize (c) && c->check_array (arrayZ, len));
   }
 
   public:
   LenType len;
   Type arrayZ[VAR];

@@ -1034,75 +628,94 @@
 };
 template <typename Type> struct LArrayOf : ArrayOf<Type, HBUINT32> {};
 typedef ArrayOf<HBUINT8, HBUINT8> PString;
 
 /* Array of Offset's */
-template <typename Type, typename OffsetType=HBUINT16>
-struct OffsetArrayOf : ArrayOf<OffsetTo<Type, OffsetType> > {};
+template <typename Type>
+struct OffsetArrayOf : ArrayOf<OffsetTo<Type, HBUINT16> > {};
+template <typename Type>
+struct LOffsetArrayOf : ArrayOf<OffsetTo<Type, HBUINT32> > {};
+template <typename Type>
+struct LOffsetLArrayOf : ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT32> {};
 
 /* Array of offsets relative to the beginning of the array itself. */
 template <typename Type>
 struct OffsetListOf : OffsetArrayOf<Type>
 {
-  inline const Type& operator [] (unsigned int i) const
+  const Type& operator [] (int i_) const
   {
-    if (unlikely (i >= this->len)) return Null(Type);
+    unsigned int i = (unsigned int) i_;
+    if (unlikely (i >= this->len)) return Null (Type);
     return this+this->arrayZ[i];
   }
-  inline const Type& operator [] (unsigned int i)
+  const Type& operator [] (int i_)
   {
-    if (unlikely (i >= this->len)) return Crap(Type);
+    unsigned int i = (unsigned int) i_;
+    if (unlikely (i >= this->len)) return Crap (Type);
     return this+this->arrayZ[i];
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) const
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    struct OffsetListOf<Type> *out = c->serializer->embed (*this);
+    if (unlikely (!out)) return_trace (false);
+    unsigned int count = this->len;
+    for (unsigned int i = 0; i < count; i++)
+      out->arrayZ[i].serialize_subset (c, (*this)[i], out);
+    return_trace (true);
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (OffsetArrayOf<Type>::sanitize (c, this));
   }
   template <typename T>
-  inline bool sanitize (hb_sanitize_context_t *c, T user_data) const
+  bool sanitize (hb_sanitize_context_t *c, T user_data) const
   {
     TRACE_SANITIZE (this);
     return_trace (OffsetArrayOf<Type>::sanitize (c, this, user_data));
   }
 };
 
-
 /* An array starting at second element. */
 template <typename Type, typename LenType=HBUINT16>
 struct HeadlessArrayOf
 {
-  inline const Type& operator [] (unsigned int i) const
+  static constexpr unsigned item_size = Type::static_size;
+
+  HB_NO_CREATE_COPY_ASSIGN_TEMPLATE2 (HeadlessArrayOf, Type, LenType);
+
+  const Type& operator [] (int i_) const
   {
-    if (unlikely (i >= len || !i)) return Null(Type);
+    unsigned int i = (unsigned int) i_;
+    if (unlikely (i >= lenP1 || !i)) return Null (Type);
     return arrayZ[i-1];
   }
-  inline Type& operator [] (unsigned int i)
+  Type& operator [] (int i_)
   {
-    if (unlikely (i >= len || !i)) return Crap(Type);
+    unsigned int i = (unsigned int) i_;
+    if (unlikely (i >= lenP1 || !i)) return Crap (Type);
     return arrayZ[i-1];
   }
-  inline unsigned int get_size (void) const
-  { return len.static_size + (len ? len - 1 : 0) * Type::static_size; }
+  unsigned int get_size () const
+  { return lenP1.static_size + (lenP1 ? lenP1 - 1 : 0) * Type::static_size; }
 
-  inline bool serialize (hb_serialize_context_t *c,
-                         Supplier<Type> &items,
-                         unsigned int items_len)
+  bool serialize (hb_serialize_context_t *c,
+                  hb_array_t<const Type> items)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return_trace (false);
-    len.set (items_len); /* TODO(serialize) Overflow? */
-    if (unlikely (!items_len)) return_trace (true);
+    lenP1.set (items.length + 1); /* TODO(serialize) Overflow? */
     if (unlikely (!c->extend (*this))) return_trace (false);
-    for (unsigned int i = 0; i < items_len - 1; i++)
+    for (unsigned int i = 0; i < items.length; i++)
       arrayZ[i] = items[i];
-    items += items_len - 1;
     return_trace (true);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) const
+  bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c))) return_trace (false);
 
     /* Note: for structs that do not reference other structs,

@@ -1116,185 +729,280 @@
 
     return_trace (true);
   }
 
   private:
-  inline bool sanitize_shallow (hb_sanitize_context_t *c) const
+  bool sanitize_shallow (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (len.sanitize (c) &&
-                  (!len || c->check_array (arrayZ, Type::static_size, len - 1)));
+    return_trace (lenP1.sanitize (c) &&
+                  (!lenP1 || c->check_array (arrayZ, lenP1 - 1)));
   }
 
   public:
-  LenType len;
+  LenType       lenP1;
   Type arrayZ[VAR];
   public:
   DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
 };
 
-
-/*
- * An array with sorted elements.  Supports binary searching.
- */
+/* An array storing length-1. */
 template <typename Type, typename LenType=HBUINT16>
-struct SortedArrayOf : ArrayOf<Type, LenType>
+struct ArrayOfM1
 {
-  template <typename SearchType>
-  inline int bsearch (const SearchType &x) const
+  HB_NO_CREATE_COPY_ASSIGN_TEMPLATE2 (ArrayOfM1, Type, LenType);
+
+  const Type& operator [] (int i_) const
   {
-    /* Hand-coded bsearch here since this is in the hot inner loop. */
-    const Type *arr = this->arrayZ;
-    int min = 0, max = (int) this->len - 1;
-    while (min <= max)
+    unsigned int i = (unsigned int) i_;
+    if (unlikely (i > lenM1)) return Null (Type);
+    return arrayZ[i];
+  }
+  Type& operator [] (int i_)
     {
-      int mid = (min + max) / 2;
-      int c = arr[mid].cmp (x);
-      if (c < 0)
-        max = mid - 1;
-      else if (c > 0)
-        min = mid + 1;
-      else
-        return mid;
+    unsigned int i = (unsigned int) i_;
+    if (unlikely (i > lenM1)) return Crap (Type);
+    return arrayZ[i];
+  }
+  unsigned int get_size () const
+  { return lenM1.static_size + (lenM1 + 1) * Type::static_size; }
+
+  template <typename T>
+  bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!sanitize_shallow (c))) return_trace (false);
+    unsigned int count = lenM1 + 1;
+    for (unsigned int i = 0; i < count; i++)
+      if (unlikely (!arrayZ[i].sanitize (c, base, user_data)))
+        return_trace (false);
+    return_trace (true);
     }
-    return -1;
+
+  private:
+  bool sanitize_shallow (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (lenM1.sanitize (c) &&
+                  (c->check_array (arrayZ, lenM1 + 1)));
   }
+
+  public:
+  LenType       lenM1;
+  Type          arrayZ[VAR];
+  public:
+  DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
+};
+
+/* An array with sorted elements.  Supports binary searching. */
+template <typename Type, typename LenType=HBUINT16>
+struct SortedArrayOf : ArrayOf<Type, LenType>
+{
+  hb_sorted_array_t<Type> as_array ()
+  { return hb_sorted_array (this->arrayZ, this->len); }
+  hb_sorted_array_t<const Type> as_array () const
+  { return hb_sorted_array (this->arrayZ, this->len); }
+  operator hb_sorted_array_t<Type> ()             { return as_array (); }
+  operator hb_sorted_array_t<const Type> () const { return as_array (); }
+
+  hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const
+  { return as_array ().sub_array (start_offset, count);}
+  hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const
+  { return as_array ().sub_array (start_offset, count);}
+  hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int count)
+  { return as_array ().sub_array (start_offset, count);}
+  hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */)
+  { return as_array ().sub_array (start_offset, count);}
+
+  template <typename T>
+  Type &bsearch (const T &x, Type &not_found = Crap (Type))
+  { return *as_array ().bsearch (x, &not_found); }
+  template <typename T>
+  const Type &bsearch (const T &x, const Type &not_found = Null (Type)) const
+  { return *as_array ().bsearch (x, &not_found); }
+  template <typename T>
+  bool bfind (const T &x, unsigned int *i = nullptr,
+                     hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
+                     unsigned int to_store = (unsigned int) -1) const
+  { return as_array ().bfind (x, i, not_found, to_store); }
 };
 
 /*
  * Binary-search arrays
  */
 
+template <typename LenType=HBUINT16>
 struct BinSearchHeader
 {
-  inline operator uint32_t (void) const { return len; }
+  operator uint32_t () const { return len; }
 
-  inline bool sanitize (hb_sanitize_context_t *c) const
+  bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
   }
 
-  inline void set (unsigned int v)
+  void set (unsigned int v)
   {
     len.set (v);
     assert (len == v);
-    entrySelector.set (MAX (1u, _hb_bit_storage (v)) - 1);
+    entrySelector.set (MAX (1u, hb_bit_storage (v)) - 1);
     searchRange.set (16 * (1u << entrySelector));
     rangeShift.set (v * 16 > searchRange
                     ? 16 * v - searchRange
                     : 0);
   }
 
   protected:
-  HBUINT16      len;
-  HBUINT16      searchRange;
-  HBUINT16      entrySelector;
-  HBUINT16      rangeShift;
+  LenType       len;
+  LenType       searchRange;
+  LenType       entrySelector;
+  LenType       rangeShift;
 
   public:
   DEFINE_SIZE_STATIC (8);
 };
 
-template <typename Type>
-struct BinSearchArrayOf : SortedArrayOf<Type, BinSearchHeader> {};
-
+template <typename Type, typename LenType=HBUINT16>
+struct BinSearchArrayOf : SortedArrayOf<Type, BinSearchHeader<LenType> > {};
 
-/* Lazy struct and blob loaders. */
 
-/* Logic is shared between hb_lazy_loader_t and hb_table_lazy_loader_t */
-template <typename T>
-struct hb_lazy_loader_t
+struct VarSizedBinSearchHeader
 {
-  inline void init (hb_face_t *face_)
+
+  bool sanitize (hb_sanitize_context_t *c) const
   {
-    face = face_;
-    instance = nullptr;
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
   }
 
-  inline void fini (void)
-  {
-    if (instance && instance != &Null(T))
+  HBUINT16      unitSize;       /* Size of a lookup unit for this search in bytes. */
+  HBUINT16      nUnits;         /* Number of units of the preceding size to be searched. */
+  HBUINT16      searchRange;    /* The value of unitSize times the largest power of 2
+                                 * that is less than or equal to the value of nUnits. */
+  HBUINT16      entrySelector;  /* The log base 2 of the largest power of 2 less than
+                                 * or equal to the value of nUnits. */
+  HBUINT16      rangeShift;     /* The value of unitSize times the difference of the
+                                 * value of nUnits minus the largest power of 2 less
+                                 * than or equal to the value of nUnits. */
+  public:
+  DEFINE_SIZE_STATIC (10);
+};
+
+template <typename Type>
+struct VarSizedBinSearchArrayOf
+{
+  static constexpr unsigned item_size = Type::static_size;
+
+  HB_NO_CREATE_COPY_ASSIGN_TEMPLATE (VarSizedBinSearchArrayOf, Type);
+
+  bool last_is_terminator () const
     {
-      instance->fini();
-      free (instance);
-    }
+    if (unlikely (!header.nUnits)) return false;
+
+    /* Gah.
+     *
+     * "The number of termination values that need to be included is table-specific.
+     * The value that indicates binary search termination is 0xFFFF." */
+    const HBUINT16 *words = &StructAtOffset<HBUINT16> (&bytesZ, (header.nUnits - 1) * header.unitSize);
+    unsigned int count = Type::TerminationWordCount;
+    for (unsigned int i = 0; i < count; i++)
+      if (words[i] != 0xFFFFu)
+        return false;
+    return true;
   }
 
-  inline const T* get (void) const
-  {
-  retry:
-    T *p = (T *) hb_atomic_ptr_get (&instance);
-    if (unlikely (!p))
+  const Type& operator [] (int i_) const
     {
-      p = (T *) calloc (1, sizeof (T));
-      if (unlikely (!p))
-        p = const_cast<T *> (&Null(T));
-      else
-        p->init (face);
-      if (unlikely (!hb_atomic_ptr_cmpexch (const_cast<T **>(&instance), nullptr, p)))
-      {
-        if (p != &Null(T))
-          p->fini ();
-        goto retry;
-      }
+    unsigned int i = (unsigned int) i_;
+    if (unlikely (i >= get_length ())) return Null (Type);
+    return StructAtOffset<Type> (&bytesZ, i * header.unitSize);
     }
-    return p;
+  Type& operator [] (int i_)
+  {
+    unsigned int i = (unsigned int) i_;
+    if (unlikely (i >= get_length ())) return Crap (Type);
+    return StructAtOffset<Type> (&bytesZ, i * header.unitSize);
   }
+  unsigned int get_length () const
+  { return header.nUnits - last_is_terminator (); }
+  unsigned int get_size () const
+  { return header.static_size + header.nUnits * header.unitSize; }
 
-  inline const T* operator-> (void) const
+  bool sanitize (hb_sanitize_context_t *c) const
   {
-    return get ();
-  }
+    TRACE_SANITIZE (this);
+    if (unlikely (!sanitize_shallow (c))) return_trace (false);
 
-  private:
-  hb_face_t *face;
-  T *instance;
-};
+    /* Note: for structs that do not reference other structs,
+     * we do not need to call their sanitize() as we already did
+     * a bound check on the aggregate array size.  We just include
+     * a small unreachable expression to make sure the structs
+     * pointed to do have a simple sanitize(), ie. they do not
+     * reference other structs via offsets.
+     */
+    (void) (false && StructAtOffset<Type> (&bytesZ, 0).sanitize (c));
 
-/* Logic is shared between hb_lazy_loader_t and hb_table_lazy_loader_t */
-template <typename T>
-struct hb_table_lazy_loader_t
-{
-  inline void init (hb_face_t *face_)
+    return_trace (true);
+  }
+  bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
-    face = face_;
-    blob = nullptr;
+    TRACE_SANITIZE (this);
+    if (unlikely (!sanitize_shallow (c))) return_trace (false);
+    unsigned int count = get_length ();
+    for (unsigned int i = 0; i < count; i++)
+      if (unlikely (!(*this)[i].sanitize (c, base)))
+        return_trace (false);
+    return_trace (true);
   }
-
-  inline void fini (void)
+  template <typename T>
+  bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const
   {
-    hb_blob_destroy (blob);
+    TRACE_SANITIZE (this);
+    if (unlikely (!sanitize_shallow (c))) return_trace (false);
+    unsigned int count = get_length ();
+    for (unsigned int i = 0; i < count; i++)
+      if (unlikely (!(*this)[i].sanitize (c, base, user_data)))
+        return_trace (false);
+    return_trace (true);
   }
 
-  inline const T* get (void) const
-  {
-  retry:
-    hb_blob_t *blob_ = (hb_blob_t *) hb_atomic_ptr_get (&blob);
-    if (unlikely (!blob_))
+  template <typename T>
+  const Type *bsearch (const T &key) const
     {
-      blob_ = OT::Sanitizer<T>().sanitize (face->reference_table (T::tableTag));
-      if (!hb_atomic_ptr_cmpexch (&blob, nullptr, blob_))
+    unsigned int size = header.unitSize;
+    int min = 0, max = (int) get_length () - 1;
+    while (min <= max)
       {
-        hb_blob_destroy (blob_);
-        goto retry;
-      }
-      blob = blob_;
+      int mid = ((unsigned int) min + (unsigned int) max) / 2;
+      const Type *p = (const Type *) (((const char *) &bytesZ) + (mid * size));
+      int c = p->cmp (key);
+      if (c < 0) max = mid - 1;
+      else if (c > 0) min = mid + 1;
+      else return p;
     }
-    return blob_->as<T> ();
+    return nullptr;
   }
 
-  inline const T* operator-> (void) const
+  private:
+  bool sanitize_shallow (hb_sanitize_context_t *c) const
   {
-    return get();
+    TRACE_SANITIZE (this);
+    return_trace (header.sanitize (c) &&
+                  Type::static_size <= header.unitSize &&
+                  c->check_range (bytesZ.arrayZ,
+                                  header.nUnits,
+                                  header.unitSize));
   }
 
-  private:
-  hb_face_t *face;
-  mutable hb_blob_t *blob;
+  protected:
+  VarSizedBinSearchHeader       header;
+  UnsizedArrayOf<HBUINT8>       bytesZ;
+  public:
+  DEFINE_SIZE_ARRAY (10, bytesZ);
 };
 
 
 } /* namespace OT */
 
 
-#endif /* HB_OPEN_TYPE_PRIVATE_HH */
+#endif /* HB_OPEN_TYPE_HH */
< prev index next >