[HarfBuzz] harfbuzz: Branch 'master' - 11 commits

Behdad Esfahbod behdad at kemper.freedesktop.org
Sun Nov 25 04:17:14 UTC 2018


 src/hb-aat-layout-common.hh                          |    6 +
 src/hb-aat-layout-kerx-table.hh                      |   21 +++++
 src/hb-aat-layout-lcar-table.hh                      |    6 -
 src/hb-aat-layout-morx-table.hh                      |    8 ++
 src/hb-debug.hh                                      |   16 ++--
 src/hb-dsalgs.hh                                     |   44 +++++++----
 src/hb-machinery.hh                                  |   25 ++++++
 src/hb-open-type.hh                                  |   70 ++++++++++++++-----
 src/hb-ot-layout-gdef-table.hh                       |   14 ++-
 src/hb-ot-math-table.hh                              |   10 +-
 test/shaping/data/aots/fonts/classdef1_font1.otf     |binary
 test/shaping/data/aots/fonts/classdef1_font2.otf     |binary
 test/shaping/data/aots/tests/classdef1_empty.tests   |    2 
 test/shaping/data/in-house/Makefile.sources          |    3 
 test/shaping/data/in-house/tests/macos-10.12.6.tests |   11 --
 test/shaping/data/in-house/tests/macos-10.13.6.tests |   13 ---
 test/shaping/data/in-house/tests/macos.tests         |   26 +++++++
 test/shaping/run-tests.py                            |    4 -
 18 files changed, 195 insertions(+), 84 deletions(-)

New commits:
commit 3d3097269995aa227b4b198d4da2baf942b65c66
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sat Nov 24 23:12:28 2018 -0500

    [aat] Skip terminator in VarSizedBinSearchArray<>
    
    Fixes shaping with Apple Chancery on 10.13 again.  In that font,
    there was a terminator segment, that was tripping off sanitize().

diff --git a/src/hb-aat-layout-common.hh b/src/hb-aat-layout-common.hh
index 2c09a796..3ee96bc9 100644
--- a/src/hb-aat-layout-common.hh
+++ b/src/hb-aat-layout-common.hh
@@ -76,6 +76,8 @@ struct LookupFormat0
 template <typename T>
 struct LookupSegmentSingle
 {
+  enum { TerminationWordCount = 2 };
+
   inline int cmp (hb_codepoint_t g) const {
     return g < first ? -1 : g <= last ? 0 : +1 ;
   }
@@ -134,6 +136,8 @@ struct LookupFormat2
 template <typename T>
 struct LookupSegmentArray
 {
+  enum { TerminationWordCount = 2 };
+
   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] : nullptr;
@@ -204,6 +208,8 @@ struct LookupFormat4
 template <typename T>
 struct LookupSingle
 {
+  enum { TerminationWordCount = 1 };
+
   inline int cmp (hb_codepoint_t g) const { return glyph.cmp (g); }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
diff --git a/src/hb-open-type.hh b/src/hb-open-type.hh
index 8970ec78..9b412dbc 100644
--- a/src/hb-open-type.hh
+++ b/src/hb-open-type.hh
@@ -874,6 +874,22 @@ struct VarSizedBinSearchArrayOf
 
   HB_NO_CREATE_COPY_ASSIGN_TEMPLATE (VarSizedBinSearchArrayOf, Type);
 
+  inline bool last_is_terminator (void) const
+  {
+    if (unlikely (!header.nUnits)) return false;
+
+    /* Gah.
+     *
+     * "The number of termination values that need to be included is table-specific.
+     * The value that indicates binary search termination is 0xFFFF." */
+    const HBUINT16 *words = &StructAtOffset<HBUINT16> (&bytesZ, (header.nUnits - 1) * header.unitSize);
+    unsigned int count = Type::TerminationWordCount;
+    for (unsigned int i = 0; i < count; i++)
+      if (words[i] != 0xFFFFu)
+        return false;
+    return true;
+  }
+
   inline const Type& operator [] (unsigned int i) const
   {
     if (unlikely (i >= get_length ())) return Null (Type);
@@ -884,7 +900,10 @@ struct VarSizedBinSearchArrayOf
     if (unlikely (i >= get_length ())) return Crap (Type);
     return StructAtOffset<Type> (&bytesZ, i * header.unitSize);
   }
-  inline unsigned int get_length (void) const { return header.nUnits; }
+  inline unsigned int get_length (void) const
+  {
+    return header.nUnits - last_is_terminator ();
+  }
   inline unsigned int get_size (void) const
   { return header.static_size + header.nUnits * header.unitSize; }
 
commit 4202a3cde3b6065124feb7f4c662563de1e08126
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sat Nov 24 22:48:34 2018 -0500

    Minor

diff --git a/src/hb-open-type.hh b/src/hb-open-type.hh
index 83edc773..8970ec78 100644
--- a/src/hb-open-type.hh
+++ b/src/hb-open-type.hh
@@ -443,8 +443,17 @@ struct UnsizedOffsetListOf : UnsizedOffsetArrayOf<Type, OffsetType, has_null>
 {
   inline const Type& operator [] (unsigned int i) const
   {
-    return this+this->arrayZ[i];
+    const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i];
+    if (unlikely (p < this->arrayZ)) return Null (Type); /* Overflowed. */
+    return this+*p;
   }
+  inline Type& operator [] (unsigned int i)
+  {
+    const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i];
+    if (unlikely (p < this->arrayZ)) return Crap (Type); /* Overflowed. */
+    return this+*p;
+  }
+
 
   inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
   {
@@ -867,13 +876,15 @@ struct VarSizedBinSearchArrayOf
 
   inline const Type& operator [] (unsigned int i) const
   {
-    if (unlikely (i >= header.nUnits)) return Null (Type);
+    if (unlikely (i >= get_length ())) return Null (Type);
     return StructAtOffset<Type> (&bytesZ, i * header.unitSize);
   }
   inline Type& operator [] (unsigned int i)
   {
+    if (unlikely (i >= get_length ())) return Crap (Type);
     return StructAtOffset<Type> (&bytesZ, i * header.unitSize);
   }
+  inline unsigned int get_length (void) const { return header.nUnits; }
   inline unsigned int get_size (void) const
   { return header.static_size + header.nUnits * header.unitSize; }
 
@@ -897,7 +908,7 @@ struct VarSizedBinSearchArrayOf
   {
     TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c))) return_trace (false);
-    unsigned int count = header.nUnits;
+    unsigned int count = get_length ();
     for (unsigned int i = 0; i < count; i++)
       if (unlikely (!(*this)[i].sanitize (c, base)))
 	return_trace (false);
@@ -908,7 +919,7 @@ struct VarSizedBinSearchArrayOf
   {
     TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c))) return_trace (false);
-    unsigned int count = header.nUnits;
+    unsigned int count = get_length ();
     for (unsigned int i = 0; i < count; i++)
       if (unlikely (!(*this)[i].sanitize (c, base, user_data)))
 	return_trace (false);
@@ -919,7 +930,7 @@ struct VarSizedBinSearchArrayOf
   inline const Type *bsearch (const T &key) const
   {
     unsigned int size = header.unitSize;
-    int min = 0, max = (int) header.nUnits - 1;
+    int min = 0, max = (int) get_length () - 1;
     while (min <= max)
     {
       int mid = ((unsigned int) min + (unsigned int) max) / 2;
commit 1c2302bbf1d2d0e66f49ab54ad98d1b61bc5603d
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sat Nov 24 22:32:17 2018 -0500

    [debug] Print function in return_trace()

diff --git a/src/hb-debug.hh b/src/hb-debug.hh
index d218e432..f13cfddb 100644
--- a/src/hb-debug.hh
+++ b/src/hb-debug.hh
@@ -293,14 +293,16 @@ struct hb_auto_trace_t
     if (plevel) --*plevel;
   }
 
-  inline ret_t ret (ret_t v, unsigned int line = 0)
+  inline ret_t ret (ret_t v,
+		    const char *func = "",
+		    unsigned int line = 0)
   {
     if (unlikely (returned)) {
       fprintf (stderr, "OUCH, double calls to return_trace().  This is a bug, please report.\n");
       return v;
     }
 
-    _hb_debug_msg<max_level> (what, obj, nullptr, true, plevel ? *plevel : 1, -1,
+    _hb_debug_msg<max_level> (what, obj, func, true, plevel ? *plevel : 1, -1,
 			      "return %s (line %d)",
 			      hb_printer_t<ret_t>().print (v), line);
     if (plevel) --*plevel;
@@ -325,17 +327,21 @@ struct hb_auto_trace_t<0, ret_t>
 				   const char *message,
 				   ...) HB_PRINTF_FUNC(6, 7) {}
 
-  inline ret_t ret (ret_t v, unsigned int line HB_UNUSED = 0) { return v; }
+  inline ret_t ret (ret_t v,
+		    const char *func HB_UNUSED = 0,
+		    unsigned int line HB_UNUSED = 0) { return v; }
 };
 
 /* For disabled tracing; optimize out everything.
  * https://github.com/harfbuzz/harfbuzz/pull/605 */
 template <typename ret_t>
 struct hb_no_trace_t {
-  inline ret_t ret (ret_t v, unsigned int line HB_UNUSED = 0) { return v; }
+  inline ret_t ret (ret_t v,
+		    const char *func HB_UNUSED = "",
+		    unsigned int line HB_UNUSED = 0) { return v; }
 };
 
-#define return_trace(RET) return trace.ret (RET, __LINE__)
+#define return_trace(RET) return trace.ret (RET, HB_FUNC, __LINE__)
 
 
 /*
commit 748198a6718adbb200ee24ac013c617f62c946a4
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sat Nov 24 22:16:59 2018 -0500

    Revert "[aat.morx] Remove set_object() business"
    
    This reverts commit ae8ed58a6e53441d9ccbf67afd8a00b815cde99e.
    
    Apparently this broke Apple Chancery from OS X 10.12 :(.
    Investigating...

diff --git a/src/hb-aat-layout-morx-table.hh b/src/hb-aat-layout-morx-table.hh
index 77abf457..dc406f59 100644
--- a/src/hb-aat-layout-morx-table.hh
+++ b/src/hb-aat-layout-morx-table.hh
@@ -1026,6 +1026,8 @@ struct Chain
       if (reverse)
         c->buffer->reverse ();
 
+      c->sanitizer.set_object (*subtable);
+
       subtable->dispatch (c);
 
       if (reverse)
@@ -1039,6 +1041,7 @@ struct Chain
       subtable = &StructAfter<ChainSubtable<Types> > (*subtable);
       c->set_lookup_index (c->lookup_index + 1);
     }
+    c->sanitizer.reset_object ();
   }
 
   inline unsigned int get_size (void) const { return length; }
@@ -1058,10 +1061,15 @@ struct Chain
     unsigned int count = subtableCount;
     for (unsigned int i = 0; i < count; i++)
     {
+      c->reset_object ();
+      if (unlikely (!c->check_struct (subtable)))
+	return_trace (false);
+      c->set_object (*subtable);
       if (!subtable->sanitize (c))
 	return_trace (false);
       subtable = &StructAfter<ChainSubtable<Types> > (*subtable);
     }
+    c->reset_object ();
 
     return_trace (true);
   }
commit c8a2dc820eb0ee3124e3762cb1167ac9e528ad28
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sat Nov 24 22:16:53 2018 -0500

    Revert "[aat.kerx] Remove kerx subtable boundary enforcement"
    
    This reverts commit 15905a2a2998f7ddd964f920a4828602235d6b00.

diff --git a/src/hb-aat-layout-kerx-table.hh b/src/hb-aat-layout-kerx-table.hh
index b5c1e1d1..fbeb35b0 100644
--- a/src/hb-aat-layout-kerx-table.hh
+++ b/src/hb-aat-layout-kerx-table.hh
@@ -926,6 +926,12 @@ struct KerxTable
       if (reverse)
 	c->buffer->reverse ();
 
+      /* See comment in sanitize() for conditional here. */
+      if (i < count - 1)
+	c->sanitizer.set_object (*st);
+      else
+	c->sanitizer.reset_object ();
+
       ret |= st->dispatch (c);
 
       if (reverse)
@@ -937,6 +943,7 @@ struct KerxTable
       st = &StructAfter<SubTable> (*st);
       c->set_lookup_index (c->lookup_index + 1);
     }
+    c->sanitizer.reset_object ();
 
     return ret;
   }
@@ -955,10 +962,24 @@ struct KerxTable
     unsigned int count = thiz()->tableCount;
     for (unsigned int i = 0; i < count; i++)
     {
+      c->reset_object ();
+      if (unlikely (!st->u.header.sanitize (c)))
+	return_trace (false);
+      /* OpenType kern table has 2-byte subtable lengths.  That's limiting.
+       * MS implementation also only supports one subtable, of format 0,
+       * anyway.  Certain versions of some fonts, like Calibry, contain
+       * kern subtable that exceeds 64kb.  Looks like, the subtable length
+       * is simply ignored.  Which makes sense.  It's only needed if you
+       * have multiple subtables.  To handle such fonts, we just ignore
+       * the length for the last subtable. */
+      if (i < count - 1)
+	c->set_object (*st);
+
       if (unlikely (!st->sanitize (c)))
 	return_trace (false);
       st = &StructAfter<SubTable> (*st);
     }
+    c->reset_object ();
 
     return_trace (true);
   }
commit 9eeebd8ddedb96c03860ce7eb5500aafa3969d6b
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sat Nov 24 22:16:47 2018 -0500

    Revert "[sanitize] Remove now-unused set_object() machinery"
    
    This reverts commit bbdb6edb3e1cea4c5b7076c4f6b3e6998ae36dae.

diff --git a/src/hb-machinery.hh b/src/hb-machinery.hh
index 9ca247d9..edef5405 100644
--- a/src/hb-machinery.hh
+++ b/src/hb-machinery.hh
@@ -259,11 +259,34 @@ struct hb_sanitize_context_t :
 
   inline void set_max_ops (int max_ops_) { max_ops = max_ops_; }
 
-  inline void start_processing (void)
+  template <typename T>
+  inline void set_object (const T& obj)
+  {
+    reset_object ();
+
+    const char *obj_start = (const char *) &obj;
+    const char *obj_end = (const char *) &obj + obj.get_size ();
+    assert (obj_start <= obj_end); /* Must not overflow. */
+
+    if (unlikely (obj_end < this->start || this->end < obj_start))
+      this->start = this->end = nullptr;
+    else
+    {
+      this->start = MAX (this->start, obj_start);
+      this->end   = MIN (this->end  , obj_end  );
+    }
+  }
+
+  inline void reset_object (void)
   {
     this->start = this->blob->data;
     this->end = this->start + this->blob->length;
     assert (this->start <= this->end); /* Must not overflow. */
+  }
+
+  inline void start_processing (void)
+  {
+    reset_object ();
     this->max_ops = MAX ((unsigned int) (this->end - this->start) * HB_SANITIZE_MAX_OPS_FACTOR,
 			 (unsigned) HB_SANITIZE_MAX_OPS_MIN);
     this->edit_count = 0;
commit 248ce22857c8918bf3468ef48d906de4c19c3d4d
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sat Nov 24 22:01:06 2018 -0500

    [tests] Minor

diff --git a/test/shaping/run-tests.py b/test/shaping/run-tests.py
index 959d08f9..26853e4e 100755
--- a/test/shaping/run-tests.py
+++ b/test/shaping/run-tests.py
@@ -87,11 +87,11 @@ for filename in args:
 
 		if comment:
 			if not reference:
-				print ("# %s %s --unicodes %s" % (hb_shape, fontfile, unicodes))
+				print ('# %s "%s" --unicodes %s' % (hb_shape, fontfile, unicodes))
 			continue
 
 		if not reference:
-			print ("%s %s %s %s --unicodes %s" %
+			print ('%s "%s" %s %s --unicodes %s' %
 					 (hb_shape, fontfile, ' '.join(extra_options), options, unicodes))
 
 		# hack to support fonts with space on run-tests.py, after several other tries...
commit f47c5da0aa04a88b37d9c3af4730204319a9a36b
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sat Nov 24 21:36:57 2018 -0500

    [arrays] Use hb_array_t<> in all places with sub_array()

diff --git a/src/hb-aat-layout-lcar-table.hh b/src/hb-aat-layout-lcar-table.hh
index 43ac74f9..40d34f59 100644
--- a/src/hb-aat-layout-lcar-table.hh
+++ b/src/hb-aat-layout-lcar-table.hh
@@ -52,10 +52,10 @@ struct lcar
     const OffsetTo<LigCaretClassEntry>* entry_offset = lookup.get_value (glyph,
 									 font->face->get_num_glyphs ());
     const LigCaretClassEntry& array = entry_offset ? this+*entry_offset : Null (LigCaretClassEntry);
-    if (caret_count && *caret_count)
+    if (caret_count)
     {
-      const HBINT16 *arr = array.sub_array (start_offset, caret_count);
-      unsigned int count = *caret_count;
+      hb_array_t<const HBINT16> arr = array.sub_array (start_offset, caret_count);
+      unsigned int count = arr.len;
       for (unsigned int i = 0; i < count; ++i)
 	switch (format)
 	{
diff --git a/src/hb-ot-layout-gdef-table.hh b/src/hb-ot-layout-gdef-table.hh
index 22e07f7a..2c4cbea8 100644
--- a/src/hb-ot-layout-gdef-table.hh
+++ b/src/hb-ot-layout-gdef-table.hh
@@ -61,9 +61,10 @@ struct AttachList
 
     const AttachPoint &points = this+attachPoint[index];
 
-    if (point_count) {
-      const HBUINT16 *array = points.sub_array (start_offset, point_count);
-      unsigned int count = *point_count;
+    if (point_count)
+    {
+      hb_array_t<const HBUINT16> array = points.sub_array (start_offset, point_count);
+      unsigned int count = array.len;
       for (unsigned int i = 0; i < count; i++)
 	point_array[i] = array[i];
     }
@@ -216,9 +217,10 @@ struct LigGlyph
 				      unsigned int *caret_count /* IN/OUT */,
 				      hb_position_t *caret_array /* OUT */) const
   {
-    if (caret_count) {
-      const OffsetTo<CaretValue> *array = carets.sub_array (start_offset, caret_count);
-      unsigned int count = *caret_count;
+    if (caret_count)
+    {
+      hb_array_t <const OffsetTo<CaretValue> > array = carets.sub_array (start_offset, caret_count);
+      unsigned int count = array.len;
       for (unsigned int i = 0; i < count; i++)
 	caret_array[i] = (this+array[i]).get_caret_value (font, direction, glyph_id, var_store);
     }
diff --git a/src/hb-ot-math-table.hh b/src/hb-ot-math-table.hh
index b8730497..153a4179 100644
--- a/src/hb-ot-math-table.hh
+++ b/src/hb-ot-math-table.hh
@@ -509,9 +509,8 @@ struct MathGlyphAssembly
     if (parts_count)
     {
       int scale = font->dir_scale (direction);
-      const MathGlyphPartRecord *arr =
-	    partRecords.sub_array (start_offset, parts_count);
-      unsigned int count = *parts_count;
+      hb_array_t<const MathGlyphPartRecord> arr = partRecords.sub_array (start_offset, parts_count);
+      unsigned int count = arr.len;
       for (unsigned int i = 0; i < count; i++)
 	arr[i].extract (parts[i], scale, font);
     }
@@ -556,9 +555,8 @@ struct MathGlyphConstruction
     if (variants_count)
     {
       int scale = font->dir_scale (direction);
-      const MathGlyphVariantRecord *arr =
-	    mathGlyphVariantRecord.sub_array (start_offset, variants_count);
-      unsigned int count = *variants_count;
+      hb_array_t<const MathGlyphVariantRecord> arr = mathGlyphVariantRecord.sub_array (start_offset, variants_count);
+      unsigned int count = arr.len;
       for (unsigned int i = 0; i < count; i++)
       {
 	variants[i].glyph = arr[i].variantGlyph;
commit 3246a8ebbd900bcc3e3c70532eab0f406b8f5c4a
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sat Nov 24 21:32:00 2018 -0500

    [arrays] Merge ArrayOf's sub_array into hb_array_t's

diff --git a/src/hb-dsalgs.hh b/src/hb-dsalgs.hh
index 1680bf91..57735960 100644
--- a/src/hb-dsalgs.hh
+++ b/src/hb-dsalgs.hh
@@ -567,6 +567,7 @@ struct hb_array_t
 {
   static_assert ((bool) (unsigned) hb_static_size (Type), "");
 
+  inline hb_array_t (void) : arrayZ (nullptr), len (0) {}
   inline hb_array_t (const hb_array_t &o) : arrayZ (o.arrayZ), len (o.len) {}
   inline hb_array_t (Type *array_, unsigned int len_) : arrayZ (array_), len (len_) {}
 
@@ -582,6 +583,24 @@ struct hb_array_t
 
   inline unsigned int get_size (void) const { return len * sizeof (Type); }
 
+  inline hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int *seg_count /* IN/OUT */) const
+  {
+    if (!seg_count) return hb_array_t<Type> ();
+
+    unsigned int count = len;
+    if (unlikely (start_offset > count))
+      count = 0;
+    else
+      count -= start_offset;
+    count = *seg_count = MIN (count, *seg_count);
+    return hb_array_t<Type> (arrayZ + start_offset, count);
+  }
+  inline hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int seg_count) const
+  { return sub_array (start_offset, &seg_count); }
+
+  inline hb_bytes_t as_bytes (void) const
+  { return hb_bytes_t (arrayZ, len * sizeof (Type)); }
+
   template <typename T>
   inline Type *lsearch (const T &x,
 			Type *not_found = nullptr)
@@ -620,23 +639,8 @@ struct hb_array_t
     ::qsort (arrayZ + start, end - start, sizeof (Type), Type::cmp);
   }
 
-  inline hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int seg_count) const
-  {
-    unsigned int count = len;
-    if (unlikely (start_offset > count))
-      count = 0;
-    else
-      count -= start_offset;
-    count = MIN (count, seg_count);
-    return hb_array_t<Type> (arrayZ + start_offset, count);
-  }
-
-  inline hb_bytes_t as_bytes (void) const
-  {
-    return hb_bytes_t (arrayZ, len * sizeof (Type));
-  }
-
-  inline void free (void) { ::free ((void *) arrayZ); arrayZ = nullptr; len = 0; }
+  inline void free (void)
+  { ::free ((void *) arrayZ); arrayZ = nullptr; len = 0; }
 
   template <typename hb_sanitize_context_t>
   inline bool sanitize (hb_sanitize_context_t *c) const
@@ -660,9 +664,15 @@ enum hb_bfind_not_found_t
 template <typename Type>
 struct hb_sorted_array_t : hb_array_t<Type>
 {
+  inline hb_sorted_array_t (void) : hb_array_t<Type> () {}
   inline hb_sorted_array_t (const hb_array_t<Type> &o) : hb_array_t<Type> (o) {}
   inline hb_sorted_array_t (Type *array_, unsigned int len_) : hb_array_t<Type> (array_, len_) {}
 
+  inline hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int *seg_count /* IN/OUT */) const
+  { return hb_sorted_array_t<Type> (((const hb_array_t<Type> *) (this))->sub_array (start_offset, seg_count)); }
+  inline hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int seg_count) const
+  { return sub_array (start_offset, &seg_count); }
+
   template <typename T>
   inline Type *bsearch (const T &x, Type *not_found = nullptr)
   {
diff --git a/src/hb-open-type.hh b/src/hb-open-type.hh
index 2e3db31d..83edc773 100644
--- a/src/hb-open-type.hh
+++ b/src/hb-open-type.hh
@@ -492,18 +492,6 @@ struct ArrayOf
 
   HB_NO_CREATE_COPY_ASSIGN_TEMPLATE2 (ArrayOf, Type, LenType);
 
-  inline const Type *sub_array (unsigned int start_offset, unsigned int *pcount /* IN/OUT */) const
-  {
-    unsigned int count = len;
-    if (unlikely (start_offset > count))
-      count = 0;
-    else
-      count -= start_offset;
-    count = MIN (count, *pcount);
-    *pcount = count;
-    return arrayZ + start_offset;
-  }
-
   inline const Type& operator [] (unsigned int i) const
   {
     if (unlikely (i >= len)) return Null (Type);
@@ -523,6 +511,15 @@ struct ArrayOf
   inline hb_array_t<const Type> as_array (void) const
   { return hb_array (arrayZ, len); }
 
+  inline hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const
+  { return as_array ().sub_array (start_offset, count);}
+  inline hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count /* IN/OUT */) const
+  { return as_array ().sub_array (start_offset, count);}
+  inline hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int count)
+  { return as_array ().sub_array (start_offset, count);}
+  inline hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count /* IN/OUT */)
+  { return as_array ().sub_array (start_offset, count);}
+
   inline bool serialize (hb_serialize_context_t *c,
 			 unsigned int items_len)
   {
@@ -777,6 +774,15 @@ struct SortedArrayOf : ArrayOf<Type, LenType>
   inline hb_sorted_array_t<const Type> as_array (void) const
   { return hb_sorted_array (this->arrayZ, this->len); }
 
+  inline hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const
+  { return as_array ().sub_array (start_offset, count);}
+  inline hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count /* IN/OUT */) const
+  { return as_array ().sub_array (start_offset, count);}
+  inline hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int count)
+  { return as_array ().sub_array (start_offset, count);}
+  inline hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count /* IN/OUT */)
+  { return as_array ().sub_array (start_offset, count);}
+
   template <typename T>
   inline Type &bsearch (const T &x, Type &not_found = Crap (Type))
   { return *as_array ().bsearch (x, &not_found); }
commit e6877e28cd30e89af7cce59d903184a5a01ec970
Author: Ebrahim Byagowi <ebrahim at gnu.org>
Date:   Sun Nov 25 02:12:40 2018 +0330

    [test] Add the missed aots fonts

diff --git a/test/shaping/data/aots/fonts/classdef1_font1.otf b/test/shaping/data/aots/fonts/classdef1_font1.otf
new file mode 100644
index 00000000..f0add698
Binary files /dev/null and b/test/shaping/data/aots/fonts/classdef1_font1.otf differ
diff --git a/test/shaping/data/aots/fonts/classdef1_font2.otf b/test/shaping/data/aots/fonts/classdef1_font2.otf
new file mode 100644
index 00000000..f01876dd
Binary files /dev/null and b/test/shaping/data/aots/fonts/classdef1_font2.otf differ
diff --git a/test/shaping/data/aots/tests/classdef1_empty.tests b/test/shaping/data/aots/tests/classdef1_empty.tests
index 76aaecc4..71d87f1c 100644
--- a/test/shaping/data/aots/tests/classdef1_empty.tests
+++ b/test/shaping/data/aots/tests/classdef1_empty.tests
@@ -1 +1 @@
-#../fonts/classdef1_font2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0011,U+0012,U+0013,U+0014,U+0015:[17|23|24|25|21]
+../fonts/classdef1_font2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0011,U+0012,U+0013,U+0014,U+0015:[17|23|24|25|21]
commit 825ea5a4607fafa11c56a72a82bda773f6b44e79
Author: Ebrahim Byagowi <ebrahim at gnu.org>
Date:   Sun Nov 25 01:59:54 2018 +0330

    [test] Merge 10.12.6 and 10.13.6 tests, update to Apple Chancery fix

diff --git a/test/shaping/data/in-house/Makefile.sources b/test/shaping/data/in-house/Makefile.sources
index 1a3d1775..d548e961 100644
--- a/test/shaping/data/in-house/Makefile.sources
+++ b/test/shaping/data/in-house/Makefile.sources
@@ -33,8 +33,7 @@ TESTS = \
 	tests/khmer-misc.tests \
 	tests/language-tags.tests \
 	tests/ligature-id.tests \
-	tests/macos-10.12.6.tests \
-	tests/macos-10.13.6.tests \
+	tests/macos.tests \
 	tests/mark-attachment.tests \
 	tests/mark-filtering-sets.tests \
 	tests/mongolian-variation-selector.tests \
diff --git a/test/shaping/data/in-house/tests/macos-10.12.6.tests b/test/shaping/data/in-house/tests/macos-10.12.6.tests
deleted file mode 100644
index 0f10fedf..00000000
--- a/test/shaping/data/in-house/tests/macos-10.12.6.tests
+++ /dev/null
@@ -1,11 +0,0 @@
-/System/Library/Fonts/Times.dfont at 39c954614d3f3317b28564db06d5b7b7a6ff0e39::U+0066,U+0069:[fi=0+1139]
-/Library/Fonts/Khmer MN.ttc at 5f5b1072df99b7355d3066ea85fe82969d13c94a::U+17A2,U+1780,U+17D2,U+179F,U+179A,U+1781,U+17D2,U+1798,U+17C2,U+179A:[km_qa=0+1025|km_ka=1+1025|km_sa.sub=1+517|km_ro=4+593|km_vs_ae=5+605|km_kha=5+1025|km_mo.sub=5+0|km_ro=9+593]
-/Library/Fonts/Tamil MN.ttc at 37a2020c3f86ebcc45e02c1de5fdf81e2676989d::U+0BA4,U+0BCA,U+0B95,U+0BC1,U+0B95,U+0BCD,U+0B95,U+0BAA,U+0BCD,U+0BAA,U+0B9F,U+0BCD,U+0B9F,U+0BC1:[tgm_e=0+1702|tgc_ta=0+1598|tgm_aa=0+1074|tgc_ka=2 at -74,0+1518|tgm_u=2+1205|tgc_ka=4+1592|tgm_pulli=4+503|tgc_ka=6+1592|tgc_pa=7+1370|tgm_pulli=7+503|tgc_pa=9+1370|tgc_tta=10+1566|tgm_pulli=10+503|tgc_tta=12+1566|tgm_u=12+1205]
-/System/Library/Fonts/Times.dfont at 39c954614d3f3317b28564db06d5b7b7a6ff0e39::U+0041,U+0066,U+0300,U+0066,U+0069,U+005A:[A=0+1479|f=1+682|gravecmb=1 at -480,588+0|fi=3+1139|Z=5+1251]
-/System/Library/Fonts/LucidaGrande.ttc at d89a9d7e57767bfe3b5a4cfd22bb1e9dbe03a062::U+05E1,U+05B0:[shevahebrew=0 at -7,0+0|samekhhebrew=0+1361]
-/Library/Fonts/Apple Chancery.ttf at 5fc49ae9bce39e2105864323183b68ea34c9e562::U+0054,U+0068,U+0020,U+0074,U+0068,U+0020,U+006C,U+006C,U+0020,U+0074,U+0065,U+0020,U+0074,U+006F,U+0020,U+0074,U+0072,U+0020,U+0066,U+0072,U+0020,U+0066,U+0075,U+0020,U+0066,U+006A:[T_h=0+2308|space=2+569|t_h=3+1687|space=5+569|l_l=6+1108|space=8+569|t_e=9+1408|space=11+569|t_o=12+1531|space=14+569|t_r=15+1385|space=17+569|f_r=18+1432|space=20+569|f_u=21+1733|space=23+569|f_j=24+1073]
-/System/Library/Fonts/GeezaPro.ttc at f43ee7151c2e9f1dddfbc26cfc148609eb5c5820::U+0627,U+0644,U+0623,U+064E,U+0628,U+0652,U+062C,U+064E,U+062F,U+0650,U+064A,U+064E,U+0651,U+0629,U+0640,U+0627,U+0644,U+0639,U+064E,U+0631,U+064E,U+0628,U+0650,U+064A,U+064E,U+0651,U+0629:[u0629.final.tehMarbuta=26+713|u064e_u0651.shaddaFatha=23 at 0,-200+0|u064a.medial.yeh=23+656|u0650.kasra=21 at 80,290+80|u0628.initial.beh=21 at -80,0+576|u064e.fatha=19 at 200,-570+200|u0631.final.reh=19 at -200,0+702|u064e.fatha=17 at 200,-200+200|u0639.medial.ain=17 at -200,0+738|u0644.initial.lam=16+515|u0627.final.alef=15+647|u0640.tatweel=14+449|u0629.final.tehMarbuta=13+713|u064e_u0651.shaddaFatha=10 at 0,-200+0|u064a.initial.yeh=10+656|u0650.kasra=8 at 80,570+80|u062f.final.dal=8 at -80,0+822|u064e.fatha=6 at 290,-160+290|u062c.medial.jeem=6 at -290,0+1069|u0652.sukun=4 at 0,-200+0|u0628.initial.beh=4+656|u064e.fatha=1 at -252,120+-252|u0644_u0623.isolated.lamHamzaOnAlef=1 at 120,0+1282|u0627.alef=0+647]
-/System/Library/Fonts/GeezaPro.ttc at f43ee7151c2e9f1dddfbc26cfc148609eb5c5820::U+0628,U+064A,U+064E,U+0651,U+0629:[u0629.final.tehMarbuta=4+713|u064e_u0651.shaddaFatha=1 at 0,-200+0|u064a.medial.yeh=1+656|u0628.initial.beh=0+656]
-/System/Library/Fonts/GeezaPro.ttc at f43ee7151c2e9f1dddfbc26cfc148609eb5c5820::U+0631,U+0628:[u0628.beh=1+1415|u0631.reh=0 at -202,0+700]
-/System/Library/Fonts/GeezaPro.ttc at f43ee7151c2e9f1dddfbc26cfc148609eb5c5820::U+0628,U+064F:[u064f.damma=0 at 250,-250+250|u0628.beh=0 at -250,0+1165]
-/System/Library/Fonts/SFNSDisplay.ttf at 92787c30716672737e9059bc367c15d04fbc1ced::U+0056,U+0041,U+0056,U+0041:[gid265=0+1227|gid4=1 at -65,0+1162|gid265=2 at -65,0+1162|gid4=3 at -65,0+1227]
diff --git a/test/shaping/data/in-house/tests/macos-10.13.6.tests b/test/shaping/data/in-house/tests/macos-10.13.6.tests
deleted file mode 100644
index 9d456d2d..00000000
--- a/test/shaping/data/in-house/tests/macos-10.13.6.tests
+++ /dev/null
@@ -1,13 +0,0 @@
-/System/Library/Fonts/Times.ttc at 896098b6979306ad84355025459f7c68b029139c::U+0066,U+0069:[fi=0+1139]
-/Library/Fonts/Khmer MN.ttc at 782ba6cf3fca0512ab348dfe08345a2d5dc5bf2c::U+17A2,U+1780,U+17D2,U+179F,U+179A,U+1781,U+17D2,U+1798,U+17C2,U+179A:[km_qa=0+1025|km_ka=1+1025|km_sa.sub=1+517|km_ro=4+593|km_vs_ae=5+605|km_kha=5+1025|km_mo.sub=5+0|km_ro=9+593]
-# The following is broken
-#/Library/Fonts/Tamil MN.ttc at 3de37f3f8f3cb6015b093fbd6e9d323daaf6fb1d::U+0BA4,U+0BCA,U+0B95,U+0BC1,U+0B95,U+0BCD,U+0B95,U+0BAA,U+0BCD,U+0BAA,U+0B9F,U+0BCD,U+0B9F,U+0BC1:[tgm_e=0+1702|tgc_ta=0+1598|tgm_aa=0+1074|tgc_ka=2 at -74,0+1518|tgm_u=2+1205|tgc_ka=4+1592|tgm_pulli=4+503|tgc_ka=6+1592|tgc_pa=7+1370|tgm_pulli=7+503|tgc_pa=9+1370|tgc_tta=10+1566|tgm_pulli=10+503|tgc_tta=12+1566|tgm_u=12+1205]
-/System/Library/Fonts/Times.ttc at 896098b6979306ad84355025459f7c68b029139c::U+0041,U+0066,U+0300,U+0066,U+0069,U+005A:[A=0+1479|f=1+682|gravecmb=1 at -480,588+0|fi=3+1139|Z=5+1251]
-/System/Library/Fonts/LucidaGrande.ttc at 63ba1b1de4709bd832ca76bd62368dd99fc34269::U+05E1,U+05B0:[shevahebrew=0 at -7,0+0|samekhhebrew=0+1361]
-# The following is broken
-#/Library/Fonts/Apple Chancery.ttf at 4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac::U+0054,U+0068,U+0020,U+0074,U+0068,U+0020,U+006C,U+006C,U+0020,U+0074,U+0065,U+0020,U+0074,U+006F,U+0020,U+0074,U+0072,U+0020,U+0066,U+0072,U+0020,U+0066,U+0075,U+0020,U+0066,U+006A:[T_h=0+2308|space=2+569|t_h=3+1687|space=5+569|l_l=6+1108|space=8+569|t_e=9+1408|space=11+569|t_o=12+1531|space=14+569|t_r=15+1385|space=17+569|f_r=18+1432|space=20+569|f_u=21+1733|space=23+569|f_j=24+1073]
-/System/Library/Fonts/GeezaPro.ttc at ab26ea45dcaa5e1c5a958e42af10e10d330e7334::U+0627,U+0644,U+0623,U+064E,U+0628,U+0652,U+062C,U+064E,U+062F,U+0650,U+064A,U+064E,U+0651,U+0629,U+0640,U+0627,U+0644,U+0639,U+064E,U+0631,U+064E,U+0628,U+0650,U+064A,U+064E,U+0651,U+0629:[u0629.final.tehMarbuta=26+713|u064e_u0651.shaddaFatha=23 at 0,-200+0|u064a.medial.yeh=23+656|u0650.kasra=21 at 80,290+80|u0628.initial.beh=21 at -80,0+576|u064e.fatha=19 at 200,-570+200|u0631.final.reh=19 at -200,0+702|u064e.fatha=17 at 200,-200+200|u0639.medial.ain=17 at -200,0+738|u0644.initial.lam=16+515|u0627.final.alef=15+647|u0640.tatweel=14+449|u0629.final.tehMarbuta=13+713|u064e_u0651.shaddaFatha=10 at 0,-200+0|u064a.initial.yeh=10+656|u0650.kasra=8 at 80,570+80|u062f.final.dal=8 at -80,0+822|u064e.fatha=6 at 290,-160+290|u062c.medial.jeem=6 at -290,0+1069|u0652.sukun=4 at 0,-200+0|u0628.initial.beh=4+656|u064e.fatha=1 at -252,120+-252|u0644_u0623.isolated.lamHamzaOnAlef=1 at 120,0+1282|u0627.alef=0+647]
-/System/Library/Fonts/GeezaPro.ttc at ab26ea45dcaa5e1c5a958e42af10e10d330e7334::U+0628,U+064A,U+064E,U+0651,U+0629:[u0629.final.tehMarbuta=4+713|u064e_u0651.shaddaFatha=1 at 0,-200+0|u064a.medial.yeh=1+656|u0628.initial.beh=0+656]
-/System/Library/Fonts/GeezaPro.ttc at ab26ea45dcaa5e1c5a958e42af10e10d330e7334::U+0631,U+0628:[u0628.beh=1+1415|u0631.reh=0 at -202,0+700]
-/System/Library/Fonts/GeezaPro.ttc at ab26ea45dcaa5e1c5a958e42af10e10d330e7334::U+0628,U+064F:[u064f.damma=0 at 250,-250+250|u0628.beh=0 at -250,0+1165]
-/System/Library/Fonts/SFNSDisplay.ttf at c8948f464ff822a5f9bbf2e12d0e4e32268815aa::U+0056,U+0041,U+0056,U+0041:[gid332=0+1227|gid4=1 at -65,0+1162|gid332=2 at -65,0+1162|gid4=3 at -65,0+1227]
diff --git a/test/shaping/data/in-house/tests/macos.tests b/test/shaping/data/in-house/tests/macos.tests
new file mode 100644
index 00000000..4d76d84e
--- /dev/null
+++ b/test/shaping/data/in-house/tests/macos.tests
@@ -0,0 +1,26 @@
+# 10.12.6
+/System/Library/Fonts/Times.dfont at 39c954614d3f3317b28564db06d5b7b7a6ff0e39::U+0066,U+0069:[fi=0+1139]
+/Library/Fonts/Khmer MN.ttc at 5f5b1072df99b7355d3066ea85fe82969d13c94a::U+17A2,U+1780,U+17D2,U+179F,U+179A,U+1781,U+17D2,U+1798,U+17C2,U+179A:[km_qa=0+1025|km_ka=1+1025|km_sa.sub=1+517|km_ro=4+593|km_vs_ae=5+605|km_kha=5+1025|km_mo.sub=5+0|km_ro=9+593]
+/Library/Fonts/Tamil MN.ttc at 37a2020c3f86ebcc45e02c1de5fdf81e2676989d::U+0BA4,U+0BCA,U+0B95,U+0BC1,U+0B95,U+0BCD,U+0B95,U+0BAA,U+0BCD,U+0BAA,U+0B9F,U+0BCD,U+0B9F,U+0BC1:[tgm_e=0+1702|tgc_ta=0+1598|tgm_aa=0+1074|tgc_ka=2 at -74,0+1518|tgm_u=2+1205|tgc_ka=4+1592|tgm_pulli=4+503|tgc_ka=6+1592|tgc_pa=7+1370|tgm_pulli=7+503|tgc_pa=9+1370|tgc_tta=10+1566|tgm_pulli=10+503|tgc_tta=12+1566|tgm_u=12+1205]
+/System/Library/Fonts/Times.dfont at 39c954614d3f3317b28564db06d5b7b7a6ff0e39::U+0041,U+0066,U+0300,U+0066,U+0069,U+005A:[A=0+1479|f=1+682|gravecmb=1 at -480,588+0|fi=3+1139|Z=5+1251]
+/System/Library/Fonts/LucidaGrande.ttc at d89a9d7e57767bfe3b5a4cfd22bb1e9dbe03a062::U+05E1,U+05B0:[shevahebrew=0 at -7,0+0|samekhhebrew=0+1361]
+/Library/Fonts/Apple Chancery.ttf at 5fc49ae9bce39e2105864323183b68ea34c9e562::U+0054,U+0068,U+0020,U+0074,U+0068,U+0020,U+006C,U+006C,U+0020,U+0074,U+0065,U+0020,U+0074,U+006F,U+0020,U+0074,U+0072,U+0020,U+0066,U+0072,U+0020,U+0066,U+0075,U+0020,U+0066,U+006A:[T_h=0+2308|space=2+569|t_h=3+1687|space=5+569|l_l=6+1108|space=8+569|t_e=9+1408|space=11+569|t_o=12+1531|space=14+569|t_r=15+1385|space=17+569|f_r=18+1432|space=20+569|f_u=21+1733|space=23+569|f_j=24+1073]
+/System/Library/Fonts/GeezaPro.ttc at f43ee7151c2e9f1dddfbc26cfc148609eb5c5820::U+0627,U+0644,U+0623,U+064E,U+0628,U+0652,U+062C,U+064E,U+062F,U+0650,U+064A,U+064E,U+0651,U+0629,U+0640,U+0627,U+0644,U+0639,U+064E,U+0631,U+064E,U+0628,U+0650,U+064A,U+064E,U+0651,U+0629:[u0629.final.tehMarbuta=26+713|u064e_u0651.shaddaFatha=23 at 0,-200+0|u064a.medial.yeh=23+656|u0650.kasra=21 at 80,290+80|u0628.initial.beh=21 at -80,0+576|u064e.fatha=19 at 200,-570+200|u0631.final.reh=19 at -200,0+702|u064e.fatha=17 at 200,-200+200|u0639.medial.ain=17 at -200,0+738|u0644.initial.lam=16+515|u0627.final.alef=15+647|u0640.tatweel=14+449|u0629.final.tehMarbuta=13+713|u064e_u0651.shaddaFatha=10 at 0,-200+0|u064a.initial.yeh=10+656|u0650.kasra=8 at 80,570+80|u062f.final.dal=8 at -80,0+822|u064e.fatha=6 at 290,-160+290|u062c.medial.jeem=6 at -290,0+1069|u0652.sukun=4 at 0,-200+0|u0628.initial.beh=4+656|u064e.fatha=1 at -252,120+-252|u0644_u0623.isolated.lamHamzaOnAlef=1 at 120,0+1282|u0627.alef=0+647]
+/System/Library/Fonts/GeezaPro.ttc at f43ee7151c2e9f1dddfbc26cfc148609eb5c5820::U+0628,U+064A,U+064E,U+0651,U+0629:[u0629.final.tehMarbuta=4+713|u064e_u0651.shaddaFatha=1 at 0,-200+0|u064a.medial.yeh=1+656|u0628.initial.beh=0+656]
+/System/Library/Fonts/GeezaPro.ttc at f43ee7151c2e9f1dddfbc26cfc148609eb5c5820::U+0631,U+0628:[u0628.beh=1+1415|u0631.reh=0 at -202,0+700]
+/System/Library/Fonts/GeezaPro.ttc at f43ee7151c2e9f1dddfbc26cfc148609eb5c5820::U+0628,U+064F:[u064f.damma=0 at 250,-250+250|u0628.beh=0 at -250,0+1165]
+/System/Library/Fonts/SFNSDisplay.ttf at 92787c30716672737e9059bc367c15d04fbc1ced::U+0056,U+0041,U+0056,U+0041:[gid265=0+1227|gid4=1 at -65,0+1162|gid265=2 at -65,0+1162|gid4=3 at -65,0+1227]
+
+# 10.13.6
+/System/Library/Fonts/Times.ttc at 896098b6979306ad84355025459f7c68b029139c::U+0066,U+0069:[fi=0+1139]
+/Library/Fonts/Khmer MN.ttc at 782ba6cf3fca0512ab348dfe08345a2d5dc5bf2c::U+17A2,U+1780,U+17D2,U+179F,U+179A,U+1781,U+17D2,U+1798,U+17C2,U+179A:[km_qa=0+1025|km_ka=1+1025|km_sa.sub=1+517|km_ro=4+593|km_vs_ae=5+605|km_kha=5+1025|km_mo.sub=5+0|km_ro=9+593]
+# The following is broken https://github.com/harfbuzz/harfbuzz/issues/1410
+#/Library/Fonts/Tamil MN.ttc at 3de37f3f8f3cb6015b093fbd6e9d323daaf6fb1d::U+0BA4,U+0BCA,U+0B95,U+0BC1,U+0B95,U+0BCD,U+0B95,U+0BAA,U+0BCD,U+0BAA,U+0B9F,U+0BCD,U+0B9F,U+0BC1:[tgm_e=0+1702|tgc_ta=0+1598|tgm_aa=0+1074|tgc_ka=2 at -74,0+1518|tgm_u=2+1205|tgc_ka=4+1592|tgm_pulli=4+503|tgc_ka=6+1592|tgc_pa=7+1370|tgm_pulli=7+503|tgc_pa=9+1370|tgc_tta=10+1566|tgm_pulli=10+503|tgc_tta=12+1566|tgm_u=12+1205]
+/System/Library/Fonts/Times.ttc at 896098b6979306ad84355025459f7c68b029139c::U+0041,U+0066,U+0300,U+0066,U+0069,U+005A:[A=0+1479|f=1+682|gravecmb=1 at -480,588+0|fi=3+1139|Z=5+1251]
+/System/Library/Fonts/LucidaGrande.ttc at 63ba1b1de4709bd832ca76bd62368dd99fc34269::U+05E1,U+05B0:[shevahebrew=0 at -7,0+0|samekhhebrew=0+1361]
+/Library/Fonts/Apple Chancery.ttf at 4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac::U+0054,U+0068,U+0020,U+0074,U+0068,U+0020,U+006C,U+006C,U+0020,U+0074,U+0065,U+0020,U+0074,U+006F,U+0020,U+0074,U+0072,U+0020,U+0066,U+0072,U+0020,U+0066,U+0075,U+0020,U+0066,U+006A:[T_h=0+2308|space=2+569|t_h=3+1687|space=5+569|l_l=6+1108|space=8+569|t_e=9+1408|space=11+569|t_o=12+1531|space=14+569|t_r=15+1385|space=17+569|f_r=18+1432|space=20+569|f_u=21+1733|space=23+569|f_j=24+1073]
+/System/Library/Fonts/GeezaPro.ttc at ab26ea45dcaa5e1c5a958e42af10e10d330e7334::U+0627,U+0644,U+0623,U+064E,U+0628,U+0652,U+062C,U+064E,U+062F,U+0650,U+064A,U+064E,U+0651,U+0629,U+0640,U+0627,U+0644,U+0639,U+064E,U+0631,U+064E,U+0628,U+0650,U+064A,U+064E,U+0651,U+0629:[u0629.final.tehMarbuta=26+713|u064e_u0651.shaddaFatha=23 at 0,-200+0|u064a.medial.yeh=23+656|u0650.kasra=21 at 80,290+80|u0628.initial.beh=21 at -80,0+576|u064e.fatha=19 at 200,-570+200|u0631.final.reh=19 at -200,0+702|u064e.fatha=17 at 200,-200+200|u0639.medial.ain=17 at -200,0+738|u0644.initial.lam=16+515|u0627.final.alef=15+647|u0640.tatweel=14+449|u0629.final.tehMarbuta=13+713|u064e_u0651.shaddaFatha=10 at 0,-200+0|u064a.initial.yeh=10+656|u0650.kasra=8 at 80,570+80|u062f.final.dal=8 at -80,0+822|u064e.fatha=6 at 290,-160+290|u062c.medial.jeem=6 at -290,0+1069|u0652.sukun=4 at 0,-200+0|u0628.initial.beh=4+656|u064e.fatha=1 at -252,120+-252|u0644_u0623.isolated.lamHamzaOnAlef=1 at 120,0+1282|u0627.alef=0+647]
+/System/Library/Fonts/GeezaPro.ttc at ab26ea45dcaa5e1c5a958e42af10e10d330e7334::U+0628,U+064A,U+064E,U+0651,U+0629:[u0629.final.tehMarbuta=4+713|u064e_u0651.shaddaFatha=1 at 0,-200+0|u064a.medial.yeh=1+656|u0628.initial.beh=0+656]
+/System/Library/Fonts/GeezaPro.ttc at ab26ea45dcaa5e1c5a958e42af10e10d330e7334::U+0631,U+0628:[u0628.beh=1+1415|u0631.reh=0 at -202,0+700]
+/System/Library/Fonts/GeezaPro.ttc at ab26ea45dcaa5e1c5a958e42af10e10d330e7334::U+0628,U+064F:[u064f.damma=0 at 250,-250+250|u0628.beh=0 at -250,0+1165]
+/System/Library/Fonts/SFNSDisplay.ttf at c8948f464ff822a5f9bbf2e12d0e4e32268815aa::U+0056,U+0041,U+0056,U+0041:[gid332=0+1227|gid4=1 at -65,0+1162|gid332=2 at -65,0+1162|gid4=3 at -65,0+1227]


More information about the HarfBuzz mailing list