Imported Upstream version 1.8.1
[platform/upstream/harfbuzz.git] / src / hb-open-type-private.hh
index 5d33199..8180287 100644 (file)
@@ -31,6 +31,7 @@
 
 #include "hb-private.hh"
 #include "hb-debug.hh"
+#include "hb-blob-private.hh"
 #include "hb-face-private.hh"
 
 
@@ -127,46 +128,6 @@ static inline Type& StructAfter(TObject &X)
 
 
 /*
- * Null objects
- */
-
-/* Global nul-content Null pool.  Enlarge as necessary. */
-
-#define HB_NULL_POOL_SIZE 264
-static_assert (HB_NULL_POOL_SIZE % sizeof (void *) == 0, "Align HB_NULL_POOL_SIZE.");
-
-#ifdef HB_NO_VISIBILITY
-static
-#else
-extern HB_INTERNAL
-#endif
-const void * const _hb_NullPool[HB_NULL_POOL_SIZE / sizeof (void *)]
-#ifdef HB_NO_VISIBILITY
-= {}
-#endif
-;
-
-/* Generic nul-content Null objects. */
-template <typename Type>
-static inline const Type& Null (void) {
-  static_assert (sizeof (Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE.");
-  return *CastP<Type> (_hb_NullPool);
-}
-
-/* Specializaiton for arbitrary-content arbitrary-sized Null objects. */
-#define DEFINE_NULL_DATA(Type, data) \
-static const char _Null##Type[sizeof (Type) + 1] = data; /* +1 is for nul-termination in data */ \
-template <> \
-/*static*/ inline const Type& Null<Type> (void) { \
-  return *CastP<Type> (_Null##Type); \
-} /* The following line really exists such that we end in a place needing semicolon */ \
-static_assert (Type::min_size + 1 <= sizeof (_Null##Type), "Null pool too small.  Enlarge.")
-
-/* Accessor macro. */
-#define Null(Type) Null<Type>()
-
-
-/*
  * Dispatch
  */
 
@@ -225,7 +186,7 @@ struct hb_sanitize_context_t :
   inline void start_processing (void)
   {
     this->start = hb_blob_get_data (this->blob, nullptr);
-    this->end = this->start + hb_blob_get_length (this->blob);
+    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);
@@ -288,7 +249,7 @@ struct hb_sanitize_context_t :
     return likely (this->check_range (obj, obj->min_size));
   }
 
-  inline bool may_edit (const void *base HB_UNUSED, unsigned int len HB_UNUSED)
+  inline bool may_edit (const void *base, unsigned int len)
   {
     if (this->edit_count >= HB_SANITIZE_MAX_EDITS)
       return false;
@@ -368,7 +329,7 @@ struct Sanitizer
       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 + hb_blob_get_length (blob);
+       c->end = c->start + blob->length;
 
        if (c->start) {
          c->writable = true;
@@ -383,19 +344,17 @@ struct Sanitizer
 
     DEBUG_MSG_FUNC (SANITIZE, c->start, sane ? "PASSED" : "FAILED");
     if (sane)
+    {
+      blob->lock ();
       return blob;
-    else {
+    }
+    else
+    {
       hb_blob_destroy (blob);
       return hb_blob_get_empty ();
     }
   }
 
-  static const Type* lock_instance (hb_blob_t *blob) {
-    hb_blob_make_immutable (blob);
-    const char *base = hb_blob_get_data (blob, nullptr);
-    return unlikely (!base) ? &Null(Type) : CastP<Type> (base);
-  }
-
   inline void set_num_glyphs (unsigned int num_glyphs) { c->num_glyphs = num_glyphs; }
 
   private:
@@ -672,7 +631,7 @@ 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. */
-typedef IntType<uint32_t, 3> UINT24;   /* 24-bit unsigned integer. */
+typedef IntType<uint32_t, 3> HBUINT24; /* 24-bit unsigned integer. */
 
 /* 16-bit signed integer (HBINT16) that describes a quantity in FUnits. */
 typedef HBINT16 FWORD;
@@ -683,17 +642,19 @@ typedef HBUINT16 UFWORD;
 /* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */
 struct F2DOT14 : HBINT16
 {
-  //inline float to_float (void) const { return ???; }
-  //inline void set_float (float f) { v.set (f * ???); }
+  // 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)); }
   public:
   DEFINE_SIZE_STATIC (2);
 };
 
 /* 32-bit signed fixed-point number (16.16). */
-struct Fixed: HBINT32
+struct Fixed : HBINT32
 {
-  inline float to_float (void) const { return ((int32_t) v) / 65536.0; }
-  inline void set_float (float f) { v.set (round (f * 65536.0)); }
+  // 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)); }
   public:
   DEFINE_SIZE_STATIC (4);
 };
@@ -724,16 +685,19 @@ struct Tag : HBUINT32
   public:
   DEFINE_SIZE_STATIC (4);
 };
-DEFINE_NULL_DATA (Tag, "    ");
+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;
 };
-DEFINE_NULL_DATA (Index, "\xff\xff");
+DEFINE_NULL_DATA (OT, Index, "\xff\xff");
 
 /* Offset, Null offset = 0 */
 template <typename Type>
@@ -815,6 +779,12 @@ struct OffsetTo : Offset<OffsetType>
   {
     unsigned int offset = *this;
     if (unlikely (!offset)) return Null(Type);
+    return StructAtOffset<const Type> (base, offset);
+  }
+  inline Type& operator () (void *base) const
+  {
+    unsigned int offset = *this;
+    if (unlikely (!offset)) return Crap(Type);
     return StructAtOffset<Type> (base, offset);
   }
 
@@ -862,6 +832,89 @@ static inline Type& operator + (Base &base, OffsetTo<Type, OffsetType> &offset)
  * 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]; }
+
+  inline 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,
+     * 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 && arrayZ[0].sanitize (c));
+
+    return_trace (true);
+  }
+  inline 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
+  {
+    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
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_array (arrayZ, arrayZ[0].static_size, count));
+  }
+
+  public:
+  Type arrayZ[VAR];
+  public:
+  DEFINE_SIZE_ARRAY (0, arrayZ);
+};
+
+/* Unsized array of offset's */
+template <typename Type, typename OffsetType>
+struct UnsizedOffsetArrayOf : UnsizedArrayOf<OffsetTo<Type, OffsetType> > {};
+
+/* Unsized array of offsets relative to the beginning of the array itself. */
+template <typename Type, typename OffsetType>
+struct UnsizedOffsetListOf : UnsizedOffsetArrayOf<Type, OffsetType>
+{
+  inline const Type& operator [] (unsigned int i) const
+  {
+    return this+this->arrayZ[i];
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace ((UnsizedOffsetArrayOf<Type, OffsetType>::sanitize (c, count, this)));
+  }
+  template <typename T>
+  inline 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)));
+  }
+};
+
+
 /* An array with a number of elements. */
 template <typename Type, typename LenType=HBUINT16>
 struct ArrayOf
@@ -875,17 +928,18 @@ struct ArrayOf
       count -= start_offset;
     count = MIN (count, *pcount);
     *pcount = count;
-    return array + start_offset;
+    return arrayZ + start_offset;
   }
 
   inline const Type& operator [] (unsigned int i) const
   {
     if (unlikely (i >= len)) return Null(Type);
-    return array[i];
+    return arrayZ[i];
   }
   inline Type& operator [] (unsigned int i)
   {
-    return array[i];
+    if (unlikely (i >= len)) return Crap(Type);
+    return arrayZ[i];
   }
   inline unsigned int get_size (void) const
   { return len.static_size + len * Type::static_size; }
@@ -907,7 +961,7 @@ struct ArrayOf
     TRACE_SERIALIZE (this);
     if (unlikely (!serialize (c, items_len))) return_trace (false);
     for (unsigned int i = 0; i < items_len; i++)
-      array[i] = items[i];
+      arrayZ[i] = items[i];
     items += items_len;
     return_trace (true);
   }
@@ -924,7 +978,7 @@ struct ArrayOf
      * pointed to do have a simple sanitize(), ie. they do not
      * reference other structs via offsets.
      */
-    (void) (false && array[0].sanitize (c));
+    (void) (false && arrayZ[0].sanitize (c));
 
     return_trace (true);
   }
@@ -934,7 +988,7 @@ struct ArrayOf
     if (unlikely (!sanitize_shallow (c))) return_trace (false);
     unsigned int count = len;
     for (unsigned int i = 0; i < count; i++)
-      if (unlikely (!array[i].sanitize (c, base)))
+      if (unlikely (!arrayZ[i].sanitize (c, base)))
         return_trace (false);
     return_trace (true);
   }
@@ -945,7 +999,7 @@ struct ArrayOf
     if (unlikely (!sanitize_shallow (c))) return_trace (false);
     unsigned int count = len;
     for (unsigned int i = 0; i < count; i++)
-      if (unlikely (!array[i].sanitize (c, base, user_data)))
+      if (unlikely (!arrayZ[i].sanitize (c, base, user_data)))
         return_trace (false);
     return_trace (true);
   }
@@ -955,28 +1009,28 @@ struct ArrayOf
   {
     unsigned int count = len;
     for (unsigned int i = 0; i < count; i++)
-      if (!this->array[i].cmp (x))
+      if (!this->arrayZ[i].cmp (x))
         return i;
     return -1;
   }
 
   inline void qsort (void)
   {
-    ::qsort (array, len, sizeof (Type), Type::cmp);
+    ::qsort (arrayZ, len, sizeof (Type), Type::cmp);
   }
 
   private:
   inline bool sanitize_shallow (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (len.sanitize (c) && c->check_array (array, Type::static_size, len));
+    return_trace (len.sanitize (c) && c->check_array (arrayZ, Type::static_size, len));
   }
 
   public:
   LenType len;
-  Type array[VAR];
+  Type arrayZ[VAR];
   public:
-  DEFINE_SIZE_ARRAY (sizeof (LenType), array);
+  DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
 };
 template <typename Type> struct LArrayOf : ArrayOf<Type, HBUINT32> {};
 
@@ -991,7 +1045,12 @@ struct OffsetListOf : OffsetArrayOf<Type>
   inline const Type& operator [] (unsigned int i) const
   {
     if (unlikely (i >= this->len)) return Null(Type);
-    return this+this->array[i];
+    return this+this->arrayZ[i];
+  }
+  inline const Type& operator [] (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
@@ -1015,7 +1074,12 @@ struct HeadlessArrayOf
   inline const Type& operator [] (unsigned int i) const
   {
     if (unlikely (i >= len || !i)) return Null(Type);
-    return array[i-1];
+    return arrayZ[i-1];
+  }
+  inline Type& operator [] (unsigned int i)
+  {
+    if (unlikely (i >= len || !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; }
@@ -1030,7 +1094,7 @@ struct HeadlessArrayOf
     if (unlikely (!items_len)) return_trace (true);
     if (unlikely (!c->extend (*this))) return_trace (false);
     for (unsigned int i = 0; i < items_len - 1; i++)
-      array[i] = items[i];
+      arrayZ[i] = items[i];
     items += items_len - 1;
     return_trace (true);
   }
@@ -1047,7 +1111,7 @@ struct HeadlessArrayOf
      * pointed to do have a simple sanitize(), ie. they do not
      * reference other structs via offsets.
      */
-    (void) (false && array[0].sanitize (c));
+    (void) (false && arrayZ[0].sanitize (c));
 
     return_trace (true);
   }
@@ -1057,14 +1121,14 @@ struct HeadlessArrayOf
   {
     TRACE_SANITIZE (this);
     return_trace (len.sanitize (c) &&
-                 (!len || c->check_array (array, Type::static_size, len - 1)));
+                 (!len || c->check_array (arrayZ, Type::static_size, len - 1)));
   }
 
   public:
   LenType len;
-  Type array[VAR];
+  Type arrayZ[VAR];
   public:
-  DEFINE_SIZE_ARRAY (sizeof (LenType), array);
+  DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
 };
 
 
@@ -1078,7 +1142,7 @@ struct SortedArrayOf : ArrayOf<Type, LenType>
   inline int bsearch (const SearchType &x) const
   {
     /* Hand-coded bsearch here since this is in the hot inner loop. */
-    const Type *arr = this->array;
+    const Type *arr = this->arrayZ;
     int min = 0, max = (int) this->len - 1;
     while (min <= max)
     {
@@ -1113,18 +1177,18 @@ struct BinSearchHeader
   {
     len.set (v);
     assert (len == v);
-    entrySelectorZ.set (MAX (1u, _hb_bit_storage (v)) - 1);
-    searchRangeZ.set (16 * (1u << entrySelectorZ));
-    rangeShiftZ.set (v * 16 > searchRangeZ
-                     ? 16 * v - searchRangeZ
-                     : 0);
+    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     searchRangeZ;
-  HBUINT16     entrySelectorZ;
-  HBUINT16     rangeShiftZ;
+  HBUINT16     searchRange;
+  HBUINT16     entrySelector;
+  HBUINT16     rangeShift;
 
   public:
   DEFINE_SIZE_STATIC (8);
@@ -1136,7 +1200,7 @@ struct BinSearchArrayOf : SortedArrayOf<Type, BinSearchHeader> {};
 
 /* Lazy struct and blob loaders. */
 
-/* Logic is shared between hb_lazy_loader_t and hb_lazy_table_loader_t */
+/* Logic is shared between hb_lazy_loader_t and hb_table_lazy_loader_t */
 template <typename T>
 struct hb_lazy_loader_t
 {
@@ -1148,7 +1212,7 @@ struct hb_lazy_loader_t
 
   inline void fini (void)
   {
-    if (instance && instance != &OT::Null(T))
+    if (instance && instance != &Null(T))
     {
       instance->fini();
       free (instance);
@@ -1163,12 +1227,12 @@ struct hb_lazy_loader_t
     {
       p = (T *) calloc (1, sizeof (T));
       if (unlikely (!p))
-        p = const_cast<T *> (&OT::Null(T));
+        p = const_cast<T *> (&Null(T));
       else
        p->init (face);
       if (unlikely (!hb_atomic_ptr_cmpexch (const_cast<T **>(&instance), nullptr, p)))
       {
-       if (p != &OT::Null(T))
+       if (p != &Null(T))
          p->fini ();
        goto retry;
       }
@@ -1186,15 +1250,14 @@ struct hb_lazy_loader_t
   T *instance;
 };
 
-/* Logic is shared between hb_lazy_loader_t and hb_lazy_table_loader_t */
+/* Logic is shared between hb_lazy_loader_t and hb_table_lazy_loader_t */
 template <typename T>
-struct hb_lazy_table_loader_t
+struct hb_table_lazy_loader_t
 {
   inline void init (hb_face_t *face_)
   {
     face = face_;
     blob = nullptr;
-    instance = nullptr;
   }
 
   inline void fini (void)
@@ -1205,19 +1268,18 @@ struct hb_lazy_table_loader_t
   inline const T* get (void) const
   {
   retry:
-    T *p = (T *) hb_atomic_ptr_get (&instance);
-    if (unlikely (!p))
+    hb_blob_t *blob_ = (hb_blob_t *) hb_atomic_ptr_get (&blob);
+    if (unlikely (!blob_))
     {
-      hb_blob_t *blob_ = OT::Sanitizer<T>().sanitize (face->reference_table (T::tableTag));
-      p = const_cast<T *>(OT::Sanitizer<T>::lock_instance (blob_));
-      if (!hb_atomic_ptr_cmpexch (const_cast<T **>(&instance), nullptr, p))
+      blob_ = OT::Sanitizer<T>().sanitize (face->reference_table (T::tableTag));
+      if (!hb_atomic_ptr_cmpexch (&blob, nullptr, blob_))
       {
        hb_blob_destroy (blob_);
        goto retry;
       }
       blob = blob_;
     }
-    return p;
+    return blob_->as<T> ();
   }
 
   inline const T* operator-> (void) const
@@ -1225,10 +1287,9 @@ struct hb_lazy_table_loader_t
     return get();
   }
 
+  private:
   hb_face_t *face;
   mutable hb_blob_t *blob;
-  private:
-  mutable T *instance;
 };