[aat] Implement Lookup table
authorBehdad Esfahbod <behdad@behdad.org>
Tue, 9 Jan 2018 14:48:51 +0000 (15:48 +0100)
committerBehdad Esfahbod <behdad@behdad.org>
Wed, 10 Jan 2018 01:50:49 +0000 (02:50 +0100)
Untested, but compiles.

13 files changed:
src/hb-aat-layout-common-private.hh
src/hb-aat-layout-morx-table.hh
src/hb-aat-layout.cc
src/hb-face.cc
src/hb-open-type-private.hh
src/hb-ot-cbdt-table.hh
src/hb-ot-cmap-table.hh
src/hb-ot-glyf-table.hh
src/hb-ot-hmtx-table.hh
src/hb-ot-kern-table.hh
src/hb-ot-layout.cc
src/hb-ot-post-table.hh
src/hb-uniscribe.cc

index e1abd07..88a9cd8 100644 (file)
@@ -41,7 +41,6 @@ using namespace OT;
 
 struct BinSearchHeader
 {
-  friend struct BinSearchArray;
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -49,7 +48,6 @@ struct BinSearchHeader
     return_trace (c->check_struct (this));
   }
 
-  protected:
   UINT16       unitSize;       /* Size of a lookup unit for this search in bytes. */
   UINT16       nUnits;         /* Number of units of the preceding size to be searched. */
   UINT16       searchRange;    /* The value of unitSize times the largest power of 2
@@ -106,9 +104,23 @@ struct BinSearchArrayOf
   }
 
   template <typename T>
-  inline Type *bsearch (const T &key) const
+  inline const Type *bsearch (const T &key) const
   {
-    return ::bsearch (&key, bytes, header.nUnits, header.unitSize, Type::cmp);
+    unsigned int size = header.unitSize;
+    int min = 0, max = (int) header.nUnits - 1;
+    while (min <= max)
+    {
+      int mid = (min + max) / 2;
+      const Type *p = (const Type *) (((const char *) bytes) + (mid * size));
+      int c = p->cmp (key);
+      if (c < 0)
+       max = mid - 1;
+      else if (c > 0)
+       min = mid + 1;
+      else
+       return p;
+    }
+    return NULL;
   }
 
   private:
@@ -128,6 +140,294 @@ struct BinSearchArrayOf
 };
 
 
+/* TODO Move this to hb-open-type-private.hh and 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);
+
+    /* 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 && count && arrayZ->sanitize (c));
+
+    return_trace (c->check_array (arrayZ, arrayZ[0].static_size, count));
+  }
+
+  protected:
+  Type arrayZ[VAR];
+  public:
+  DEFINE_SIZE_ARRAY (0, arrayZ);
+};
+
+
+/*
+ * Lookup Table
+ */
+
+template <typename T> struct Lookup;
+
+template <typename T>
+struct LookupFormat0
+{
+  friend struct Lookup<T>;
+
+  private:
+  inline const T& get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
+  {
+    if (unlikely (glyph_id >= num_glyphs)) return Null(T);
+    return arrayZ[glyph_id];
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (arrayZ.sanitize (c, c->num_glyphs));
+  }
+
+  protected:
+  UINT16       format;         /* Format identifier--format = 0 */
+  UnsizedArrayOf<T>
+               arrayZ;         /* Array of lookup values, indexed by glyph index. */
+  public:
+  DEFINE_SIZE_ARRAY (2, arrayZ);
+};
+
+
+template <typename T>
+struct LookupSegmentSingle
+{
+  inline int cmp (hb_codepoint_t g) const {
+    return g < first ? -1 : g <= last ? 0 : +1 ;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && value.sanitize (c));
+  }
+
+  GlyphID      last;           /* Last GlyphID in this segment */
+  GlyphID      first;          /* First GlyphID in this segment */
+  T            value;          /* The lookup value (only one) */
+  public:
+  DEFINE_SIZE_STATIC (4 + sizeof (T));
+};
+
+template <typename T>
+struct LookupFormat2
+{
+  friend struct Lookup<T>;
+
+  private:
+  inline const T& get_value (hb_codepoint_t glyph_id) const
+  {
+    const LookupSegmentSingle<T> *v = segments.bsearch (glyph_id);
+    return v ? v->value : Null(T);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (segments.sanitize (c));
+  }
+
+  protected:
+  UINT16       format;         /* Format identifier--format = 2 */
+  BinSearchArrayOf<LookupSegmentSingle<T> >
+               segments;       /* The actual segments. These must already be sorted,
+                                * according to the first word in each one (the last
+                                * glyph in each segment). */
+  public:
+  DEFINE_SIZE_ARRAY (8, segments);
+};
+
+template <typename T>
+struct LookupSegmentArray
+{
+  inline const T& get_value (hb_codepoint_t glyph_id, const void *base) const
+  {
+    return first <= glyph_id && glyph_id <= last ? (base+valuesZ)[glyph_id - first] : Null(T);
+  }
+
+  inline int cmp (hb_codepoint_t g) const {
+    return g < first ? -1 : g <= last ? 0 : +1 ;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+                 first <= last &&
+                 valuesZ.sanitize (c, base, last - first + 1));
+  }
+
+  GlyphID      last;           /* Last GlyphID in this segment */
+  GlyphID      first;          /* First GlyphID in this segment */
+  OffsetTo<UnsizedArrayOf<T> >
+               valuesZ;        /* A 16-bit offset from the start of
+                                * the table to the data. */
+  public:
+  DEFINE_SIZE_STATIC (6);
+};
+
+template <typename T>
+struct LookupFormat4
+{
+  friend struct Lookup<T>;
+
+  private:
+  inline const T& get_value (hb_codepoint_t glyph_id) const
+  {
+    const LookupSegmentArray<T> *v = segments.bsearch (glyph_id);
+    return v ? v->get_value (glyph_id, this) : Null(T);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (segments.sanitize (c, this));
+  }
+
+  protected:
+  UINT16       format;         /* Format identifier--format = 2 */
+  BinSearchArrayOf<LookupSegmentArray<T> >
+               segments;       /* The actual segments. These must already be sorted,
+                                * according to the first word in each one (the last
+                                * glyph in each segment). */
+  public:
+  DEFINE_SIZE_ARRAY (8, segments);
+};
+
+template <typename T>
+struct LookupSingle
+{
+  inline int cmp (hb_codepoint_t g) const { return glyph.cmp (g); }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && value.sanitize (c));
+  }
+
+  GlyphID      glyph;          /* Last GlyphID */
+  T            value;          /* The lookup value (only one) */
+  public:
+  DEFINE_SIZE_STATIC (4 + sizeof (T));
+};
+
+template <typename T>
+struct LookupFormat6
+{
+  friend struct Lookup<T>;
+
+  private:
+  inline const T& get_value (hb_codepoint_t glyph_id) const
+  {
+    const LookupSingle<T> *v = entries.bsearch (glyph_id);
+    return v ? v->value : Null(T);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (entries.sanitize (c));
+  }
+
+  protected:
+  UINT16       format;         /* Format identifier--format = 6 */
+  BinSearchArrayOf<LookupSingle<T> >
+               entries;        /* The actual entries, sorted by glyph index. */
+  public:
+  DEFINE_SIZE_ARRAY (8, entries);
+};
+
+template <typename T>
+struct LookupFormat8
+{
+  friend struct Lookup<T>;
+
+  private:
+  inline const T& get_value (hb_codepoint_t glyph_id) const
+  {
+    return firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount ? valueArrayZ[glyph_id - firstGlyph] : Null(T);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && valueArrayZ.sanitize (c, glyphCount));
+  }
+
+  protected:
+  UINT16       format;         /* Format identifier--format = 6 */
+  GlyphID      firstGlyph;     /* First glyph index included in the trimmed array. */
+  UINT16       glyphCount;     /* Total number of glyphs (equivalent to the last
+                                * glyph minus the value of firstGlyph plus 1). */
+  UnsizedArrayOf<T>
+               valueArrayZ;    /* The lookup values (indexed by the glyph index
+                                * minus the value of firstGlyph). */
+  public:
+  DEFINE_SIZE_ARRAY (6, valueArrayZ);
+};
+
+template <typename T>
+struct Lookup
+{
+  inline const T& get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
+  {
+    switch (u.format) {
+    case 0: return u.format0.get_value (glyph_id, num_glyphs);
+    case 2: return u.format2.get_value (glyph_id);
+    case 4: return u.format4.get_value (glyph_id);
+    case 6: return u.format6.get_value (glyph_id);
+    case 8: return u.format8.get_value (glyph_id);
+    default:return Null(T);
+    }
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (!u.format.sanitize (c)) return_trace (false);
+    switch (u.format) {
+    case 0: return_trace (u.format0.sanitize (c));
+    case 2: return_trace (u.format2.sanitize (c));
+    case 4: return_trace (u.format4.sanitize (c));
+    case 6: return_trace (u.format6.sanitize (c));
+    case 8: return_trace (u.format8.sanitize (c));
+    default:return_trace (true);
+    }
+  }
+
+  protected:
+  union {
+  UINT16               format;         /* Format identifier */
+  LookupFormat0<T>     format0;
+  LookupFormat2<T>     format2;
+  LookupFormat4<T>     format4;
+  LookupFormat6<T>     format6;
+  LookupFormat8<T>     format8;
+  } u;
+  public:
+  DEFINE_SIZE_UNION (2, format);
+};
+
+// Instantiate, to catch compile errors.
+Lookup<GlyphID> g;
+Lookup<Tag> t;
+
+
 } /* namespace AAT */
 
 
index a8a8de4..2cd7743 100644 (file)
@@ -74,13 +74,16 @@ struct LigatureSubtable
 
 struct NoncontextualSubtable
 {
-  /* TODO */
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    /* TODO */
-    return_trace (false);
+    return_trace (substitute.sanitize (c));
   }
+
+  protected:
+  Lookup<GlyphID>      substitute;
+  public:
+  DEFINE_SIZE_MIN (2);
 };
 
 struct InsertionSubtable
index 73ceafe..bd647d5 100644 (file)
@@ -41,3 +41,17 @@ _get_morx (hb_face_t *face)
   hb_ot_layout_t * layout = hb_ot_layout_from_face (face);
   return *(layout->morx.get ());
 }
+
+void
+_hb_aat_layout_create (hb_face_t *face)
+{
+  OT::Sanitizer<AAT::morx> sanitizer;
+  sanitizer.set_num_glyphs (face->get_num_glyphs ());
+  hb_blob_t *morx_blob = sanitizer.sanitize (face->reference_table (HB_AAT_TAG_MORX));
+  OT::Sanitizer<AAT::morx>::lock_instance (morx_blob);
+
+  if (0)
+  {
+    OT::Sanitizer<AAT::Lookup<OT::GlyphID> >::lock_instance (morx_blob)->get_value (1, face->get_num_glyphs ());
+  }
+}
index 26fddbe..d8af8c1 100644 (file)
@@ -164,7 +164,7 @@ hb_face_create (hb_blob_t    *blob,
   if (unlikely (!blob))
     blob = hb_blob_get_empty ();
 
-  hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (OT::Sanitizer<OT::OpenTypeFontFile>::sanitize (hb_blob_reference (blob)), index);
+  hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (OT::Sanitizer<OT::OpenTypeFontFile>().sanitize (hb_blob_reference (blob)), index);
 
   if (unlikely (!closure))
     return hb_face_get_empty ();
@@ -424,7 +424,7 @@ hb_face_get_upem (hb_face_t *face)
 void
 hb_face_t::load_upem (void) const
 {
-  hb_blob_t *head_blob = OT::Sanitizer<OT::head>::sanitize (reference_table (HB_OT_TAG_head));
+  hb_blob_t *head_blob = OT::Sanitizer<OT::head>().sanitize (reference_table (HB_OT_TAG_head));
   const OT::head *head_table = OT::Sanitizer<OT::head>::lock_instance (head_blob);
   upem = head_table->get_upem ();
   hb_blob_destroy (head_blob);
@@ -468,7 +468,7 @@ hb_face_get_glyph_count (hb_face_t *face)
 void
 hb_face_t::load_num_glyphs (void) const
 {
-  hb_blob_t *maxp_blob = OT::Sanitizer<OT::maxp>::sanitize (reference_table (HB_OT_TAG_maxp));
+  hb_blob_t *maxp_blob = OT::Sanitizer<OT::maxp>().sanitize (reference_table (HB_OT_TAG_maxp));
   const OT::maxp *maxp_table = OT::Sanitizer<OT::maxp>::lock_instance (maxp_blob);
   num_glyphs = maxp_table->get_num_glyphs ();
   hb_blob_destroy (maxp_blob);
index 2f4e1b9..b68568c 100644 (file)
@@ -187,7 +187,8 @@ struct hb_sanitize_context_t :
        debug_depth (0),
        start (nullptr), end (nullptr),
        writable (false), edit_count (0),
-       blob (nullptr) {}
+       blob (nullptr),
+       num_glyphs (0) {}
 
   inline const char *get_name (void) { return "SANITIZE"; }
   template <typename T, typename F>
@@ -298,6 +299,7 @@ struct hb_sanitize_context_t :
   bool writable;
   unsigned int edit_count;
   hb_blob_t *blob;
+  unsigned int num_glyphs;
 };
 
 
@@ -306,8 +308,9 @@ struct hb_sanitize_context_t :
 template <typename Type>
 struct Sanitizer
 {
-  static hb_blob_t *sanitize (hb_blob_t *blob) {
-    hb_sanitize_context_t c[1];
+  inline Sanitizer (void) {}
+
+  inline hb_blob_t *sanitize (hb_blob_t *blob) {
     bool sane;
 
     /* TODO is_sane() stuff */
@@ -370,6 +373,11 @@ struct Sanitizer
     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:
+  hb_sanitize_context_t c[1];
 };
 
 
@@ -1154,7 +1162,7 @@ struct hb_lazy_table_loader_t
     T *p = (T *) hb_atomic_ptr_get (&instance);
     if (unlikely (!p))
     {
-      hb_blob_t *blob_ = OT::Sanitizer<T>::sanitize (face->reference_table (T::tableTag));
+      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))
       {
index 415625e..dad34e2 100644 (file)
@@ -379,8 +379,8 @@ struct CBDT
     {
       upem = face->get_upem();
 
-      cblc_blob = Sanitizer<CBLC>::sanitize (face->reference_table (HB_OT_TAG_CBLC));
-      cbdt_blob = Sanitizer<CBDT>::sanitize (face->reference_table (HB_OT_TAG_CBDT));
+      cblc_blob = Sanitizer<CBLC>().sanitize (face->reference_table (HB_OT_TAG_CBLC));
+      cbdt_blob = Sanitizer<CBDT>().sanitize (face->reference_table (HB_OT_TAG_CBDT));
       cbdt_len = hb_blob_get_length (cbdt_blob);
 
       if (hb_blob_get_length (cblc_blob) == 0) {
index 883d7b3..c61801c 100644 (file)
@@ -508,7 +508,7 @@ struct cmap
   {
     inline void init (hb_face_t *face)
     {
-      this->blob = OT::Sanitizer<OT::cmap>::sanitize (face->reference_table (HB_OT_TAG_cmap));
+      this->blob = OT::Sanitizer<OT::cmap>().sanitize (face->reference_table (HB_OT_TAG_cmap));
       const OT::cmap *cmap = OT::Sanitizer<OT::cmap>::lock_instance (this->blob);
       const OT::CmapSubtable *subtable = nullptr;
       const OT::CmapSubtableFormat14 *subtable_uvs = nullptr;
index 88d3850..c5a54e3 100644 (file)
@@ -96,7 +96,7 @@ struct glyf
   {
     inline void init (hb_face_t *face)
     {
-      hb_blob_t *head_blob = Sanitizer<head>::sanitize (face->reference_table (HB_OT_TAG_head));
+      hb_blob_t *head_blob = Sanitizer<head>().sanitize (face->reference_table (HB_OT_TAG_head));
       const head *head_table = Sanitizer<head>::lock_instance (head_blob);
       if ((unsigned int) head_table->indexToLocFormat > 1 || head_table->glyphDataFormat != 0)
       {
@@ -107,9 +107,9 @@ struct glyf
       short_offset = 0 == head_table->indexToLocFormat;
       hb_blob_destroy (head_blob);
 
-      loca_blob = Sanitizer<loca>::sanitize (face->reference_table (HB_OT_TAG_loca));
+      loca_blob = Sanitizer<loca>().sanitize (face->reference_table (HB_OT_TAG_loca));
       loca_table = Sanitizer<loca>::lock_instance (loca_blob);
-      glyf_blob = Sanitizer<glyf>::sanitize (face->reference_table (HB_OT_TAG_glyf));
+      glyf_blob = Sanitizer<glyf>().sanitize (face->reference_table (HB_OT_TAG_glyf));
       glyf_table = Sanitizer<glyf>::lock_instance (glyf_blob);
 
       num_glyphs = MAX (1u, hb_blob_get_length (loca_blob) / (short_offset ? 2 : 4)) - 1;
index 29770f7..934acde 100644 (file)
@@ -74,7 +74,7 @@ struct hmtxvmtx
       bool got_font_extents = false;
       if (T::os2Tag)
       {
-       hb_blob_t *os2_blob = Sanitizer<os2>::sanitize (face->reference_table (T::os2Tag));
+       hb_blob_t *os2_blob = Sanitizer<os2>().sanitize (face->reference_table (T::os2Tag));
        const os2 *os2_table = Sanitizer<os2>::lock_instance (os2_blob);
 #define USE_TYPO_METRICS (1u<<7)
        if (0 != (os2_table->fsSelection & USE_TYPO_METRICS))
@@ -87,7 +87,7 @@ struct hmtxvmtx
        hb_blob_destroy (os2_blob);
       }
 
-      hb_blob_t *_hea_blob = Sanitizer<_hea>::sanitize (face->reference_table (T::headerTag));
+      hb_blob_t *_hea_blob = Sanitizer<_hea>().sanitize (face->reference_table (T::headerTag));
       const _hea *_hea_table = Sanitizer<_hea>::lock_instance (_hea_blob);
       num_advances = _hea_table->numberOfLongMetrics;
       if (!got_font_extents)
@@ -101,7 +101,7 @@ struct hmtxvmtx
 
       has_font_extents = got_font_extents;
 
-      blob = Sanitizer<hmtxvmtx>::sanitize (face->reference_table (T::tableTag));
+      blob = Sanitizer<hmtxvmtx>().sanitize (face->reference_table (T::tableTag));
 
       /* Cap num_metrics() and num_advances() based on table length. */
       unsigned int len = hb_blob_get_length (blob);
@@ -119,7 +119,7 @@ struct hmtxvmtx
       }
       table = Sanitizer<hmtxvmtx>::lock_instance (blob);
 
-      var_blob = Sanitizer<HVARVVAR>::sanitize (face->reference_table (T::variationsTag));
+      var_blob = Sanitizer<HVARVVAR>().sanitize (face->reference_table (T::variationsTag));
       var_table = Sanitizer<HVARVVAR>::lock_instance (var_blob);
     }
 
index e07faca..c9aaf03 100644 (file)
@@ -360,7 +360,7 @@ struct kern
   {
     inline void init (hb_face_t *face)
     {
-      blob = Sanitizer<kern>::sanitize (face->reference_table (HB_OT_TAG_kern));
+      blob = Sanitizer<kern>().sanitize (face->reference_table (HB_OT_TAG_kern));
       table = Sanitizer<kern>::lock_instance (blob);
       table_length = hb_blob_get_length (blob);
     }
index d473739..14b6435 100644 (file)
@@ -50,13 +50,13 @@ _hb_ot_layout_create (hb_face_t *face)
   if (unlikely (!layout))
     return nullptr;
 
-  layout->gdef_blob = OT::Sanitizer<OT::GDEF>::sanitize (face->reference_table (HB_OT_TAG_GDEF));
+  layout->gdef_blob = OT::Sanitizer<OT::GDEF>().sanitize (face->reference_table (HB_OT_TAG_GDEF));
   layout->gdef = OT::Sanitizer<OT::GDEF>::lock_instance (layout->gdef_blob);
 
-  layout->gsub_blob = OT::Sanitizer<OT::GSUB>::sanitize (face->reference_table (HB_OT_TAG_GSUB));
+  layout->gsub_blob = OT::Sanitizer<OT::GSUB>().sanitize (face->reference_table (HB_OT_TAG_GSUB));
   layout->gsub = OT::Sanitizer<OT::GSUB>::lock_instance (layout->gsub_blob);
 
-  layout->gpos_blob = OT::Sanitizer<OT::GPOS>::sanitize (face->reference_table (HB_OT_TAG_GPOS));
+  layout->gpos_blob = OT::Sanitizer<OT::GPOS>().sanitize (face->reference_table (HB_OT_TAG_GPOS));
   layout->gpos = OT::Sanitizer<OT::GPOS>::lock_instance (layout->gpos_blob);
 
   layout->math.init (face);
index 7f1c2c4..523ba2a 100644 (file)
@@ -86,7 +86,7 @@ struct post
   {
     inline void init (hb_face_t *face)
     {
-      blob = Sanitizer<post>::sanitize (face->reference_table (HB_OT_TAG_post));
+      blob = Sanitizer<post>().sanitize (face->reference_table (HB_OT_TAG_post));
       const post *table = Sanitizer<post>::lock_instance (blob);
       unsigned int table_length = hb_blob_get_length (blob);
 
index 0b0bad5..5e05baa 100644 (file)
@@ -351,7 +351,7 @@ _hb_rename_font (hb_blob_t *blob, wchar_t *new_name)
    * full, PS. All of them point to the same name data with our unique name.
    */
 
-  blob = OT::Sanitizer<OT::OpenTypeFontFile>::sanitize (blob);
+  blob = OT::Sanitizer<OT::OpenTypeFontFile>().sanitize (blob);
 
   unsigned int length, new_length, name_str_len;
   const char *orig_sfnt_data = hb_blob_get_data (blob, &length);