LCOV - code coverage report
Current view: top level - gfx/harfbuzz/src - hb-open-type-private.hh (source / functions) Hit Total Coverage
Test: output.info Lines: 189 347 54.5 %
Date: 2017-07-14 16:53:18 Functions: 372 1161 32.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
       3             :  * Copyright © 2012  Google, Inc.
       4             :  *
       5             :  *  This is part of HarfBuzz, a text shaping library.
       6             :  *
       7             :  * Permission is hereby granted, without written agreement and without
       8             :  * license or royalty fees, to use, copy, modify, and distribute this
       9             :  * software and its documentation for any purpose, provided that the
      10             :  * above copyright notice and the following two paragraphs appear in
      11             :  * all copies of this software.
      12             :  *
      13             :  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
      14             :  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
      15             :  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
      16             :  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
      17             :  * DAMAGE.
      18             :  *
      19             :  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
      20             :  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
      21             :  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
      22             :  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
      23             :  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
      24             :  *
      25             :  * Red Hat Author(s): Behdad Esfahbod
      26             :  * Google Author(s): Behdad Esfahbod
      27             :  */
      28             : 
      29             : #ifndef HB_OPEN_TYPE_PRIVATE_HH
      30             : #define HB_OPEN_TYPE_PRIVATE_HH
      31             : 
      32             : #include "hb-private.hh"
      33             : #include "hb-face-private.hh"
      34             : 
      35             : 
      36             : namespace OT {
      37             : 
      38             : 
      39             : 
      40             : /*
      41             :  * Casts
      42             :  */
      43             : 
      44             : /* Cast to struct T, reference to reference */
      45             : template<typename Type, typename TObject>
      46        1494 : static inline const Type& CastR(const TObject &X)
      47        1494 : { return reinterpret_cast<const Type&> (X); }
      48             : template<typename Type, typename TObject>
      49           0 : static inline Type& CastR(TObject &X)
      50           0 : { return reinterpret_cast<Type&> (X); }
      51             : 
      52             : /* Cast to struct T, pointer to pointer */
      53             : template<typename Type, typename TObject>
      54         520 : static inline const Type* CastP(const TObject *X)
      55         520 : { return reinterpret_cast<const Type*> (X); }
      56             : template<typename Type, typename TObject>
      57         492 : static inline Type* CastP(TObject *X)
      58         492 : { return reinterpret_cast<Type*> (X); }
      59             : 
      60             : /* StructAtOffset<T>(P,Ofs) returns the struct T& that is placed at memory
      61             :  * location pointed to by P plus Ofs bytes. */
      62             : template<typename Type>
      63       15784 : static inline const Type& StructAtOffset(const void *P, unsigned int offset)
      64       15784 : { return * reinterpret_cast<const Type*> ((const char *) P + offset); }
      65             : template<typename Type>
      66           0 : static inline Type& StructAtOffset(void *P, unsigned int offset)
      67           0 : { return * reinterpret_cast<Type*> ((char *) P + offset); }
      68             : 
      69             : /* StructAfter<T>(X) returns the struct T& that is placed after X.
      70             :  * Works with X of variable size also.  X must implement get_size() */
      71             : template<typename Type, typename TObject>
      72          56 : static inline const Type& StructAfter(const TObject &X)
      73          56 : { return StructAtOffset<Type>(&X, X.get_size()); }
      74             : template<typename Type, typename TObject>
      75           0 : static inline Type& StructAfter(TObject &X)
      76           0 : { return StructAtOffset<Type>(&X, X.get_size()); }
      77             : 
      78             : 
      79             : 
      80             : /*
      81             :  * Size checking
      82             :  */
      83             : 
      84             : /* Check _assertion in a method environment */
      85             : #define _DEFINE_INSTANCE_ASSERTION1(_line, _assertion) \
      86             :   inline void _instance_assertion_on_line_##_line (void) const \
      87             :   { \
      88             :     ASSERT_STATIC (_assertion); \
      89             :     ASSERT_INSTANCE_POD (*this); /* Make sure it's POD. */ \
      90             :   }
      91             : # define _DEFINE_INSTANCE_ASSERTION0(_line, _assertion) _DEFINE_INSTANCE_ASSERTION1 (_line, _assertion)
      92             : # define DEFINE_INSTANCE_ASSERTION(_assertion) _DEFINE_INSTANCE_ASSERTION0 (__LINE__, _assertion)
      93             : 
      94             : /* Check that _code compiles in a method environment */
      95             : #define _DEFINE_COMPILES_ASSERTION1(_line, _code) \
      96             :   inline void _compiles_assertion_on_line_##_line (void) const \
      97             :   { _code; }
      98             : # define _DEFINE_COMPILES_ASSERTION0(_line, _code) _DEFINE_COMPILES_ASSERTION1 (_line, _code)
      99             : # define DEFINE_COMPILES_ASSERTION(_code) _DEFINE_COMPILES_ASSERTION0 (__LINE__, _code)
     100             : 
     101             : 
     102             : #define DEFINE_SIZE_STATIC(size) \
     103             :   DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size)); \
     104             :   static const unsigned int static_size = (size); \
     105             :   static const unsigned int min_size = (size); \
     106             :   inline unsigned int get_size (void) const { return (size); }
     107             : 
     108             : #define DEFINE_SIZE_UNION(size, _member) \
     109             :   DEFINE_INSTANCE_ASSERTION (0*sizeof(this->u._member.static_size) + sizeof(this->u._member) == (size)); \
     110             :   static const unsigned int min_size = (size)
     111             : 
     112             : #define DEFINE_SIZE_MIN(size) \
     113             :   DEFINE_INSTANCE_ASSERTION (sizeof (*this) >= (size)); \
     114             :   static const unsigned int min_size = (size)
     115             : 
     116             : #define DEFINE_SIZE_ARRAY(size, array) \
     117             :   DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + sizeof (array[0])); \
     118             :   DEFINE_COMPILES_ASSERTION ((void) array[0].static_size) \
     119             :   static const unsigned int min_size = (size)
     120             : 
     121             : #define DEFINE_SIZE_ARRAY2(size, array1, array2) \
     122             :   DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + sizeof (this->array1[0]) + sizeof (this->array2[0])); \
     123             :   DEFINE_COMPILES_ASSERTION ((void) array1[0].static_size; (void) array2[0].static_size) \
     124             :   static const unsigned int min_size = (size)
     125             : 
     126             : 
     127             : 
     128             : /*
     129             :  * Null objects
     130             :  */
     131             : 
     132             : /* Global nul-content Null pool.  Enlarge as necessary. */
     133             : /* TODO This really should be a extern HB_INTERNAL and defined somewhere... */
     134             : static const void *_NullPool[(256+8) / sizeof (void *)];
     135             : 
     136             : /* Generic nul-content Null objects. */
     137             : template <typename Type>
     138         480 : static inline const Type& Null (void) {
     139             :   ASSERT_STATIC (sizeof (Type) <= sizeof (_NullPool));
     140         480 :   return *CastP<Type> (_NullPool);
     141             : }
     142             : 
     143             : /* Specializaiton for arbitrary-content arbitrary-sized Null objects. */
     144             : #define DEFINE_NULL_DATA(Type, data) \
     145             : static const char _Null##Type[sizeof (Type) + 1] = data; /* +1 is for nul-termination in data */ \
     146             : template <> \
     147             : /*static*/ inline const Type& Null<Type> (void) { \
     148             :   return *CastP<Type> (_Null##Type); \
     149             : } /* The following line really exists such that we end in a place needing semicolon */ \
     150             : ASSERT_STATIC (Type::min_size + 1 <= sizeof (_Null##Type))
     151             : 
     152             : /* Accessor macro. */
     153             : #define Null(Type) Null<Type>()
     154             : 
     155             : 
     156             : /*
     157             :  * Dispatch
     158             :  */
     159             : 
     160             : template <typename Context, typename Return, unsigned int MaxDebugDepth>
     161         774 : struct hb_dispatch_context_t
     162             : {
     163             :   static const unsigned int max_debug_depth = MaxDebugDepth;
     164             :   typedef Return return_t;
     165             :   template <typename T, typename F>
     166        1384 :   inline bool may_dispatch (const T *obj, const F *format) { return true; }
     167           0 :   static return_t no_dispatch_return_value (void) { return Context::default_return_value (); }
     168             : };
     169             : 
     170             : 
     171             : /*
     172             :  * Sanitize
     173             :  */
     174             : 
     175             : #ifndef HB_DEBUG_SANITIZE
     176             : #define HB_DEBUG_SANITIZE (HB_DEBUG+0)
     177             : #endif
     178             : 
     179             : 
     180             : #define TRACE_SANITIZE(this) \
     181             :         hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace \
     182             :         (&c->debug_depth, c->get_name (), this, HB_FUNC, \
     183             :          "");
     184             : 
     185             : /* This limits sanitizing time on really broken fonts. */
     186             : #ifndef HB_SANITIZE_MAX_EDITS
     187             : #define HB_SANITIZE_MAX_EDITS 32
     188             : #endif
     189             : 
     190             : struct hb_sanitize_context_t :
     191             :        hb_dispatch_context_t<hb_sanitize_context_t, bool, HB_DEBUG_SANITIZE>
     192             : {
     193          14 :   inline hb_sanitize_context_t (void) :
     194             :         debug_depth (0),
     195             :         start (NULL), end (NULL),
     196             :         writable (false), edit_count (0),
     197          14 :         blob (NULL) {}
     198             : 
     199       23674 :   inline const char *get_name (void) { return "SANITIZE"; }
     200             :   template <typename T, typename F>
     201         204 :   inline bool may_dispatch (const T *obj, const F *format)
     202         204 :   { return format->sanitize (this); }
     203             :   template <typename T>
     204         102 :   inline return_t dispatch (const T &obj) { return obj.sanitize (this); }
     205         102 :   static return_t default_return_value (void) { return true; }
     206           0 :   static return_t no_dispatch_return_value (void) { return false; }
     207         102 :   bool stop_sublookup_iteration (const return_t r) const { return !r; }
     208             : 
     209          14 :   inline void init (hb_blob_t *b)
     210             :   {
     211          14 :     this->blob = hb_blob_reference (b);
     212          14 :     this->writable = false;
     213          14 :   }
     214             : 
     215          14 :   inline void start_processing (void)
     216             :   {
     217          14 :     this->start = hb_blob_get_data (this->blob, NULL);
     218          14 :     this->end = this->start + hb_blob_get_length (this->blob);
     219          14 :     assert (this->start <= this->end); /* Must not overflow. */
     220          14 :     this->edit_count = 0;
     221          14 :     this->debug_depth = 0;
     222             : 
     223          14 :     DEBUG_MSG_LEVEL (SANITIZE, start, 0, +1,
     224             :                      "start [%p..%p] (%lu bytes)",
     225             :                      this->start, this->end,
     226          14 :                      (unsigned long) (this->end - this->start));
     227          14 :   }
     228             : 
     229          14 :   inline void end_processing (void)
     230             :   {
     231          14 :     DEBUG_MSG_LEVEL (SANITIZE, this->start, 0, -1,
     232             :                      "end [%p..%p] %u edit requests",
     233          14 :                      this->start, this->end, this->edit_count);
     234             : 
     235          14 :     hb_blob_destroy (this->blob);
     236          14 :     this->blob = NULL;
     237          14 :     this->start = this->end = NULL;
     238          14 :   }
     239             : 
     240       25634 :   inline bool check_range (const void *base, unsigned int len) const
     241             :   {
     242       25634 :     const char *p = (const char *) base;
     243       25634 :     bool ok = this->start <= p && p <= this->end && (unsigned int) (this->end - p) >= len;
     244             : 
     245       25634 :     DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
     246             :        "check_range [%p..%p] (%d bytes) in [%p..%p] -> %s",
     247             :        p, p + len, len,
     248             :        this->start, this->end,
     249       25634 :        ok ? "OK" : "OUT-OF-RANGE");
     250             : 
     251       25634 :     return likely (ok);
     252             :   }
     253             : 
     254        3268 :   inline bool check_array (const void *base, unsigned int record_size, unsigned int len) const
     255             :   {
     256        3268 :     const char *p = (const char *) base;
     257        3268 :     bool overflows = _hb_unsigned_int_mul_overflows (len, record_size);
     258        3268 :     unsigned int array_size = record_size * len;
     259        3268 :     bool ok = !overflows && this->check_range (base, array_size);
     260             : 
     261        3268 :     DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
     262             :        "check_array [%p..%p] (%d*%d=%d bytes) in [%p..%p] -> %s",
     263             :        p, p + (record_size * len), record_size, len, (unsigned int) array_size,
     264             :        this->start, this->end,
     265        3268 :        overflows ? "OVERFLOWS" : ok ? "OK" : "OUT-OF-RANGE");
     266             : 
     267        3268 :     return likely (ok);
     268             :   }
     269             : 
     270             :   template <typename Type>
     271       17022 :   inline bool check_struct (const Type *obj) const
     272             :   {
     273       17022 :     return likely (this->check_range (obj, obj->min_size));
     274             :   }
     275             : 
     276           0 :   inline bool may_edit (const void *base HB_UNUSED, unsigned int len HB_UNUSED)
     277             :   {
     278           0 :     if (this->edit_count >= HB_SANITIZE_MAX_EDITS)
     279           0 :       return false;
     280             : 
     281           0 :     const char *p = (const char *) base;
     282           0 :     this->edit_count++;
     283             : 
     284           0 :     DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
     285             :        "may_edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s",
     286             :        this->edit_count,
     287             :        p, p + len, len,
     288             :        this->start, this->end,
     289           0 :        this->writable ? "GRANTED" : "DENIED");
     290             : 
     291           0 :     return this->writable;
     292             :   }
     293             : 
     294             :   template <typename Type, typename ValueType>
     295           0 :   inline bool try_set (const Type *obj, const ValueType &v) {
     296           0 :     if (this->may_edit (obj, obj->static_size)) {
     297           0 :       const_cast<Type *> (obj)->set (v);
     298           0 :       return true;
     299             :     }
     300           0 :     return false;
     301             :   }
     302             : 
     303             :   mutable unsigned int debug_depth;
     304             :   const char *start, *end;
     305             :   bool writable;
     306             :   unsigned int edit_count;
     307             :   hb_blob_t *blob;
     308             : };
     309             : 
     310             : 
     311             : 
     312             : /* Template to sanitize an object. */
     313             : template <typename Type>
     314             : struct Sanitizer
     315             : {
     316          14 :   static hb_blob_t *sanitize (hb_blob_t *blob) {
     317          14 :     hb_sanitize_context_t c[1];
     318             :     bool sane;
     319             : 
     320             :     /* TODO is_sane() stuff */
     321             : 
     322          14 :     c->init (blob);
     323             : 
     324             :   retry:
     325          14 :     DEBUG_MSG_FUNC (SANITIZE, c->start, "start");
     326             : 
     327          14 :     c->start_processing ();
     328             : 
     329          14 :     if (unlikely (!c->start)) {
     330           2 :       c->end_processing ();
     331           2 :       return blob;
     332             :     }
     333             : 
     334          12 :     Type *t = CastP<Type> (const_cast<char *> (c->start));
     335             : 
     336          12 :     sane = t->sanitize (c);
     337          12 :     if (sane) {
     338          12 :       if (c->edit_count) {
     339           0 :         DEBUG_MSG_FUNC (SANITIZE, c->start, "passed first round with %d edits; going for second round", c->edit_count);
     340             : 
     341             :         /* sanitize again to ensure no toe-stepping */
     342           0 :         c->edit_count = 0;
     343           0 :         sane = t->sanitize (c);
     344           0 :         if (c->edit_count) {
     345           0 :           DEBUG_MSG_FUNC (SANITIZE, c->start, "requested %d edits in second round; FAILLING", c->edit_count);
     346           0 :           sane = false;
     347             :         }
     348             :       }
     349             :     } else {
     350           0 :       unsigned int edit_count = c->edit_count;
     351           0 :       if (edit_count && !c->writable) {
     352           0 :         c->start = hb_blob_get_data_writable (blob, NULL);
     353           0 :         c->end = c->start + hb_blob_get_length (blob);
     354             : 
     355           0 :         if (c->start) {
     356           0 :           c->writable = true;
     357             :           /* ok, we made it writable by relocating.  try again */
     358           0 :           DEBUG_MSG_FUNC (SANITIZE, c->start, "retry");
     359           0 :           goto retry;
     360             :         }
     361             :       }
     362             :     }
     363             : 
     364          12 :     c->end_processing ();
     365             : 
     366          12 :     DEBUG_MSG_FUNC (SANITIZE, c->start, sane ? "PASSED" : "FAILED");
     367          12 :     if (sane)
     368          12 :       return blob;
     369             :     else {
     370           0 :       hb_blob_destroy (blob);
     371           0 :       return hb_blob_get_empty ();
     372             :     }
     373             :   }
     374             : 
     375          14 :   static const Type* lock_instance (hb_blob_t *blob) {
     376          14 :     hb_blob_make_immutable (blob);
     377          14 :     const char *base = hb_blob_get_data (blob, NULL);
     378          14 :     return unlikely (!base) ? &Null(Type) : CastP<Type> (base);
     379             :   }
     380             : };
     381             : 
     382             : 
     383             : 
     384             : /*
     385             :  * Serialize
     386             :  */
     387             : 
     388             : #ifndef HB_DEBUG_SERIALIZE
     389             : #define HB_DEBUG_SERIALIZE (HB_DEBUG+0)
     390             : #endif
     391             : 
     392             : 
     393             : #define TRACE_SERIALIZE(this) \
     394             :         hb_auto_trace_t<HB_DEBUG_SERIALIZE, bool> trace \
     395             :         (&c->debug_depth, "SERIALIZE", c, HB_FUNC, \
     396             :          "");
     397             : 
     398             : 
     399             : struct hb_serialize_context_t
     400             : {
     401           0 :   inline hb_serialize_context_t (void *start_, unsigned int size)
     402           0 :   {
     403           0 :     this->start = (char *) start_;
     404           0 :     this->end = this->start + size;
     405             : 
     406           0 :     this->ran_out_of_room = false;
     407           0 :     this->head = this->start;
     408           0 :     this->debug_depth = 0;
     409           0 :   }
     410             : 
     411             :   template <typename Type>
     412           0 :   inline Type *start_serialize (void)
     413             :   {
     414           0 :     DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, +1,
     415             :                      "start [%p..%p] (%lu bytes)",
     416             :                      this->start, this->end,
     417             :                      (unsigned long) (this->end - this->start));
     418             : 
     419           0 :     return start_embed<Type> ();
     420             :   }
     421             : 
     422           0 :   inline void end_serialize (void)
     423             :   {
     424           0 :     DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, -1,
     425             :                      "end [%p..%p] serialized %d bytes; %s",
     426             :                      this->start, this->end,
     427             :                      (int) (this->head - this->start),
     428           0 :                      this->ran_out_of_room ? "RAN OUT OF ROOM" : "did not ran out of room");
     429             : 
     430           0 :   }
     431             : 
     432             :   template <typename Type>
     433           0 :   inline Type *copy (void)
     434             :   {
     435           0 :     assert (!this->ran_out_of_room);
     436           0 :     unsigned int len = this->head - this->start;
     437           0 :     void *p = malloc (len);
     438           0 :     if (p)
     439           0 :       memcpy (p, this->start, len);
     440           0 :     return reinterpret_cast<Type *> (p);
     441             :   }
     442             : 
     443             :   template <typename Type>
     444           0 :   inline Type *allocate_size (unsigned int size)
     445             :   {
     446           0 :     if (unlikely (this->ran_out_of_room || this->end - this->head < ptrdiff_t (size))) {
     447           0 :       this->ran_out_of_room = true;
     448           0 :       return NULL;
     449             :     }
     450           0 :     memset (this->head, 0, size);
     451           0 :     char *ret = this->head;
     452           0 :     this->head += size;
     453           0 :     return reinterpret_cast<Type *> (ret);
     454             :   }
     455             : 
     456             :   template <typename Type>
     457             :   inline Type *allocate_min (void)
     458             :   {
     459             :     return this->allocate_size<Type> (Type::min_size);
     460             :   }
     461             : 
     462             :   template <typename Type>
     463           0 :   inline Type *start_embed (void)
     464             :   {
     465           0 :     Type *ret = reinterpret_cast<Type *> (this->head);
     466           0 :     return ret;
     467             :   }
     468             : 
     469             :   template <typename Type>
     470             :   inline Type *embed (const Type &obj)
     471             :   {
     472             :     unsigned int size = obj.get_size ();
     473             :     Type *ret = this->allocate_size<Type> (size);
     474             :     if (unlikely (!ret)) return NULL;
     475             :     memcpy (ret, obj, size);
     476             :     return ret;
     477             :   }
     478             : 
     479             :   template <typename Type>
     480           0 :   inline Type *extend_min (Type &obj)
     481             :   {
     482           0 :     unsigned int size = obj.min_size;
     483           0 :     assert (this->start <= (char *) &obj && (char *) &obj <= this->head && (char *) &obj + size >= this->head);
     484           0 :     if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->head))) return NULL;
     485           0 :     return reinterpret_cast<Type *> (&obj);
     486             :   }
     487             : 
     488             :   template <typename Type>
     489           0 :   inline Type *extend (Type &obj)
     490             :   {
     491           0 :     unsigned int size = obj.get_size ();
     492           0 :     assert (this->start < (char *) &obj && (char *) &obj <= this->head && (char *) &obj + size >= this->head);
     493           0 :     if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->head))) return NULL;
     494           0 :     return reinterpret_cast<Type *> (&obj);
     495             :   }
     496             : 
     497             :   inline void truncate (void *new_head)
     498             :   {
     499             :     assert (this->start < new_head && new_head <= this->head);
     500             :     this->head = (char *) new_head;
     501             :   }
     502             : 
     503             :   unsigned int debug_depth;
     504             :   char *start, *end, *head;
     505             :   bool ran_out_of_room;
     506             : };
     507             : 
     508             : template <typename Type>
     509             : struct Supplier
     510             : {
     511           0 :   inline Supplier (const Type *array, unsigned int len_)
     512             :   {
     513           0 :     head = array;
     514           0 :     len = len_;
     515           0 :   }
     516           0 :   inline const Type operator [] (unsigned int i) const
     517             :   {
     518           0 :     if (unlikely (i >= len)) return Type ();
     519           0 :     return head[i];
     520             :   }
     521             : 
     522           0 :   inline void advance (unsigned int count)
     523             :   {
     524           0 :     if (unlikely (count > len))
     525           0 :       count = len;
     526           0 :     len -= count;
     527           0 :     head += count;
     528           0 :   }
     529             : 
     530             :   private:
     531             :   inline Supplier (const Supplier<Type> &); /* Disallow copy */
     532             :   inline Supplier<Type>& operator= (const Supplier<Type> &); /* Disallow copy */
     533             : 
     534             :   unsigned int len;
     535             :   const Type *head;
     536             : };
     537             : 
     538             : 
     539             : 
     540             : 
     541             : /*
     542             :  *
     543             :  * The OpenType Font File: Data Types
     544             :  */
     545             : 
     546             : 
     547             : /* "The following data types are used in the OpenType font file.
     548             :  *  All OpenType fonts use Motorola-style byte ordering (Big Endian):" */
     549             : 
     550             : /*
     551             :  * Int types
     552             :  */
     553             : 
     554             : 
     555             : template <typename Type, int Bytes> struct BEInt;
     556             : 
     557             : template <typename Type>
     558             : struct BEInt<Type, 1>
     559             : {
     560             :   public:
     561             :   inline void set (Type V)
     562             :   {
     563             :     v = V;
     564             :   }
     565           0 :   inline operator Type (void) const
     566             :   {
     567           0 :     return v;
     568             :   }
     569             :   private: uint8_t v;
     570             : };
     571             : template <typename Type>
     572             : struct BEInt<Type, 2>
     573             : {
     574             :   public:
     575           0 :   inline void set (Type V)
     576             :   {
     577           0 :     v[0] = (V >>  8) & 0xFF;
     578           0 :     v[1] = (V      ) & 0xFF;
     579           0 :   }
     580      748166 :   inline operator Type (void) const
     581             :   {
     582      748166 :     return (v[0] <<  8)
     583      748166 :          + (v[1]      );
     584             :   }
     585             :   private: uint8_t v[2];
     586             : };
     587             : template <typename Type>
     588             : struct BEInt<Type, 3>
     589             : {
     590             :   public:
     591             :   inline void set (Type V)
     592             :   {
     593             :     v[0] = (V >> 16) & 0xFF;
     594             :     v[1] = (V >>  8) & 0xFF;
     595             :     v[2] = (V      ) & 0xFF;
     596             :   }
     597             :   inline operator Type (void) const
     598             :   {
     599             :     return (v[0] << 16)
     600             :          + (v[1] <<  8)
     601             :          + (v[2]      );
     602             :   }
     603             :   private: uint8_t v[3];
     604             : };
     605             : template <typename Type>
     606             : struct BEInt<Type, 4>
     607             : {
     608             :   public:
     609           0 :   inline void set (Type V)
     610             :   {
     611           0 :     v[0] = (V >> 24) & 0xFF;
     612           0 :     v[1] = (V >> 16) & 0xFF;
     613           0 :     v[2] = (V >>  8) & 0xFF;
     614           0 :     v[3] = (V      ) & 0xFF;
     615           0 :   }
     616        1079 :   inline operator Type (void) const
     617             :   {
     618        1079 :     return (v[0] << 24)
     619        1079 :          + (v[1] << 16)
     620        1079 :          + (v[2] <<  8)
     621        1079 :          + (v[3]      );
     622             :   }
     623             :   private: uint8_t v[4];
     624             : };
     625             : 
     626             : /* Integer types in big-endian order and no alignment requirement */
     627             : template <typename Type, unsigned int Size>
     628             : struct IntType
     629             : {
     630           0 :   inline void set (Type i) { v.set (i); }
     631      749213 :   inline operator Type(void) const { return v; }
     632           0 :   inline bool operator == (const IntType<Type,Size> &o) const { return (Type) v == (Type) o.v; }
     633             :   inline bool operator != (const IntType<Type,Size> &o) const { return !(*this == o); }
     634             :   static inline int cmp (const IntType<Type,Size> *a, const IntType<Type,Size> *b) { return b->cmp (*a); }
     635          32 :   inline int cmp (Type a) const
     636             :   {
     637          32 :     Type b = v;
     638             :     if (sizeof (Type) < sizeof (int))
     639           0 :       return (int) a - (int) b;
     640             :     else
     641          32 :       return a < b ? -1 : a == b ? 0 : +1;
     642             :   }
     643        4540 :   inline bool sanitize (hb_sanitize_context_t *c) const
     644             :   {
     645        4540 :     TRACE_SANITIZE (this);
     646        4540 :     return_trace (likely (c->check_struct (this)));
     647             :   }
     648             :   protected:
     649             :   BEInt<Type, Size> v;
     650             :   public:
     651             :   DEFINE_SIZE_STATIC (Size);
     652             : };
     653             : 
     654             : typedef IntType<int8_t       , 1> CHAR;   /* 8-bit signed integer. */
     655             : typedef IntType<uint8_t      , 1> BYTE;   /* 8-bit unsigned integer. */
     656             : typedef IntType<int8_t       , 1> INT8;   /* 8-bit signed integer. */
     657             : typedef IntType<uint16_t, 2> USHORT;      /* 16-bit unsigned integer. */
     658             : typedef IntType<int16_t,  2> SHORT;       /* 16-bit signed integer. */
     659             : typedef IntType<uint32_t, 4> ULONG;       /* 32-bit unsigned integer. */
     660             : typedef IntType<int32_t,  4> LONG;        /* 32-bit signed integer. */
     661             : typedef IntType<uint32_t, 3> UINT24;      /* 24-bit unsigned integer. */
     662             : 
     663             : /* 16-bit signed integer (SHORT) that describes a quantity in FUnits. */
     664             : typedef SHORT FWORD;
     665             : 
     666             : /* 16-bit unsigned integer (USHORT) that describes a quantity in FUnits. */
     667             : typedef USHORT UFWORD;
     668             : 
     669             : /* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */
     670             : struct F2DOT14 : SHORT
     671             : {
     672             :   //inline float to_float (void) const { return ???; }
     673             :   //inline void set_float (float f) { v.set (f * ???); }
     674             :   public:
     675             :   DEFINE_SIZE_STATIC (2);
     676             : };
     677             : 
     678             : /* 32-bit signed fixed-point number (16.16). */
     679             : struct Fixed: LONG
     680             : {
     681             :   //inline float to_float (void) const { return ???; }
     682             :   //inline void set_float (float f) { v.set (f * ???); }
     683             :   public:
     684             :   DEFINE_SIZE_STATIC (4);
     685             : };
     686             : 
     687             : /* Date represented in number of seconds since 12:00 midnight, January 1,
     688             :  * 1904. The value is represented as a signed 64-bit integer. */
     689             : struct LONGDATETIME
     690             : {
     691             :   inline bool sanitize (hb_sanitize_context_t *c) const
     692             :   {
     693             :     TRACE_SANITIZE (this);
     694             :     return_trace (likely (c->check_struct (this)));
     695             :   }
     696             :   protected:
     697             :   LONG major;
     698             :   ULONG minor;
     699             :   public:
     700             :   DEFINE_SIZE_STATIC (8);
     701             : };
     702             : 
     703             : /* Array of four uint8s (length = 32 bits) used to identify a script, language
     704             :  * system, feature, or baseline */
     705             : struct Tag : ULONG
     706             : {
     707             :   /* What the char* converters return is NOT nul-terminated.  Print using "%.4s" */
     708             :   inline operator const char* (void) const { return reinterpret_cast<const char *> (&this->v); }
     709             :   inline operator char* (void) { return reinterpret_cast<char *> (&this->v); }
     710             :   public:
     711             :   DEFINE_SIZE_STATIC (4);
     712             : };
     713           0 : DEFINE_NULL_DATA (Tag, "    ");
     714             : 
     715             : /* Glyph index number, same as uint16 (length = 16 bits) */
     716             : struct GlyphID : USHORT {
     717           0 :   static inline int cmp (const GlyphID *a, const GlyphID *b) { return b->USHORT::cmp (*a); }
     718        3498 :   inline int cmp (hb_codepoint_t a) const { return (int) a - (int) *this; }
     719             : };
     720             : 
     721             : /* Script/language-system/feature index */
     722             : struct Index : USHORT {
     723             :   static const unsigned int NOT_FOUND_INDEX = 0xFFFFu;
     724             : };
     725           0 : DEFINE_NULL_DATA (Index, "\xff\xff");
     726             : 
     727             : /* Offset, Null offset = 0 */
     728             : template <typename Type=USHORT>
     729             : struct Offset : Type
     730             : {
     731         264 :   inline bool is_null (void) const { return 0 == *this; }
     732             :   public:
     733             :   DEFINE_SIZE_STATIC (sizeof(Type));
     734             : };
     735             : 
     736             : 
     737             : /* CheckSum */
     738             : struct CheckSum : ULONG
     739             : {
     740             :   /* This is reference implementation from the spec. */
     741             :   static inline uint32_t CalcTableChecksum (const ULONG *Table, uint32_t Length)
     742             :   {
     743             :     uint32_t Sum = 0L;
     744             :     const ULONG *EndPtr = Table+((Length+3) & ~3) / ULONG::static_size;
     745             : 
     746             :     while (Table < EndPtr)
     747             :       Sum += *Table++;
     748             :     return Sum;
     749             :   }
     750             : 
     751             :   /* Note: data should be 4byte aligned and have 4byte padding at the end. */
     752             :   inline void set_for_data (const void *data, unsigned int length)
     753             :   { set (CalcTableChecksum ((const ULONG *) data, length)); }
     754             : 
     755             :   public:
     756             :   DEFINE_SIZE_STATIC (4);
     757             : };
     758             : 
     759             : 
     760             : /*
     761             :  * Version Numbers
     762             :  */
     763             : 
     764             : template <typename FixedType=USHORT>
     765             : struct FixedVersion
     766             : {
     767          84 :   inline uint32_t to_int (void) const { return (major << (sizeof(FixedType) * 8)) + minor; }
     768             : 
     769          10 :   inline bool sanitize (hb_sanitize_context_t *c) const
     770             :   {
     771          10 :     TRACE_SANITIZE (this);
     772          10 :     return_trace (c->check_struct (this));
     773             :   }
     774             : 
     775             :   FixedType major;
     776             :   FixedType minor;
     777             :   public:
     778             :   DEFINE_SIZE_STATIC (2 * sizeof(FixedType));
     779             : };
     780             : 
     781             : 
     782             : 
     783             : /*
     784             :  * Template subclasses of Offset that do the dereferencing.
     785             :  * Use: (base+offset)
     786             :  */
     787             : 
     788             : template <typename Type, typename OffsetType=USHORT>
     789             : struct OffsetTo : Offset<OffsetType>
     790             : {
     791       10185 :   inline const Type& operator () (const void *base) const
     792             :   {
     793       10185 :     unsigned int offset = *this;
     794       10185 :     if (unlikely (!offset)) return Null(Type);
     795        9929 :     return StructAtOffset<Type> (base, offset);
     796             :   }
     797             : 
     798           0 :   inline Type& serialize (hb_serialize_context_t *c, const void *base)
     799             :   {
     800           0 :     Type *t = c->start_embed<Type> ();
     801           0 :     this->set ((char *) t - (char *) base); /* TODO(serialize) Overflow? */
     802           0 :     return *t;
     803             :   }
     804             : 
     805        4954 :   inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
     806             :   {
     807        4954 :     TRACE_SANITIZE (this);
     808        4954 :     if (unlikely (!c->check_struct (this))) return_trace (false);
     809        4954 :     unsigned int offset = *this;
     810        4954 :     if (unlikely (!offset)) return_trace (true);
     811        4744 :     if (unlikely (!c->check_range (base, offset))) return_trace (false);
     812        4744 :     const Type &obj = StructAtOffset<Type> (base, offset);
     813        4744 :     return_trace (likely (obj.sanitize (c)) || neuter (c));
     814             :   }
     815             :   template <typename T>
     816         864 :   inline bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const
     817             :   {
     818         864 :     TRACE_SANITIZE (this);
     819         864 :     if (unlikely (!c->check_struct (this))) return_trace (false);
     820         864 :     unsigned int offset = *this;
     821         864 :     if (unlikely (!offset)) return_trace (true);
     822         600 :     if (unlikely (!c->check_range (base, offset))) return_trace (false);
     823         600 :     const Type &obj = StructAtOffset<Type> (base, offset);
     824         600 :     return_trace (likely (obj.sanitize (c, user_data)) || neuter (c));
     825             :   }
     826             : 
     827             :   /* Set the offset to Null */
     828           0 :   inline bool neuter (hb_sanitize_context_t *c) const {
     829           0 :     return c->try_set (this, 0);
     830             :   }
     831             :   DEFINE_SIZE_STATIC (sizeof(OffsetType));
     832             : };
     833             : template <typename Type> struct LOffsetTo : OffsetTo<Type, ULONG> {};
     834             : template <typename Base, typename OffsetType, typename Type>
     835       10185 : static inline const Type& operator + (const Base &base, const OffsetTo<Type, OffsetType> &offset) { return offset (base); }
     836             : template <typename Base, typename OffsetType, typename Type>
     837             : static inline Type& operator + (Base &base, OffsetTo<Type, OffsetType> &offset) { return offset (base); }
     838             : 
     839             : 
     840             : /*
     841             :  * Array Types
     842             :  */
     843             : 
     844             : /* An array with a number of elements. */
     845             : template <typename Type, typename LenType=USHORT>
     846             : struct ArrayOf
     847             : {
     848         685 :   const Type *sub_array (unsigned int start_offset, unsigned int *pcount /* IN/OUT */) const
     849             :   {
     850         685 :     unsigned int count = len;
     851         685 :     if (unlikely (start_offset > count))
     852           0 :       count = 0;
     853             :     else
     854         685 :       count -= start_offset;
     855         685 :     count = MIN (count, *pcount);
     856         685 :     *pcount = count;
     857         685 :     return array + start_offset;
     858             :   }
     859             : 
     860      340416 :   inline const Type& operator [] (unsigned int i) const
     861             :   {
     862      340416 :     if (unlikely (i >= len)) return Null(Type);
     863      340406 :     return array[i];
     864             :   }
     865           0 :   inline Type& operator [] (unsigned int i)
     866             :   {
     867           0 :     return array[i];
     868             :   }
     869          43 :   inline unsigned int get_size (void) const
     870          43 :   { return len.static_size + len * Type::static_size; }
     871             : 
     872           0 :   inline bool serialize (hb_serialize_context_t *c,
     873             :                          unsigned int items_len)
     874             :   {
     875           0 :     TRACE_SERIALIZE (this);
     876           0 :     if (unlikely (!c->extend_min (*this))) return_trace (false);
     877           0 :     len.set (items_len); /* TODO(serialize) Overflow? */
     878           0 :     if (unlikely (!c->extend (*this))) return_trace (false);
     879           0 :     return_trace (true);
     880             :   }
     881             : 
     882           0 :   inline bool serialize (hb_serialize_context_t *c,
     883             :                          Supplier<Type> &items,
     884             :                          unsigned int items_len)
     885             :   {
     886           0 :     TRACE_SERIALIZE (this);
     887           0 :     if (unlikely (!serialize (c, items_len))) return_trace (false);
     888           0 :     for (unsigned int i = 0; i < items_len; i++)
     889           0 :       array[i] = items[i];
     890           0 :     items.advance (items_len);
     891           0 :     return_trace (true);
     892             :   }
     893             : 
     894         830 :   inline bool sanitize (hb_sanitize_context_t *c) const
     895             :   {
     896         830 :     TRACE_SANITIZE (this);
     897         830 :     if (unlikely (!sanitize_shallow (c))) return_trace (false);
     898             : 
     899             :     /* Note: for structs that do not reference other structs,
     900             :      * we do not need to call their sanitize() as we already did
     901             :      * a bound check on the aggregate array size.  We just include
     902             :      * a small unreachable expression to make sure the structs
     903             :      * pointed to do have a simple sanitize(), ie. they do not
     904             :      * reference other structs via offsets.
     905             :      */
     906             :     (void) (false && array[0].sanitize (c));
     907             : 
     908         830 :     return_trace (true);
     909             :   }
     910         212 :   inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
     911             :   {
     912         212 :     TRACE_SANITIZE (this);
     913         212 :     if (unlikely (!sanitize_shallow (c))) return_trace (false);
     914         212 :     unsigned int count = len;
     915        3170 :     for (unsigned int i = 0; i < count; i++)
     916        2958 :       if (unlikely (!array[i].sanitize (c, base)))
     917           0 :         return_trace (false);
     918         212 :     return_trace (true);
     919             :   }
     920             :   template <typename T>
     921           2 :   inline bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const
     922             :   {
     923           2 :     TRACE_SANITIZE (this);
     924           2 :     if (unlikely (!sanitize_shallow (c))) return_trace (false);
     925           2 :     unsigned int count = len;
     926         212 :     for (unsigned int i = 0; i < count; i++)
     927         210 :       if (unlikely (!array[i].sanitize (c, base, user_data)))
     928           0 :         return_trace (false);
     929           2 :     return_trace (true);
     930             :   }
     931             : 
     932             :   template <typename SearchType>
     933             :   inline int lsearch (const SearchType &x) const
     934             :   {
     935             :     unsigned int count = len;
     936             :     for (unsigned int i = 0; i < count; i++)
     937             :       if (!this->array[i].cmp (x))
     938             :         return i;
     939             :     return -1;
     940             :   }
     941             : 
     942             :   private:
     943        1044 :   inline bool sanitize_shallow (hb_sanitize_context_t *c) const
     944             :   {
     945        1044 :     TRACE_SANITIZE (this);
     946        1044 :     return_trace (c->check_struct (this) && c->check_array (array, Type::static_size, len));
     947             :   }
     948             : 
     949             :   public:
     950             :   LenType len;
     951             :   Type array[VAR];
     952             :   public:
     953             :   DEFINE_SIZE_ARRAY (sizeof (LenType), array);
     954             : };
     955             : template <typename Type> struct LArrayOf : ArrayOf<Type, ULONG> {};
     956             : 
     957             : /* Array of Offset's */
     958             : template <typename Type, typename OffsetType=USHORT>
     959             : struct OffsetArrayOf : ArrayOf<OffsetTo<Type, OffsetType> > {};
     960             : 
     961             : /* Array of offsets relative to the beginning of the array itself. */
     962             : template <typename Type>
     963             : struct OffsetListOf : OffsetArrayOf<Type>
     964             : {
     965         692 :   inline const Type& operator [] (unsigned int i) const
     966             :   {
     967         692 :     if (unlikely (i >= this->len)) return Null(Type);
     968         692 :     return this+this->array[i];
     969             :   }
     970             : 
     971          16 :   inline bool sanitize (hb_sanitize_context_t *c) const
     972             :   {
     973          16 :     TRACE_SANITIZE (this);
     974          16 :     return_trace (OffsetArrayOf<Type>::sanitize (c, this));
     975             :   }
     976             :   template <typename T>
     977           0 :   inline bool sanitize (hb_sanitize_context_t *c, T user_data) const
     978             :   {
     979           0 :     TRACE_SANITIZE (this);
     980           0 :     return_trace (OffsetArrayOf<Type>::sanitize (c, this, user_data));
     981             :   }
     982             : };
     983             : 
     984             : 
     985             : /* An array starting at second element. */
     986             : template <typename Type, typename LenType=USHORT>
     987             : struct HeadlessArrayOf
     988             : {
     989        5899 :   inline const Type& operator [] (unsigned int i) const
     990             :   {
     991        5899 :     if (unlikely (i >= len || !i)) return Null(Type);
     992        5899 :     return array[i-1];
     993             :   }
     994          13 :   inline unsigned int get_size (void) const
     995          13 :   { return len.static_size + (len ? len - 1 : 0) * Type::static_size; }
     996             : 
     997           0 :   inline bool serialize (hb_serialize_context_t *c,
     998             :                          Supplier<Type> &items,
     999             :                          unsigned int items_len)
    1000             :   {
    1001           0 :     TRACE_SERIALIZE (this);
    1002           0 :     if (unlikely (!c->extend_min (*this))) return_trace (false);
    1003           0 :     len.set (items_len); /* TODO(serialize) Overflow? */
    1004           0 :     if (unlikely (!items_len)) return_trace (true);
    1005           0 :     if (unlikely (!c->extend (*this))) return_trace (false);
    1006           0 :     for (unsigned int i = 0; i < items_len - 1; i++)
    1007           0 :       array[i] = items[i];
    1008           0 :     items.advance (items_len - 1);
    1009           0 :     return_trace (true);
    1010             :   }
    1011             : 
    1012        1992 :   inline bool sanitize_shallow (hb_sanitize_context_t *c) const
    1013             :   {
    1014             :     return c->check_struct (this)
    1015        1992 :         && c->check_array (this, Type::static_size, len);
    1016             :   }
    1017             : 
    1018        1992 :   inline bool sanitize (hb_sanitize_context_t *c) const
    1019             :   {
    1020        1992 :     TRACE_SANITIZE (this);
    1021        1992 :     if (unlikely (!sanitize_shallow (c))) return_trace (false);
    1022             : 
    1023             :     /* Note: for structs that do not reference other structs,
    1024             :      * we do not need to call their sanitize() as we already did
    1025             :      * a bound check on the aggregate array size.  We just include
    1026             :      * a small unreachable expression to make sure the structs
    1027             :      * pointed to do have a simple sanitize(), ie. they do not
    1028             :      * reference other structs via offsets.
    1029             :      */
    1030             :     (void) (false && array[0].sanitize (c));
    1031             : 
    1032        1992 :     return_trace (true);
    1033             :   }
    1034             : 
    1035             :   LenType len;
    1036             :   Type array[VAR];
    1037             :   public:
    1038             :   DEFINE_SIZE_ARRAY (sizeof (LenType), array);
    1039             : };
    1040             : 
    1041             : 
    1042             : /* An array with sorted elements.  Supports binary searching. */
    1043             : template <typename Type, typename LenType=USHORT>
    1044             : struct SortedArrayOf : ArrayOf<Type, LenType>
    1045             : {
    1046             :   template <typename SearchType>
    1047        1078 :   inline int bsearch (const SearchType &x) const
    1048             :   {
    1049             :     /* Hand-coded bsearch here since this is in the hot inner loop. */
    1050        1078 :     int min = 0, max = (int) this->len - 1;
    1051       14060 :     while (min <= max)
    1052             :     {
    1053        6787 :       int mid = (min + max) / 2;
    1054        6787 :       int c = this->array[mid].cmp (x);
    1055        6787 :       if (c < 0)
    1056        4093 :         max = mid - 1;
    1057        2694 :       else if (c > 0)
    1058        2398 :         min = mid + 1;
    1059             :       else
    1060         296 :         return mid;
    1061             :     }
    1062         782 :     return -1;
    1063             :   }
    1064             : };
    1065             : 
    1066             : 
    1067             : /* Lazy struct and blob loaders. */
    1068             : 
    1069             : /* Logic is shared between hb_lazy_loader_t and hb_lazy_table_loader_t */
    1070             : template <typename T>
    1071             : struct hb_lazy_loader_t
    1072             : {
    1073             :   inline void init (hb_face_t *face_)
    1074             :   {
    1075             :     face = face_;
    1076             :     instance = NULL;
    1077             :   }
    1078             : 
    1079             :   inline void fini (void)
    1080             :   {
    1081             :     if (instance && instance != &OT::Null(T))
    1082             :     {
    1083             :       instance->fini();
    1084             :       free (instance);
    1085             :     }
    1086             :   }
    1087             : 
    1088             :   inline const T* get (void) const
    1089             :   {
    1090             :   retry:
    1091             :     T *p = (T *) hb_atomic_ptr_get (&instance);
    1092             :     if (unlikely (!p))
    1093             :     {
    1094             :       p = (T *) calloc (1, sizeof (T));
    1095             :       if (unlikely (!p))
    1096             :         p = const_cast<T *> (&OT::Null(T));
    1097             :       else
    1098             :         p->init (face);
    1099             :       if (unlikely (!hb_atomic_ptr_cmpexch (const_cast<T **>(&instance), NULL, p)))
    1100             :       {
    1101             :         if (p != &OT::Null(T))
    1102             :           p->fini ();
    1103             :         goto retry;
    1104             :       }
    1105             :     }
    1106             :     return p;
    1107             :   }
    1108             : 
    1109             :   inline const T* operator-> (void) const
    1110             :   {
    1111             :     return get ();
    1112             :   }
    1113             : 
    1114             :   private:
    1115             :   hb_face_t *face;
    1116             :   T *instance;
    1117             : };
    1118             : 
    1119             : /* Logic is shared between hb_lazy_loader_t and hb_lazy_table_loader_t */
    1120             : template <typename T>
    1121             : struct hb_lazy_table_loader_t
    1122             : {
    1123          12 :   inline void init (hb_face_t *face_)
    1124             :   {
    1125          12 :     face = face_;
    1126          12 :     instance = NULL;
    1127          12 :     blob = NULL;
    1128          12 :   }
    1129             : 
    1130           6 :   inline void fini (void)
    1131             :   {
    1132           6 :     hb_blob_destroy (blob);
    1133           6 :   }
    1134             : 
    1135           0 :   inline const T* get (void) const
    1136             :   {
    1137             :   retry:
    1138           0 :     T *p = (T *) hb_atomic_ptr_get (&instance);
    1139           0 :     if (unlikely (!p))
    1140             :     {
    1141           0 :       hb_blob_t *blob_ = OT::Sanitizer<T>::sanitize (face->reference_table (T::tableTag));
    1142           0 :       p = const_cast<T *>(OT::Sanitizer<T>::lock_instance (blob_));
    1143           0 :       if (!hb_atomic_ptr_cmpexch (const_cast<T **>(&instance), NULL, p))
    1144             :       {
    1145           0 :         hb_blob_destroy (blob_);
    1146           0 :         goto retry;
    1147             :       }
    1148           0 :       blob = blob_;
    1149             :     }
    1150           0 :     return p;
    1151             :   }
    1152             : 
    1153             :   inline const T* operator-> (void) const
    1154             :   {
    1155             :     return get();
    1156             :   }
    1157             : 
    1158             :   private:
    1159             :   hb_face_t *face;
    1160             :   T *instance;
    1161             :   mutable hb_blob_t *blob;
    1162             : };
    1163             : 
    1164             : 
    1165             : } /* namespace OT */
    1166             : 
    1167             : 
    1168             : #endif /* HB_OPEN_TYPE_PRIVATE_HH */

Generated by: LCOV version 1.13