Imported Upstream version 2.3.1
[platform/upstream/harfbuzz.git] / src / hb-ot-cmap-table.hh
index c1903f6..0526c35 100644 (file)
@@ -27,9 +27,8 @@
 #ifndef HB_OT_CMAP_TABLE_HH
 #define HB_OT_CMAP_TABLE_HH
 
-#include "hb-open-type-private.hh"
-#include "hb-set-private.hh"
-#include "hb-subset-plan.hh"
+#include "hb-open-type.hh"
+#include "hb-set.hh"
 
 /*
  * cmap -- Character to Glyph Index Mapping
  */
 #define HB_OT_TAG_cmap HB_TAG('c','m','a','p')
 
-
 namespace OT {
 
 
 struct CmapSubtableFormat0
 {
-  inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
+  bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
   {
     hb_codepoint_t gid = codepoint < 256 ? glyphIdArray[codepoint] : 0;
     if (!gid)
@@ -51,8 +49,14 @@ struct CmapSubtableFormat0
     *glyph = gid;
     return true;
   }
+  void collect_unicodes (hb_set_t *out) const
+  {
+    for (unsigned int i = 0; i < 256; i++)
+      if (glyphIdArray[i])
+       out->add (i);
+  }
 
-  inline bool sanitize (hb_sanitize_context_t *c) const
+  bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
@@ -78,8 +82,8 @@ struct CmapSubtableFormat4
   };
 
   bool serialize (hb_serialize_context_t *c,
-                  const hb_subset_plan_t *plan,
-                  const hb_vector_t<segment_plan> &segments)
+                 const hb_subset_plan_t *plan,
+                 const hb_vector_t<segment_plan> &segments)
   {
     TRACE_SERIALIZE (this);
 
@@ -88,92 +92,92 @@ struct CmapSubtableFormat4
     this->format.set (4);
     this->length.set (get_sub_table_size (segments));
 
-    this->segCountX2.set (segments.len * 2);
-    this->entrySelector.set (MAX (1u, _hb_bit_storage (segments.len)) - 1);
+    this->segCountX2.set (segments.length * 2);
+    this->entrySelector.set (MAX (1u, hb_bit_storage (segments.length)) - 1);
     this->searchRange.set (2 * (1u << this->entrySelector));
-    this->rangeShift.set (segments.len * 2 > this->searchRange
-                          ? 2 * segments.len - this->searchRange
-                          : 0);
+    this->rangeShift.set (segments.length * 2 > this->searchRange
+                         ? 2 * segments.length - this->searchRange
+                         : 0);
 
-    HBUINT16 *end_count = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.len);
+    HBUINT16 *end_count = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.length);
     c->allocate_size<HBUINT16> (HBUINT16::static_size); // 2 bytes of padding.
-    HBUINT16 *start_count = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.len);
-    HBINT16 *id_delta = c->allocate_size<HBINT16> (HBUINT16::static_size * segments.len);
-    HBUINT16 *id_range_offset = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.len);
+    HBUINT16 *start_count = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.length);
+    HBINT16 *id_delta = c->allocate_size<HBINT16> (HBUINT16::static_size * segments.length);
+    HBUINT16 *id_range_offset = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.length);
 
     if (id_range_offset == nullptr)
       return_trace (false);
 
-    for (unsigned int i = 0; i < segments.len; i++)
+    for (unsigned int i = 0; i < segments.length; i++)
     {
       end_count[i].set (segments[i].end_code);
       start_count[i].set (segments[i].start_code);
       if (segments[i].use_delta)
       {
-        hb_codepoint_t cp = segments[i].start_code;
-        hb_codepoint_t start_gid = 0;
-        if (unlikely (!plan->new_gid_for_codepoint (cp, &start_gid) && cp != 0xFFFF))
-          return_trace (false);
-        id_delta[i].set (start_gid - segments[i].start_code);
+       hb_codepoint_t cp = segments[i].start_code;
+       hb_codepoint_t start_gid = 0;
+       if (unlikely (!plan->new_gid_for_codepoint (cp, &start_gid) && cp != 0xFFFF))
+         return_trace (false);
+       id_delta[i].set (start_gid - segments[i].start_code);
       } else {
-        id_delta[i].set (0);
-        unsigned int num_codepoints = segments[i].end_code - segments[i].start_code + 1;
-        HBUINT16 *glyph_id_array = c->allocate_size<HBUINT16> (HBUINT16::static_size * num_codepoints);
-        if (glyph_id_array == nullptr)
-          return_trace (false);
-        // From the cmap spec:
-        //
-        // id_range_offset[i]/2
-        // + (cp - segments[i].start_code)
-        // + (id_range_offset + i)
-        // =
-        // glyph_id_array + (cp - segments[i].start_code)
-        //
-        // So, solve for id_range_offset[i]:
-        //
-        // id_range_offset[i]
-        // =
-        // 2 * (glyph_id_array - id_range_offset - i)
-        id_range_offset[i].set (2 * (
-            glyph_id_array - id_range_offset - i));
-        for (unsigned int j = 0; j < num_codepoints; j++)
-        {
-          hb_codepoint_t cp = segments[i].start_code + j;
-          hb_codepoint_t new_gid;
-          if (unlikely (!plan->new_gid_for_codepoint (cp, &new_gid)))
-            return_trace (false);
-          glyph_id_array[j].set (new_gid);
-        }
+       id_delta[i].set (0);
+       unsigned int num_codepoints = segments[i].end_code - segments[i].start_code + 1;
+       HBUINT16 *glyph_id_array = c->allocate_size<HBUINT16> (HBUINT16::static_size * num_codepoints);
+       if (glyph_id_array == nullptr)
+         return_trace (false);
+       // From the cmap spec:
+       //
+       // id_range_offset[i]/2
+       // + (cp - segments[i].start_code)
+       // + (id_range_offset + i)
+       // =
+       // glyph_id_array + (cp - segments[i].start_code)
+       //
+       // So, solve for id_range_offset[i]:
+       //
+       // id_range_offset[i]
+       // =
+       // 2 * (glyph_id_array - id_range_offset - i)
+       id_range_offset[i].set (2 * (
+           glyph_id_array - id_range_offset - i));
+       for (unsigned int j = 0; j < num_codepoints; j++)
+       {
+         hb_codepoint_t cp = segments[i].start_code + j;
+         hb_codepoint_t new_gid;
+         if (unlikely (!plan->new_gid_for_codepoint (cp, &new_gid)))
+           return_trace (false);
+         glyph_id_array[j].set (new_gid);
+       }
       }
     }
 
     return_trace (true);
   }
 
-  static inline size_t get_sub_table_size (const hb_vector_t<segment_plan> &segments)
+  static size_t get_sub_table_size (const hb_vector_t<segment_plan> &segments)
   {
     size_t segment_size = 0;
-    for (unsigned int i = 0; i < segments.len; i++)
+    for (unsigned int i = 0; i < segments.length; i++)
     {
       // Parallel array entries
       segment_size +=
-            2  // end count
-          + 2  // start count
-          + 2  // delta
-          + 2; // range offset
+           2  // end count
+         + 2  // start count
+         + 2  // delta
+         + 2; // range offset
 
       if (!segments[i].use_delta)
-        // Add bytes for the glyph index array entries for this segment.
-        segment_size += (segments[i].end_code - segments[i].start_code + 1) * 2;
+       // Add bytes for the glyph index array entries for this segment.
+       segment_size += (segments[i].end_code - segments[i].start_code + 1) * 2;
     }
 
     return min_size
-        + 2 // Padding
-        + segment_size;
+       + 2 // Padding
+       + segment_size;
   }
 
-  static inline bool create_sub_table_plan (const hb_subset_plan_t *plan,
-                                            hb_vector_t<segment_plan> *segments)
+  static bool create_sub_table_plan (const hb_subset_plan_t *plan,
+                                    hb_vector_t<segment_plan> *segments)
   {
     segment_plan *segment = nullptr;
     hb_codepoint_t last_gid = 0;
@@ -187,24 +191,22 @@ struct CmapSubtableFormat4
        return false;
       }
 
-      if (cp > 0xFFFF) {
-        // We are now outside of unicode BMP, stop adding to this cmap.
-        break;
-      }
+      /* Stop adding to cmap if we are now outside of unicode BMP. */
+      if (cp > 0xFFFF) break;
 
-      if (!segment
-          || cp != segment->end_code + 1u)
+      if (!segment ||
+         cp != segment->end_code + 1u)
       {
-        segment = segments->push ();
-        segment->start_code.set (cp);
-        segment->end_code.set (cp);
-        segment->use_delta = true;
+       segment = segments->push ();
+       segment->start_code.set (cp);
+       segment->end_code.set (cp);
+       segment->use_delta = true;
       } else {
-        segment->end_code.set (cp);
-        if (last_gid + 1u != new_gid)
-          // gid's are not consecutive in this segment so delta
-          // cannot be used.
-          segment->use_delta = false;
+       segment->end_code.set (cp);
+       if (last_gid + 1u != new_gid)
+         // gid's are not consecutive in this segment so delta
+         // cannot be used.
+         segment->use_delta = false;
       }
 
       last_gid = new_gid;
@@ -224,29 +226,32 @@ struct CmapSubtableFormat4
 
   struct accelerator_t
   {
-    inline void init (const CmapSubtableFormat4 *subtable)
+    accelerator_t () {}
+    accelerator_t (const CmapSubtableFormat4 *subtable) { init (subtable); }
+    ~accelerator_t () { fini (); }
+
+    void init (const CmapSubtableFormat4 *subtable)
     {
       segCount = subtable->segCountX2 / 2;
-      endCount = subtable->values;
+      endCount = subtable->values.arrayZ;
       startCount = endCount + segCount + 1;
       idDelta = startCount + segCount;
       idRangeOffset = idDelta + segCount;
       glyphIdArray = idRangeOffset + segCount;
       glyphIdArrayLength = (subtable->length - 16 - 8 * segCount) / 2;
     }
+    void fini () {}
 
-    static inline bool get_glyph_func (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph)
+    bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
     {
-      const accelerator_t *thiz = (const accelerator_t *) obj;
-
       /* Custom two-array bsearch. */
-      int min = 0, max = (int) thiz->segCount - 1;
-      const HBUINT16 *startCount = thiz->startCount;
-      const HBUINT16 *endCount = thiz->endCount;
+      int min = 0, max = (int) this->segCount - 1;
+      const HBUINT16 *startCount = this->startCount;
+      const HBUINT16 *endCount = this->endCount;
       unsigned int i;
       while (min <= max)
       {
-       int mid = (min + max) / 2;
+       int mid = ((unsigned int) min + (unsigned int) max) / 2;
        if (codepoint < startCount[mid])
          max = mid - 1;
        else if (codepoint > endCount[mid])
@@ -261,33 +266,55 @@ struct CmapSubtableFormat4
 
     found:
       hb_codepoint_t gid;
-      unsigned int rangeOffset = thiz->idRangeOffset[i];
+      unsigned int rangeOffset = this->idRangeOffset[i];
       if (rangeOffset == 0)
-       gid = codepoint + thiz->idDelta[i];
+       gid = codepoint + this->idDelta[i];
       else
       {
        /* Somebody has been smoking... */
-       unsigned int index = rangeOffset / 2 + (codepoint - thiz->startCount[i]) + i - thiz->segCount;
-       if (unlikely (index >= thiz->glyphIdArrayLength))
+       unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount;
+       if (unlikely (index >= this->glyphIdArrayLength))
          return false;
-       gid = thiz->glyphIdArray[index];
+       gid = this->glyphIdArray[index];
        if (unlikely (!gid))
          return false;
-       gid += thiz->idDelta[i];
+       gid += this->idDelta[i];
       }
-
-      *glyph = gid & 0xFFFFu;
+      gid &= 0xFFFFu;
+      if (!gid)
+       return false;
+      *glyph = gid;
       return true;
     }
-
-    static inline void get_all_codepoints_func (const void *obj, hb_set_t *out)
+    static bool get_glyph_func (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph)
     {
-      const accelerator_t *thiz = (const accelerator_t *) obj;
-      for (unsigned int i = 0; i < thiz->segCount; i++)
+      return ((const accelerator_t *) obj)->get_glyph (codepoint, glyph);
+    }
+    void collect_unicodes (hb_set_t *out) const
+    {
+      unsigned int count = this->segCount;
+      if (count && this->startCount[count - 1] == 0xFFFFu)
+       count--; /* Skip sentinel segment. */
+      for (unsigned int i = 0; i < count; i++)
       {
-       if (thiz->startCount[i] != 0xFFFFu
-           || thiz->endCount[i] != 0xFFFFu) // Skip the last segment (0xFFFF)
-         hb_set_add_range (out, thiz->startCount[i], thiz->endCount[i]);
+       unsigned int rangeOffset = this->idRangeOffset[i];
+       if (rangeOffset == 0)
+         out->add_range (this->startCount[i], this->endCount[i]);
+       else
+       {
+         for (hb_codepoint_t codepoint = this->startCount[i];
+              codepoint <= this->endCount[i];
+              codepoint++)
+         {
+           unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount;
+           if (unlikely (index >= this->glyphIdArrayLength))
+             break;
+           hb_codepoint_t gid = this->glyphIdArray[index];
+           if (unlikely (!gid))
+             continue;
+           out->add (codepoint);
+         }
+       }
       }
     }
 
@@ -300,14 +327,18 @@ struct CmapSubtableFormat4
     unsigned int glyphIdArrayLength;
   };
 
-  inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
+  bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
   {
-    accelerator_t accel;
-    accel.init (this);
+    accelerator_t accel (this);
     return accel.get_glyph_func (&accel, codepoint, glyph);
   }
+  void collect_unicodes (hb_set_t *out) const
+  {
+    accelerator_t accel (this);
+    accel.collect_unicodes (out);
+  }
 
-  inline bool sanitize (hb_sanitize_context_t *c) const
+  bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     if (unlikely (!c->check_struct (this)))
@@ -340,7 +371,8 @@ struct CmapSubtableFormat4
   HBUINT16     entrySelector;  /* log2(searchRange/2) */
   HBUINT16     rangeShift;     /* 2 x segCount - searchRange */
 
-  HBUINT16     values[VAR];
+  UnsizedArrayOf<HBUINT16>
+               values;
 #if 0
   HBUINT16     endCount[segCount];     /* End characterCode for each segment,
                                         * last=0xFFFFu. */
@@ -348,7 +380,8 @@ struct CmapSubtableFormat4
   HBUINT16     startCount[segCount];   /* Start character code for each segment. */
   HBINT16              idDelta[segCount];      /* Delta for all character codes in segment. */
   HBUINT16     idRangeOffset[segCount];/* Offsets into glyphIdArray or 0 */
-  HBUINT16     glyphIdArray[VAR];      /* Glyph index array (arbitrary length) */
+  UnsizedArrayOf<HBUINT16>
+               glyphIdArray;   /* Glyph index array (arbitrary length) */
 #endif
 
   public:
@@ -370,7 +403,7 @@ struct CmapSubtableLongGroup
     return 0;
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) const
+  bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
@@ -380,15 +413,16 @@ struct CmapSubtableLongGroup
   HBUINT32             startCharCode;  /* First character code in this group. */
   HBUINT32             endCharCode;    /* Last character code in this group. */
   HBUINT32             glyphID;        /* Glyph index; interpretation depends on
-                                * subtable format. */
+                                        * subtable format. */
   public:
   DEFINE_SIZE_STATIC (12);
 };
+DECLARE_NULL_NAMESPACE_BYTES (OT, CmapSubtableLongGroup);
 
 template <typename UINT>
 struct CmapSubtableTrimmed
 {
-  inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
+  bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
   {
     /* Rely on our implicit array bound-checking. */
     hb_codepoint_t gid = glyphIdArray[codepoint - startCharCode];
@@ -397,8 +431,16 @@ struct CmapSubtableTrimmed
     *glyph = gid;
     return true;
   }
+  void collect_unicodes (hb_set_t *out) const
+  {
+    hb_codepoint_t start = startCharCode;
+    unsigned int count = glyphIdArray.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (glyphIdArray[i])
+       out->add (start + i);
+  }
 
-  inline bool sanitize (hb_sanitize_context_t *c) const
+  bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) && glyphIdArray.sanitize (c));
@@ -424,37 +466,36 @@ struct CmapSubtableLongSegmented
 {
   friend struct cmap;
 
-  inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
+  bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
   {
-    int i = groups.bsearch (codepoint);
-    if (i == -1)
+    hb_codepoint_t gid = T::group_get_glyph (groups.bsearch (codepoint), codepoint);
+    if (!gid)
       return false;
-    *glyph = T::group_get_glyph (groups[i], codepoint);
+    *glyph = gid;
     return true;
   }
 
-  inline void get_all_codepoints (hb_set_t *out) const
+  void collect_unicodes (hb_set_t *out) const
   {
     for (unsigned int i = 0; i < this->groups.len; i++) {
-      hb_set_add_range (out,
-                       this->groups[i].startCharCode,
-                       this->groups[i].endCharCode);
+      out->add_range (this->groups[i].startCharCode,
+                     MIN ((hb_codepoint_t) this->groups[i].endCharCode,
+                          (hb_codepoint_t) HB_UNICODE_MAX));
     }
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) const
+  bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) && groups.sanitize (c));
   }
 
-  inline bool serialize (hb_serialize_context_t *c,
-                         const hb_vector_t<CmapSubtableLongGroup> &group_data)
+  bool serialize (hb_serialize_context_t *c,
+                 const hb_vector_t<CmapSubtableLongGroup> &group_data)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return_trace (false);
-    Supplier<CmapSubtableLongGroup> supplier (group_data.arrayZ, group_data.len);
-    if (unlikely (!groups.serialize (c, supplier, group_data.len))) return_trace (false);
+    if (unlikely (!groups.serialize (c, group_data.as_array ()))) return_trace (false);
     return true;
   }
 
@@ -471,13 +512,14 @@ struct CmapSubtableLongSegmented
 
 struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
 {
-  static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
-                                               hb_codepoint_t u)
-  { return group.glyphID + (u - group.startCharCode); }
+  static hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
+                                        hb_codepoint_t u)
+  { return likely (group.startCharCode <= group.endCharCode) ?
+          group.glyphID + (u - group.startCharCode) : 0; }
 
 
   bool serialize (hb_serialize_context_t *c,
-                  const hb_vector_t<CmapSubtableLongGroup> &groups)
+                 const hb_vector_t<CmapSubtableLongGroup> &groups)
   {
     if (unlikely (!c->extend_min (*this))) return false;
 
@@ -488,13 +530,13 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
     return CmapSubtableLongSegmented<CmapSubtableFormat12>::serialize (c, groups);
   }
 
-  static inline size_t get_sub_table_size (const hb_vector_t<CmapSubtableLongGroup> &groups)
+  static size_t get_sub_table_size (const hb_vector_t<CmapSubtableLongGroup> &groups)
   {
-    return 16 + 12 * groups.len;
+    return 16 + 12 * groups.length;
   }
 
-  static inline bool create_sub_table_plan (const hb_subset_plan_t *plan,
-                                            hb_vector_t<CmapSubtableLongGroup> *groups)
+  static bool create_sub_table_plan (const hb_subset_plan_t *plan,
+                                    hb_vector_t<CmapSubtableLongGroup> *groups)
   {
     CmapSubtableLongGroup *group = nullptr;
 
@@ -509,18 +551,16 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
 
       if (!group || !_is_gid_consecutive (group, cp, new_gid))
       {
-        group = groups->push ();
-        group->startCharCode.set (cp);
-        group->endCharCode.set (cp);
-        group->glyphID.set (new_gid);
-      } else
-      {
-        group->endCharCode.set (cp);
+       group = groups->push ();
+       group->startCharCode.set (cp);
+       group->endCharCode.set (cp);
+       group->glyphID.set (new_gid);
       }
+      else group->endCharCode.set (cp);
     }
 
     DEBUG_MSG(SUBSET, nullptr, "cmap");
-    for (unsigned int i = 0; i < groups->len; i++) {
+    for (unsigned int i = 0; i < groups->length; i++) {
       CmapSubtableLongGroup& group = (*groups)[i];
       DEBUG_MSG(SUBSET, nullptr, "  %d: U+%04X-U+%04X, gid %d-%d", i, (uint32_t) group.startCharCode, (uint32_t) group.endCharCode, (uint32_t) group.glyphID, (uint32_t) group.glyphID + ((uint32_t) group.endCharCode - (uint32_t) group.startCharCode));
     }
@@ -529,9 +569,9 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
   }
 
  private:
-  static inline bool _is_gid_consecutive (CmapSubtableLongGroup *group,
-                                         hb_codepoint_t cp,
-                                         hb_codepoint_t new_gid)
+  static bool _is_gid_consecutive (CmapSubtableLongGroup *group,
+                                  hb_codepoint_t cp,
+                                  hb_codepoint_t new_gid)
   {
     return (cp - 1 == group->endCharCode) &&
        new_gid == group->glyphID + (cp - group->startCharCode);
@@ -541,8 +581,8 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
 
 struct CmapSubtableFormat13 : CmapSubtableLongSegmented<CmapSubtableFormat13>
 {
-  static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
-                                               hb_codepoint_t u HB_UNUSED)
+  static hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
+                                        hb_codepoint_t u HB_UNUSED)
   { return group.glyphID; }
 };
 
@@ -555,36 +595,52 @@ typedef enum
 
 struct UnicodeValueRange
 {
-  inline int cmp (const hb_codepoint_t &codepoint) const
+  int cmp (const hb_codepoint_t &codepoint) const
   {
     if (codepoint < startUnicodeValue) return -1;
     if (codepoint > startUnicodeValue + additionalCount) return +1;
     return 0;
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) const
+  bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
   }
 
   HBUINT24     startUnicodeValue;      /* First value in this range. */
-  HBUINT8              additionalCount;        /* Number of additional values in this
+  HBUINT8      additionalCount;        /* Number of additional values in this
                                         * range. */
   public:
   DEFINE_SIZE_STATIC (4);
 };
 
-typedef SortedArrayOf<UnicodeValueRange, HBUINT32> DefaultUVS;
+struct DefaultUVS : SortedArrayOf<UnicodeValueRange, HBUINT32>
+{
+  void collect_unicodes (hb_set_t *out) const
+  {
+    unsigned int count = len;
+    for (unsigned int i = 0; i < count; i++)
+    {
+      hb_codepoint_t first = arrayZ[i].startUnicodeValue;
+      hb_codepoint_t last = MIN ((hb_codepoint_t) (first + arrayZ[i].additionalCount),
+                                (hb_codepoint_t) HB_UNICODE_MAX);
+      out->add_range (first, last);
+    }
+  }
+
+  public:
+  DEFINE_SIZE_ARRAY (4, *this);
+};
 
 struct UVSMapping
 {
-  inline int cmp (const hb_codepoint_t &codepoint) const
+  int cmp (const hb_codepoint_t &codepoint) const
   {
     return unicodeValue.cmp (codepoint);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) const
+  bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
@@ -596,35 +652,48 @@ struct UVSMapping
   DEFINE_SIZE_STATIC (5);
 };
 
-typedef SortedArrayOf<UVSMapping, HBUINT32> NonDefaultUVS;
+struct NonDefaultUVS : SortedArrayOf<UVSMapping, HBUINT32>
+{
+  void collect_unicodes (hb_set_t *out) const
+  {
+    unsigned int count = len;
+    for (unsigned int i = 0; i < count; i++)
+      out->add (arrayZ[i].glyphID);
+  }
+
+  public:
+  DEFINE_SIZE_ARRAY (4, *this);
+};
 
 struct VariationSelectorRecord
 {
-  inline glyph_variant_t get_glyph (hb_codepoint_t codepoint,
-                                   hb_codepoint_t *glyph,
-                                   const void *base) const
+  glyph_variant_t get_glyph (hb_codepoint_t codepoint,
+                            hb_codepoint_t *glyph,
+                            const void *base) const
   {
-    int i;
-    const DefaultUVS &defaults = base+defaultUVS;
-    i = defaults.bsearch (codepoint);
-    if (i != -1)
+    if ((base+defaultUVS).bfind (codepoint))
       return GLYPH_VARIANT_USE_DEFAULT;
-    const NonDefaultUVS &nonDefaults = base+nonDefaultUVS;
-    i = nonDefaults.bsearch (codepoint);
-    if (i != -1)
+    const UVSMapping &nonDefault = (base+nonDefaultUVS).bsearch (codepoint);
+    if (nonDefault.glyphID)
     {
-      *glyph = nonDefaults[i].glyphID;
+      *glyph = nonDefault.glyphID;
        return GLYPH_VARIANT_FOUND;
     }
     return GLYPH_VARIANT_NOT_FOUND;
   }
 
-  inline int cmp (const hb_codepoint_t &variation_selector) const
+  void collect_unicodes (hb_set_t *out, const void *base) const
+  {
+    (base+defaultUVS).collect_unicodes (out);
+    (base+nonDefaultUVS).collect_unicodes (out);
+  }
+
+  int cmp (const hb_codepoint_t &variation_selector) const
   {
     return varSelector.cmp (variation_selector);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
@@ -634,23 +703,35 @@ struct VariationSelectorRecord
 
   HBUINT24     varSelector;    /* Variation selector. */
   LOffsetTo<DefaultUVS>
-               defaultUVS;     /* Offset to Default UVS Table. May be 0. */
+               defaultUVS;     /* Offset to Default UVS Table.  May be 0. */
   LOffsetTo<NonDefaultUVS>
-               nonDefaultUVS;  /* Offset to Non-Default UVS Table. May be 0. */
+               nonDefaultUVS;  /* Offset to Non-Default UVS Table.  May be 0. */
   public:
   DEFINE_SIZE_STATIC (11);
 };
 
 struct CmapSubtableFormat14
 {
-  inline glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint,
-                                           hb_codepoint_t variation_selector,
-                                           hb_codepoint_t *glyph) const
+  glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint,
+                                    hb_codepoint_t variation_selector,
+                                    hb_codepoint_t *glyph) const
   {
-    return record[record.bsearch(variation_selector)].get_glyph (codepoint, glyph, this);
+    return record.bsearch (variation_selector).get_glyph (codepoint, glyph, this);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) const
+  void collect_variation_selectors (hb_set_t *out) const
+  {
+    unsigned int count = record.len;
+    for (unsigned int i = 0; i < count; i++)
+      out->add (record.arrayZ[i].varSelector);
+  }
+  void collect_variation_unicodes (hb_codepoint_t variation_selector,
+                                  hb_set_t *out) const
+  {
+    record.bsearch (variation_selector).collect_unicodes (out, this);
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
@@ -671,8 +752,8 @@ struct CmapSubtable
 {
   /* Note: We intentionally do NOT implement subtable formats 2 and 8. */
 
-  inline bool get_glyph (hb_codepoint_t codepoint,
-                        hb_codepoint_t *glyph) const
+  bool get_glyph (hb_codepoint_t codepoint,
+                 hb_codepoint_t *glyph) const
   {
     switch (u.format) {
     case  0: return u.format0 .get_glyph (codepoint, glyph);
@@ -685,8 +766,21 @@ struct CmapSubtable
     default: return false;
     }
   }
+  void collect_unicodes (hb_set_t *out) const
+  {
+    switch (u.format) {
+    case  0: u.format0 .collect_unicodes (out); return;
+    case  4: u.format4 .collect_unicodes (out); return;
+    case  6: u.format6 .collect_unicodes (out); return;
+    case 10: u.format10.collect_unicodes (out); return;
+    case 12: u.format12.collect_unicodes (out); return;
+    case 13: u.format13.collect_unicodes (out); return;
+    case 14:
+    default: return;
+    }
+  }
 
-  inline bool sanitize (hb_sanitize_context_t *c) const
+  bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return_trace (false);
@@ -720,7 +814,7 @@ struct CmapSubtable
 
 struct EncodingRecord
 {
-  inline int cmp (const EncodingRecord &other) const
+  int cmp (const EncodingRecord &other) const
   {
     int ret;
     ret = platformID.cmp (other.platformID);
@@ -730,7 +824,7 @@ struct EncodingRecord
     return 0;
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
@@ -747,106 +841,85 @@ struct EncodingRecord
 
 struct cmap
 {
-  static const hb_tag_t tableTag       = HB_OT_TAG_cmap;
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_cmap;
 
-  struct subset_plan {
-    subset_plan(void)
-    {
-      format4_segments.init();
-      format12_groups.init();
-    }
-
-    ~subset_plan(void)
-    {
-      format4_segments.fini();
-      format12_groups.fini();
-    }
-
-    inline size_t final_size() const
+  struct subset_plan
+  {
+    size_t final_size () const
     {
       return 4 // header
-          +  8 * 3 // 3 EncodingRecord
-          +  CmapSubtableFormat4::get_sub_table_size (this->format4_segments)
-          +  CmapSubtableFormat12::get_sub_table_size (this->format12_groups);
+         +  8 * 3 // 3 EncodingRecord
+         +  CmapSubtableFormat4::get_sub_table_size (this->format4_segments)
+         +  CmapSubtableFormat12::get_sub_table_size (this->format12_groups);
     }
 
-    // Format 4
     hb_vector_t<CmapSubtableFormat4::segment_plan> format4_segments;
-    // Format 12
     hb_vector_t<CmapSubtableLongGroup> format12_groups;
   };
 
-  inline bool sanitize (hb_sanitize_context_t *c) const
+  bool _create_plan (const hb_subset_plan_t *plan,
+                    subset_plan *cmap_plan) const
   {
-    TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) &&
-                 likely (version == 0) &&
-                 encodingRecord.sanitize (c, this));
-  }
-
-  inline bool _create_plan (const hb_subset_plan_t *plan,
-                            subset_plan *cmap_plan) const
-  {
-    if (unlikely( !CmapSubtableFormat4::create_sub_table_plan (plan, &cmap_plan->format4_segments)))
+    if (unlikely (!CmapSubtableFormat4::create_sub_table_plan (plan, &cmap_plan->format4_segments)))
       return false;
 
     return CmapSubtableFormat12::create_sub_table_plan (plan, &cmap_plan->format12_groups);
   }
 
-  inline bool _subset (const hb_subset_plan_t *plan,
-                       const subset_plan &cmap_subset_plan,
-                      size_t dest_sz,
-                      void *dest) const
+  bool _subset (const hb_subset_plan_t *plan,
+               const subset_plan &cmap_subset_plan,
+               size_t dest_sz,
+               void *dest) const
   {
     hb_serialize_context_t c (dest, dest_sz);
 
-    OT::cmap *cmap = c.start_serialize<OT::cmap> ();
-    if (unlikely (!c.extend_min (*cmap)))
+    cmap *table = c.start_serialize<cmap> ();
+    if (unlikely (!c.extend_min (*table)))
     {
       return false;
     }
 
-    cmap->version.set (0);
+    table->version.set (0);
 
-    if (unlikely (!cmap->encodingRecord.serialize (&c, /* numTables */ 3)))
+    if (unlikely (!table->encodingRecord.serialize (&c, /* numTables */ 3)))
       return false;
 
     // TODO(grieger): Convert the below to a for loop
 
     // Format 4, Plat 0 Encoding Record
-    EncodingRecord &format4_plat0_rec = cmap->encodingRecord[0];
+    EncodingRecord &format4_plat0_rec = table->encodingRecord[0];
     format4_plat0_rec.platformID.set (0); // Unicode
     format4_plat0_rec.encodingID.set (3);
 
     // Format 4, Plat 3 Encoding Record
-    EncodingRecord &format4_plat3_rec = cmap->encodingRecord[1];
+    EncodingRecord &format4_plat3_rec = table->encodingRecord[1];
     format4_plat3_rec.platformID.set (3); // Windows
     format4_plat3_rec.encodingID.set (1); // Unicode BMP
 
     // Format 12 Encoding Record
-    EncodingRecord &format12_rec = cmap->encodingRecord[2];
+    EncodingRecord &format12_rec = table->encodingRecord[2];
     format12_rec.platformID.set (3); // Windows
     format12_rec.encodingID.set (10); // Unicode UCS-4
 
     // Write out format 4 sub table
     {
-      CmapSubtable &subtable = format4_plat0_rec.subtable.serialize (&c, cmap);
+      CmapSubtable &subtable = format4_plat0_rec.subtable.serialize (&c, table);
       format4_plat3_rec.subtable.set (format4_plat0_rec.subtable);
       subtable.u.format.set (4);
 
       CmapSubtableFormat4 &format4 = subtable.u.format4;
       if (unlikely (!format4.serialize (&c, plan, cmap_subset_plan.format4_segments)))
-        return false;
+       return false;
     }
 
     // Write out format 12 sub table.
     {
-      CmapSubtable &subtable = format12_rec.subtable.serialize (&c, cmap);
+      CmapSubtable &subtable = format12_rec.subtable.serialize (&c, table);
       subtable.u.format.set (12);
 
       CmapSubtableFormat12 &format12 = subtable.u.format12;
       if (unlikely (!format12.serialize (&c, cmap_subset_plan.format12_groups)))
-        return false;
+       return false;
     }
 
     c.end_serialize ();
@@ -854,7 +927,7 @@ struct cmap
     return true;
   }
 
-  inline bool subset (hb_subset_plan_t *plan) const
+  bool subset (hb_subset_plan_t *plan) const
   {
     subset_plan cmap_subset_plan;
 
@@ -865,7 +938,7 @@ struct cmap
     }
 
     // We now know how big our blob needs to be
-    size_t dest_sz = cmap_subset_plan.final_size();
+    size_t dest_sz = cmap_subset_plan.final_size ();
     void *dest = malloc (dest_sz);
     if (unlikely (!dest)) {
       DEBUG_MSG(SUBSET, nullptr, "Unable to alloc %lu for cmap subset output", (unsigned long) dest_sz);
@@ -880,147 +953,159 @@ struct cmap
     }
 
     // all done, write the blob into dest
-    hb_blob_t *cmap_prime = hb_blob_create ((const char *)dest,
-                                            dest_sz,
-                                            HB_MEMORY_MODE_READONLY,
-                                            dest,
-                                            free);
+    hb_blob_t *cmap_prime = hb_blob_create ((const char *) dest,
+                                           dest_sz,
+                                           HB_MEMORY_MODE_READONLY,
+                                           dest,
+                                           free);
     bool result =  plan->add_table (HB_OT_TAG_cmap, cmap_prime);
     hb_blob_destroy (cmap_prime);
     return result;
   }
 
-  struct accelerator_t
+  const CmapSubtable *find_best_subtable (bool *symbol = nullptr) const
   {
-    inline void init (hb_face_t *face)
+    if (symbol) *symbol = false;
+
+    const CmapSubtable *subtable;
+
+    /* 32-bit subtables. */
+    if ((subtable = this->find_subtable (3, 10))) return subtable;
+    if ((subtable = this->find_subtable (0, 6))) return subtable;
+    if ((subtable = this->find_subtable (0, 4))) return subtable;
+
+    /* 16-bit subtables. */
+    if ((subtable = this->find_subtable (3, 1))) return subtable;
+    if ((subtable = this->find_subtable (0, 3))) return subtable;
+    if ((subtable = this->find_subtable (0, 2))) return subtable;
+    if ((subtable = this->find_subtable (0, 1))) return subtable;
+    if ((subtable = this->find_subtable (0, 0))) return subtable;
+
+    /* Symbol subtable. */
+    if ((subtable = this->find_subtable (3, 0)))
     {
-      this->blob = OT::Sanitizer<OT::cmap>().sanitize (face->reference_table (HB_OT_TAG_cmap));
-      const OT::cmap *cmap = this->blob->as<OT::cmap> ();
-      const OT::CmapSubtable *subtable = nullptr;
-      const OT::CmapSubtableFormat14 *subtable_uvs = nullptr;
-
-      bool symbol = false;
-      /* 32-bit subtables. */
-      if (!subtable) subtable = cmap->find_subtable (3, 10);
-      if (!subtable) subtable = cmap->find_subtable (0, 6);
-      if (!subtable) subtable = cmap->find_subtable (0, 4);
-      /* 16-bit subtables. */
-      if (!subtable) subtable = cmap->find_subtable (3, 1);
-      if (!subtable) subtable = cmap->find_subtable (0, 3);
-      if (!subtable) subtable = cmap->find_subtable (0, 2);
-      if (!subtable) subtable = cmap->find_subtable (0, 1);
-      if (!subtable) subtable = cmap->find_subtable (0, 0);
-      if (!subtable)
-      {
-       subtable = cmap->find_subtable (3, 0);
-       if (subtable) symbol = true;
-      }
-      /* Meh. */
-      if (!subtable) subtable = &Null(OT::CmapSubtable);
+      if (symbol) *symbol = true;
+      return subtable;
+    }
+
+    /* Meh. */
+    return &Null (CmapSubtable);
+  }
 
-      /* UVS subtable. */
-      if (!subtable_uvs)
+  struct accelerator_t
+  {
+    void init (hb_face_t *face)
+    {
+      this->table = hb_sanitize_context_t ().reference_table<cmap> (face);
+      bool symbol;
+      this->subtable = table->find_best_subtable (&symbol);
+      this->subtable_uvs = &Null (CmapSubtableFormat14);
       {
-       const OT::CmapSubtable *st = cmap->find_subtable (0, 5);
+       const CmapSubtable *st = table->find_subtable (0, 5);
        if (st && st->u.format == 14)
          subtable_uvs = &st->u.format14;
       }
-      /* Meh. */
-      if (!subtable_uvs) subtable_uvs = &Null(OT::CmapSubtableFormat14);
-
-      this->uvs_table = subtable_uvs;
 
       this->get_glyph_data = subtable;
       if (unlikely (symbol))
       {
-       this->get_glyph_func = get_glyph_from_symbol<OT::CmapSubtable>;
-       this->get_all_codepoints_func = null_get_all_codepoints_func;
+       this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable>;
       } else {
        switch (subtable->u.format) {
        /* Accelerate format 4 and format 12. */
        default:
-         this->get_glyph_func = get_glyph_from<OT::CmapSubtable>;
-         this->get_all_codepoints_func = null_get_all_codepoints_func;
+         this->get_glyph_funcZ = get_glyph_from<CmapSubtable>;
          break;
        case 12:
-         this->get_glyph_func = get_glyph_from<OT::CmapSubtableFormat12>;
-         this->get_all_codepoints_func = get_all_codepoints_from<OT::CmapSubtableFormat12>;
+         this->get_glyph_funcZ = get_glyph_from<CmapSubtableFormat12>;
          break;
        case  4:
          {
            this->format4_accel.init (&subtable->u.format4);
            this->get_glyph_data = &this->format4_accel;
-           this->get_glyph_func = this->format4_accel.get_glyph_func;
-           this->get_all_codepoints_func = this->format4_accel.get_all_codepoints_func;
+           this->get_glyph_funcZ = this->format4_accel.get_glyph_func;
          }
          break;
        }
       }
     }
 
-    inline void fini (void)
-    {
-      hb_blob_destroy (this->blob);
-    }
+    void fini () { this->table.destroy (); }
 
-    inline bool get_nominal_glyph (hb_codepoint_t  unicode,
+    bool get_nominal_glyph (hb_codepoint_t  unicode,
                                   hb_codepoint_t *glyph) const
     {
-      return this->get_glyph_func (this->get_glyph_data, unicode, glyph);
+      if (unlikely (!this->get_glyph_funcZ)) return false;
+      return this->get_glyph_funcZ (this->get_glyph_data, unicode, glyph);
     }
+    unsigned int get_nominal_glyphs (unsigned int count,
+                                    const hb_codepoint_t *first_unicode,
+                                    unsigned int unicode_stride,
+                                    hb_codepoint_t *first_glyph,
+                                    unsigned int glyph_stride) const
+    {
+      if (unlikely (!this->get_glyph_funcZ)) return 0;
 
-    inline bool get_variation_glyph (hb_codepoint_t  unicode,
-                                    hb_codepoint_t  variation_selector,
-                                    hb_codepoint_t *glyph) const
+      hb_cmap_get_glyph_func_t get_glyph_funcZ = this->get_glyph_funcZ;
+      const void *get_glyph_data = this->get_glyph_data;
+
+      unsigned int done;
+      for (done = 0;
+          done < count && get_glyph_funcZ (get_glyph_data, *first_unicode, first_glyph);
+          done++)
+      {
+       first_unicode = &StructAtOffsetUnaligned<hb_codepoint_t> (first_unicode, unicode_stride);
+       first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
+      }
+      return done;
+    }
+
+    bool get_variation_glyph (hb_codepoint_t  unicode,
+                             hb_codepoint_t  variation_selector,
+                             hb_codepoint_t *glyph) const
     {
-      switch (this->uvs_table->get_glyph_variant (unicode,
-                                                 variation_selector,
-                                                 glyph))
+      switch (this->subtable_uvs->get_glyph_variant (unicode,
+                                                    variation_selector,
+                                                    glyph))
       {
-       case OT::GLYPH_VARIANT_NOT_FOUND:               return false;
-       case OT::GLYPH_VARIANT_FOUND:           return true;
-       case OT::GLYPH_VARIANT_USE_DEFAULT:     break;
+       case GLYPH_VARIANT_NOT_FOUND:   return false;
+       case GLYPH_VARIANT_FOUND:       return true;
+       case GLYPH_VARIANT_USE_DEFAULT: break;
       }
 
       return get_nominal_glyph (unicode, glyph);
     }
 
-    inline void get_all_codepoints (hb_set_t *out) const
+    void collect_unicodes (hb_set_t *out) const
+    {
+      subtable->collect_unicodes (out);
+    }
+    void collect_variation_selectors (hb_set_t *out) const
+    {
+      subtable_uvs->collect_variation_selectors (out);
+    }
+    void collect_variation_unicodes (hb_codepoint_t variation_selector,
+                                    hb_set_t *out) const
     {
-      this->get_all_codepoints_func (get_glyph_data, out);
+      subtable_uvs->collect_variation_unicodes (variation_selector, out);
     }
 
     protected:
     typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj,
                                              hb_codepoint_t codepoint,
                                              hb_codepoint_t *glyph);
-    typedef void (*hb_cmap_get_all_codepoints_func_t) (const void *obj,
-                                                      hb_set_t *out);
-
-    static inline void null_get_all_codepoints_func (const void *obj, hb_set_t *out)
-    {
-      // NOOP
-    }
 
     template <typename Type>
-    static inline bool get_glyph_from (const void *obj,
-                                      hb_codepoint_t codepoint,
-                                      hb_codepoint_t *glyph)
+    static bool get_glyph_from (const void *obj,
+                               hb_codepoint_t codepoint,
+                               hb_codepoint_t *glyph)
     {
       const Type *typed_obj = (const Type *) obj;
       return typed_obj->get_glyph (codepoint, glyph);
     }
 
     template <typename Type>
-    static inline void get_all_codepoints_from (const void *obj,
-                                               hb_set_t *out)
-    {
-      const Type *typed_obj = (const Type *) obj;
-      typed_obj->get_all_codepoints (out);
-    }
-
-    template <typename Type>
-    static inline bool get_glyph_from_symbol (const void *obj,
+    static bool get_glyph_from_symbol (const void *obj,
                                              hb_codepoint_t codepoint,
                                              hb_codepoint_t *glyph)
     {
@@ -1042,33 +1127,41 @@ struct cmap
     }
 
     private:
-    hb_cmap_get_glyph_func_t get_glyph_func;
+    hb_nonnull_ptr_t<const CmapSubtable> subtable;
+    hb_nonnull_ptr_t<const CmapSubtableFormat14> subtable_uvs;
+
+    hb_cmap_get_glyph_func_t get_glyph_funcZ;
     const void *get_glyph_data;
-    hb_cmap_get_all_codepoints_func_t get_all_codepoints_func;
 
-    OT::CmapSubtableFormat4::accelerator_t format4_accel;
+    CmapSubtableFormat4::accelerator_t format4_accel;
 
-    const OT::CmapSubtableFormat14 *uvs_table;
-    hb_blob_t *blob;
+    hb_blob_ptr_t<cmap> table;
   };
 
   protected:
 
-  inline const CmapSubtable *find_subtable (unsigned int platform_id,
-                                           unsigned int encoding_id) const
+  const CmapSubtable *find_subtable (unsigned int platform_id,
+                                    unsigned int encoding_id) const
   {
     EncodingRecord key;
     key.platformID.set (platform_id);
     key.encodingID.set (encoding_id);
 
-    /* Note: We can use bsearch, but since it has no performance
-     * implications, we use lsearch and as such accept fonts with
-     * unsorted subtable list. */
-    int result = encodingRecord./*bsearch*/lsearch (key);
-    if (result == -1 || !encodingRecord[result].subtable)
+    const EncodingRecord &result = encodingRecord.bsearch (key);
+    if (!result.subtable)
       return nullptr;
 
-    return &(this+encodingRecord[result].subtable);
+    return &(this+result.subtable);
+  }
+
+  public:
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+                 likely (version == 0) &&
+                 encodingRecord.sanitize (c, this));
   }
 
   protected:
@@ -1079,6 +1172,7 @@ struct cmap
   DEFINE_SIZE_ARRAY (4, encodingRecord);
 };
 
+struct cmap_accelerator_t : cmap::accelerator_t {};
 
 } /* namespace OT */